import param
import panel as pn
from panel.custom import JSComponent
pn.extension()
class Canvas(JSComponent):
color = param.Color(default='#000000')
line_width = param.Number(default=1, bounds=(0.1, 10))
uri = param.String()
_esm = """
export function render({model, el}){
// Create canvas
const canvas = document.createElement('canvas');
canvas.style.border = '1px solid';
canvas.width = model.width;
canvas.height = model.height;
const ctx = canvas.getContext("2d")
// Set up drawing handlers
let start = null
canvas.addEventListener('mousedown', (event) => {
start = event
ctx.beginPath()
ctx.moveTo(start.offsetX, start.offsetY)
})
canvas.addEventListener('mousemove', (event) => {
if (start == null)
return
ctx.lineTo(event.offsetX, event.offsetY)
ctx.stroke()
})
canvas.addEventListener('mouseup', () => {
start = null
})
// Update styles
model.on(['color', 'line_width'], () => {
ctx.lineWidth = model.line_width;
ctx.strokeStyle = model.color;
})
// Create clear button
const clearButton = document.createElement('button');
clearButton.textContent = 'Clear';
clearButton.addEventListener('click', () => {
ctx.clearRect(0, 0, canvas.width, canvas.height)
model.uri = ""
})
// Create save button
const saveButton = document.createElement('button');
saveButton.textContent = 'Save';
saveButton.addEventListener('click', () => {
model.uri = canvas.toDataURL();
})
// Append elements to the parent element
el.appendChild(canvas);
el.appendChild(clearButton);
el.appendChild(saveButton);
}
"""
canvas = Canvas(height=400, width=400)
png_view = pn.pane.HTML(
pn.rx("<img src='{uri}'></img>").format(uri=canvas.param.uri),
height=400
)
pn.Column(
'# Drag on canvas to draw\n To export the drawing to a png click save.',
pn.Param(
canvas.param,
default_layout=pn.Row,
parameters=['color', 'line_width'],
show_name=False
),
pn.Row(
canvas,
png_view
),
).servable()