1- /**
2- * TODO: Drawing Canvas
3- * - Initialize <canvas>, handle mouse/touch drawing
4- * - Color picker, brush size, clear canvas
5- * - Save canvas as image (toDataURL)
6- * Optional: Eraser mode, undo/redo, pressure sensitivity (Pointer Events)
7- */
8-
9- document . addEventListener ( 'DOMContentLoaded' , ( ) => {
1+ document . addEventListener ( 'DOMContentLoaded' , ( ) => {
102 console . log ( 'Drawing Canvas ready' ) ;
3+
114 // TODO: Canvas setup and draw handlers
12- } ) ;
5+ const canvas = document . getElementById ( 'drawingCanvas' ) ;
6+ const ctx = canvas . getContext ( '2d' ) ;
7+ const colorPicker = document . getElementById ( 'colorPicker' ) ;
8+ const brushSize = document . getElementById ( 'brushSize' ) ;
9+ const brushSizeValue = document . getElementById ( 'brushSizeValue' ) ;
10+ const clearButton = document . getElementById ( 'clearButton' ) ;
11+ const saveButton = document . getElementById ( 'saveButton' ) ;
12+
13+ let isDrawing = false ;
14+ let lastX = 0 ;
15+ let lastY = 0 ;
16+ let dpr = window . devicePixelRatio || 1 ;
17+
18+ // Initialize canvas
19+ function initCanvas ( ) {
20+ const container = canvas . parentElement ;
21+ const width = container . clientWidth ;
22+ const height = container . clientHeight ;
23+
24+ // Set canvas size with DPR scaling
25+ canvas . width = width * dpr ;
26+ canvas . height = height * dpr ;
27+ canvas . style . width = `${ width } px` ;
28+ canvas . style . height = `${ height } px` ;
29+
30+ // Scale context for high DPI displays
31+ ctx . scale ( dpr , dpr ) ;
32+
33+ // Set initial drawing styles
34+ ctx . strokeStyle = colorPicker . value ;
35+ ctx . lineWidth = brushSize . value ;
36+ ctx . lineCap = 'round' ;
37+ ctx . lineJoin = 'round' ;
38+
39+ // Clear canvas with white background
40+ ctx . fillStyle = '#ffffff' ;
41+ ctx . fillRect ( 0 , 0 , width , height ) ;
42+ }
43+
44+ // Drawing functions
45+ function startDrawing ( e ) {
46+ isDrawing = true ;
47+ const pos = getPointerPos ( e ) ;
48+ [ lastX , lastY ] = [ pos . x , pos . y ] ;
49+ }
50+
51+ function draw ( e ) {
52+ if ( ! isDrawing ) return ;
53+
54+ e . preventDefault ( ) ;
55+ const pos = getPointerPos ( e ) ;
56+
57+ ctx . beginPath ( ) ;
58+ ctx . moveTo ( lastX , lastY ) ;
59+ ctx . lineTo ( pos . x , pos . y ) ;
60+ ctx . stroke ( ) ;
61+
62+ [ lastX , lastY ] = [ pos . x , pos . y ] ;
63+ }
64+
65+ function stopDrawing ( ) {
66+ isDrawing = false ;
67+ }
68+
69+ function getPointerPos ( e ) {
70+ const rect = canvas . getBoundingClientRect ( ) ;
71+ let clientX , clientY ;
72+
73+ if ( e . type . includes ( 'touch' ) ) {
74+ clientX = e . touches [ 0 ] . clientX ;
75+ clientY = e . touches [ 0 ] . clientY ;
76+ } else {
77+ clientX = e . clientX ;
78+ clientY = e . clientY ;
79+ }
80+
81+ return {
82+ x : ( clientX - rect . left ) * ( canvas . width / dpr / rect . width ) ,
83+ y : ( clientY - rect . top ) * ( canvas . height / dpr / rect . height )
84+ } ;
85+ }
86+
87+ // Event handlers for controls
88+ colorPicker . addEventListener ( 'input' , ( e ) => {
89+ ctx . strokeStyle = e . target . value ;
90+ } ) ;
91+
92+ brushSize . addEventListener ( 'input' , ( e ) => {
93+ const size = e . target . value ;
94+ ctx . lineWidth = size ;
95+ brushSizeValue . textContent = size ;
96+ } ) ;
97+
98+ clearButton . addEventListener ( 'click' , ( ) => {
99+ if ( confirm ( 'Are you sure you want to clear the canvas?' ) ) {
100+ const width = canvas . width / dpr ;
101+ const height = canvas . height / dpr ;
102+ ctx . fillStyle = '#ffffff' ;
103+ ctx . fillRect ( 0 , 0 , width , height ) ;
104+ }
105+ } ) ;
106+
107+ saveButton . addEventListener ( 'click' , ( ) => {
108+ // Create a temporary canvas for saving at original resolution
109+ const tempCanvas = document . createElement ( 'canvas' ) ;
110+ const tempCtx = tempCanvas . getContext ( '2d' ) ;
111+
112+ tempCanvas . width = canvas . width ;
113+ tempCanvas . height = canvas . height ;
114+
115+ // Draw the high-resolution content to temp canvas
116+ tempCtx . drawImage ( canvas , 0 , 0 ) ;
117+
118+ // Create download link
119+ const link = document . createElement ( 'a' ) ;
120+ link . download = `drawing-${ new Date ( ) . getTime ( ) } .png` ;
121+ link . href = tempCanvas . toDataURL ( 'image/png' ) ;
122+ link . click ( ) ;
123+ } ) ;
124+
125+ // Pointer event handlers for drawing
126+ canvas . addEventListener ( 'pointerdown' , startDrawing ) ;
127+ canvas . addEventListener ( 'pointermove' , draw ) ;
128+ canvas . addEventListener ( 'pointerup' , stopDrawing ) ;
129+ canvas . addEventListener ( 'pointerout' , stopDrawing ) ;
130+
131+ // Touch event handlers for mobile devices
132+ canvas . addEventListener ( 'touchstart' , ( e ) => {
133+ e . preventDefault ( ) ;
134+ startDrawing ( e ) ;
135+ } ) ;
136+
137+ canvas . addEventListener ( 'touchmove' , ( e ) => {
138+ e . preventDefault ( ) ;
139+ draw ( e ) ;
140+ } ) ;
141+
142+ canvas . addEventListener ( 'touchend' , stopDrawing ) ;
143+
144+ // Handle window resize
145+ let resizeTimeout ;
146+ window . addEventListener ( 'resize' , ( ) => {
147+ clearTimeout ( resizeTimeout ) ;
148+ resizeTimeout = setTimeout ( ( ) => {
149+ if ( confirm ( 'Resizing will clear your current drawing. Continue?' ) ) {
150+ initCanvas ( ) ;
151+ }
152+ } , 250 ) ;
153+ } ) ;
154+
155+ // Prevent context menu on canvas
156+ canvas . addEventListener ( 'contextmenu' , ( e ) => e . preventDefault ( ) ) ;
157+
158+ // Initialize the canvas
159+ initCanvas ( ) ;
160+ } ) ;
0 commit comments