Jechen00's picture
initial commit with Panel app
1078e59
#####################################
# Packages & Dependencies
#####################################
import param
from panel.reactive import ReactiveHTML
#####################################
# Canvas
#####################################
class Canvas(ReactiveHTML):
'''
The HTML canvas panel used for drawing digits (0-9) in the application.
Reference: https://panel.holoviz.org/how_to/custom_components/examples/canvas_draw.html
'''
uri = param.String()
clear = param.Boolean(default = False)
_template = '''
<canvas
id="canvas"
style="width: 100%; height: 100%"
height=400px
width=400px
onmousedown="${script('start')}"
onmousemove="${script('draw')}"
onmouseup="${script('end')}"
onmouseleave="${script('end')}">
</canvas>
'''
_scripts = {
'render': '''
state.ctx = canvas.getContext('2d');
state.ctx.fillStyle = '#FFFFFF';
state.ctx.fillRect(0, 0, canvas.width, canvas.height);
state.ctx.lineWidth = 30;
state.ctx.strokeStyle = '#000000';
state.ctx.lineJoin = 'round';
state.ctx.lineCap = 'round';
// Helper to normalize mouse coordinates
state.getCoords = function(e) {
const rect = canvas.getBoundingClientRect();
return {
x: (e.clientX - rect.left) * (canvas.width / rect.width),
y: (e.clientY - rect.top) * (canvas.height / rect.height)
};
};
''',
'start': '''
if (state.isDrawing) return;
state.isDrawing = true;
const pos = state.getCoords(event);
state.ctx.beginPath();
state.ctx.moveTo(pos.x, pos.y);
''',
'draw': '''
if (!state.isDrawing) return;
const pos = state.getCoords(event);
state.ctx.lineTo(pos.x, pos.y);
state.ctx.stroke();
data.uri = canvas.toDataURL('image/png');
''',
'end': '''
if (!state.isDrawing) return; // Early return if already not drawing
state.isDrawing = false;
''',
'clear': '''
state.ctx.fillStyle = '#FFFFFF';
state.ctx.fillRect(0, 0, canvas.width, canvas.height);
data.uri = '';
'''
}
def toggle_clear(self, *event):
'''
Toggles the value of self.clear to trigger the JS 'clear' function.
'''
self.clear = not self.clear