JavaScript · 3839 bytes Raw Blame History
1 // Main canvas setup
2 const canvas = document.getElementById('board')
3 const ctx = canvas.getContext('2d')
4 const chars = [
5 '@', '#', '$', '%', '&', '*', '+', '=',
6 '~', '?', 'Ω', '∞', '¶', '§', '★', '☆'
7 ]
8 let drawing = false
9 let currentColor = '#0f0'
10
11 // Color wheel setup
12 const colorWheel = document.getElementById('colorWheel')
13 const colorCtx = colorWheel.getContext('2d')
14 const colorPreview = document.getElementById('colorPreview')
15 colorWheel.width = 150
16 colorWheel.height = 150
17
18 // Draw color wheel
19 function drawColorWheel() {
20 const centerX = colorWheel.width / 2
21 const centerY = colorWheel.height / 2
22 const radius = Math.min(centerX, centerY) - 2
23
24 for (let angle = 0; angle < 360; angle++) {
25 const startAngle = (angle - 1) * Math.PI / 180
26 const endAngle = angle * Math.PI / 180
27
28 colorCtx.beginPath()
29 colorCtx.moveTo(centerX, centerY)
30 colorCtx.arc(centerX, centerY, radius, startAngle, endAngle)
31 colorCtx.closePath()
32
33 const gradient = colorCtx.createRadialGradient(centerX, centerY, 0, centerX, centerY, radius)
34 gradient.addColorStop(0, 'white')
35 gradient.addColorStop(0.7, `hsl(${angle}, 100%, 50%)`)
36 gradient.addColorStop(1, `hsl(${angle}, 100%, 25%)`)
37
38 colorCtx.fillStyle = gradient
39 colorCtx.fill()
40 }
41 }
42
43 // Get color from wheel position
44 function getColorFromWheel(x, y) {
45 const centerX = colorWheel.width / 2
46 const centerY = colorWheel.height / 2
47 const dx = x - centerX
48 const dy = y - centerY
49 const distance = Math.sqrt(dx * dx + dy * dy)
50 const maxRadius = Math.min(centerX, centerY) - 2
51
52 if (distance > maxRadius) return null
53
54 let angle = Math.atan2(dy, dx) * 180 / Math.PI
55 angle = (angle + 360) % 360
56
57 const saturation = Math.min(100, (distance / maxRadius) * 100)
58 const lightness = 50 - (distance / maxRadius) * 25
59
60 return `hsl(${angle}, ${saturation}%, ${lightness}%)`
61 }
62
63 // Color wheel interaction
64 colorWheel.addEventListener('click', (e) => {
65 const rect = colorWheel.getBoundingClientRect()
66 const x = e.clientX - rect.left
67 const y = e.clientY - rect.top
68 const color = getColorFromWheel(x, y)
69
70 if (color) {
71 currentColor = color
72 colorPreview.style.backgroundColor = color
73 }
74 })
75
76 // Drawing functions
77 function randomChar() {
78 return chars[Math.floor(Math.random() * chars.length)]
79 }
80
81 function getFont() {
82 return `${sizeInput.value}px monospace`
83 }
84
85 function draw(e) {
86 if (!drawing) return
87 const rect = canvas.getBoundingClientRect()
88 const x = e.clientX - rect.left
89 const y = e.clientY - rect.top
90 ctx.font = getFont()
91 ctx.fillStyle = currentColor
92 ctx.fillText(randomChar(), x, y)
93 }
94
95 // Mouse events
96 canvas.addEventListener('mousedown', () => (drawing = true))
97 canvas.addEventListener('mouseup', () => (drawing = false))
98 canvas.addEventListener('mouseleave', () => (drawing = false))
99 canvas.addEventListener('mousemove', draw)
100
101 // Touch support
102 canvas.addEventListener('touchstart', e => {
103 drawing = true
104 draw(e.touches[0])
105 })
106 canvas.addEventListener('touchmove', e => {
107 draw(e.touches[0])
108 e.preventDefault()
109 })
110 canvas.addEventListener('touchend', () => (drawing = false))
111
112 // Controls
113 const clearBtn = document.getElementById('clear')
114 clearBtn.onclick = () => ctx.clearRect(0, 0, canvas.width, canvas.height)
115
116 const sizeInput = document.getElementById('size')
117
118 // Initialize
119 drawColorWheel()
120 colorPreview.style.backgroundColor = currentColor