diff options
author | Star Rauchenberger <fefferburbia@gmail.com> | 2023-11-30 13:29:08 -0500 |
---|---|---|
committer | Star Rauchenberger <fefferburbia@gmail.com> | 2023-11-30 13:29:08 -0500 |
commit | 0929719a845897cc8567cf972e07a69a71f0fa6f (patch) | |
tree | 2b6f69c1d906abb6e0abf8a0f1d51725bc78087d /app/assets/javascripts/display2.js | |
parent | 01c1947537e4e23ded0c16812a7cd9d49ad88356 (diff) | |
download | wittle-0929719a845897cc8567cf972e07a69a71f0fa6f.tar.gz wittle-0929719a845897cc8567cf972e07a69a71f0fa6f.tar.bz2 wittle-0929719a845897cc8567cf972e07a69a71f0fa6f.zip |
Migrate to a full rails app
Diffstat (limited to 'app/assets/javascripts/display2.js')
-rw-r--r-- | app/assets/javascripts/display2.js | 316 |
1 files changed, 316 insertions, 0 deletions
diff --git a/app/assets/javascripts/display2.js b/app/assets/javascripts/display2.js new file mode 100644 index 0000000..ddf3968 --- /dev/null +++ b/app/assets/javascripts/display2.js | |||
@@ -0,0 +1,316 @@ | |||
1 | var SYM_TYPE_NONE = 0 | ||
2 | var SYM_TYPE_HORIZONTAL = 1 | ||
3 | var SYM_TYPE_VERTICAL = 2 | ||
4 | var SYM_TYPE_ROTATIONAL = 3 | ||
5 | var SYM_TYPE_ROTATE_LEFT = 4 | ||
6 | var SYM_TYPE_ROTATE_RIGHT = 5 | ||
7 | var SYM_TYPE_FLIP_XY = 6 | ||
8 | var SYM_TYPE_FLIP_NEG_XY = 7 | ||
9 | var SYM_TYPE_PARALLEL_H = 8 | ||
10 | var SYM_TYPE_PARALLEL_V = 9 | ||
11 | var SYM_TYPE_PARALLEL_H_FLIP = 10 | ||
12 | var SYM_TYPE_PARALLEL_V_FLIP = 11 | ||
13 | var SYM_TYPE_PILLAR_PARALLEL = 12 | ||
14 | var SYM_TYPE_PILLAR_HORIZONTAL = 13 | ||
15 | var SYM_TYPE_PILLAR_VERTICAL = 14 | ||
16 | var SYM_TYPE_PILLAR_ROTATIONAL = 15 | ||
17 | |||
18 | namespace(function() { | ||
19 | |||
20 | window.draw = function(puzzle, target='puzzle') { | ||
21 | if (puzzle == null) return | ||
22 | var svg = document.getElementById(target) | ||
23 | console.info('Drawing', puzzle, 'into', svg) | ||
24 | while (svg.firstChild) svg.removeChild(svg.firstChild) | ||
25 | |||
26 | // Prevent context menu popups within the puzzle | ||
27 | svg.oncontextmenu = function(event) { | ||
28 | event.preventDefault() | ||
29 | } | ||
30 | |||
31 | if (puzzle.pillar === true) { | ||
32 | // 41*width + 30*2 (padding) + 10*2 (border) | ||
33 | var pixelWidth = 41 * puzzle.width + 80 | ||
34 | } else { | ||
35 | // 41*(width-1) + 24 (extra edge) + 30*2 (padding) + 10*2 (border) | ||
36 | var pixelWidth = 41 * puzzle.width + 63 | ||
37 | } | ||
38 | var pixelHeight = 41 * puzzle.height + 63 | ||
39 | svg.setAttribute('viewbox', '0 0 ' + pixelWidth + ' ' + pixelHeight) | ||
40 | svg.setAttribute('width', pixelWidth) | ||
41 | svg.setAttribute('height', pixelHeight) | ||
42 | |||
43 | var rect = createElement('rect') | ||
44 | svg.appendChild(rect) | ||
45 | rect.setAttribute('stroke-width', 10) | ||
46 | rect.setAttribute('stroke', window.BORDER) | ||
47 | rect.setAttribute('fill', window.OUTER_BACKGROUND) | ||
48 | // Accounting for the border thickness | ||
49 | rect.setAttribute('x', 5) | ||
50 | rect.setAttribute('y', 5) | ||
51 | rect.setAttribute('width', pixelWidth - 10) // Removing border | ||
52 | rect.setAttribute('height', pixelHeight - 10) // Removing border | ||
53 | |||
54 | drawCenters(puzzle, svg) | ||
55 | drawGrid(puzzle, svg, target) | ||
56 | drawStartAndEnd(puzzle, svg) | ||
57 | // Draw cell symbols after so they overlap the lines, if necessary | ||
58 | drawSymbols(puzzle, svg, target) | ||
59 | |||
60 | // For pillar puzzles, add faders for the left and right sides | ||
61 | if (puzzle.pillar === true) { | ||
62 | var defs = window.createElement('defs') | ||
63 | defs.id = 'cursorPos' | ||
64 | defs.innerHTML = '' + | ||
65 | '<linearGradient id="fadeInLeft">\n' + | ||
66 | ' <stop offset="0%" stop-opacity="1.0" stop-color="' + window.OUTER_BACKGROUND + '"></stop>\n' + | ||
67 | ' <stop offset="25%" stop-opacity="1.0" stop-color="' + window.OUTER_BACKGROUND + '"></stop>\n' + | ||
68 | ' <stop offset="100%" stop-opacity="0.0" stop-color="' + window.OUTER_BACKGROUND + '"></stop>\n' + | ||
69 | '</linearGradient>\n' + | ||
70 | '<linearGradient id="fadeOutRight">\n' + | ||
71 | ' <stop offset="0%" stop-opacity="0.0" stop-color="' + window.OUTER_BACKGROUND + '"></stop>\n' + | ||
72 | ' <stop offset="100%" stop-opacity="1.0" stop-color="' + window.OUTER_BACKGROUND + '"></stop>\n' + | ||
73 | '</linearGradient>\n' | ||
74 | svg.appendChild(defs) | ||
75 | |||
76 | var leftBox = window.createElement('rect') | ||
77 | leftBox.setAttribute('x', 16) | ||
78 | leftBox.setAttribute('y', 10) | ||
79 | leftBox.setAttribute('width', 48) | ||
80 | leftBox.setAttribute('height', 41 * puzzle.height + 43) | ||
81 | leftBox.setAttribute('fill', 'url(#fadeInLeft)') | ||
82 | leftBox.setAttribute('style', 'pointer-events: none') | ||
83 | svg.appendChild(leftBox) | ||
84 | |||
85 | var rightBox = window.createElement('rect') | ||
86 | rightBox.setAttribute('x', 41 * puzzle.width + 22) | ||
87 | rightBox.setAttribute('y', 10) | ||
88 | rightBox.setAttribute('width', 30) | ||
89 | rightBox.setAttribute('height', 41 * puzzle.height + 43) | ||
90 | rightBox.setAttribute('fill', 'url(#fadeOutRight)') | ||
91 | rightBox.setAttribute('style', 'pointer-events: none') | ||
92 | svg.appendChild(rightBox) | ||
93 | } | ||
94 | } | ||
95 | |||
96 | function drawCenters(puzzle, svg) { | ||
97 | // @Hack that I am not fixing. This switches the puzzle's grid to a floodfilled grid | ||
98 | // where null represents cells which are part of the outside | ||
99 | var savedGrid = puzzle.switchToMaskedGrid() | ||
100 | if (puzzle.pillar === true) { | ||
101 | for (var y=1; y<puzzle.height; y += 2) { | ||
102 | if (puzzle.getCell(-1, y) == null) continue // Cell borders the outside | ||
103 | |||
104 | var rect = createElement('rect') | ||
105 | rect.setAttribute('x', 28) | ||
106 | rect.setAttribute('y', 41 * y + 11) | ||
107 | rect.setAttribute('width', 24) | ||
108 | rect.setAttribute('height', 82) | ||
109 | rect.setAttribute('fill', window.BACKGROUND) | ||
110 | svg.appendChild(rect) | ||
111 | } | ||
112 | } | ||
113 | |||
114 | for (var x=1; x<puzzle.width; x += 2) { | ||
115 | for (var y=1; y<puzzle.height; y += 2) { | ||
116 | if (puzzle.grid[x][y] == null) continue // Cell borders the outside | ||
117 | |||
118 | var rect = createElement('rect') | ||
119 | rect.setAttribute('x', 41 * x + 11) | ||
120 | rect.setAttribute('y', 41 * y + 11) | ||
121 | rect.setAttribute('width', 82) | ||
122 | rect.setAttribute('height', 82) | ||
123 | rect.setAttribute('fill', window.BACKGROUND) | ||
124 | rect.setAttribute('shape-rendering', 'crispedges') // Otherwise they don't meet behind gaps | ||
125 | svg.appendChild(rect) | ||
126 | } | ||
127 | } | ||
128 | puzzle.grid = savedGrid | ||
129 | } | ||
130 | |||
131 | function drawGrid(puzzle, svg, target) { | ||
132 | for (var x=0; x<puzzle.width; x++) { | ||
133 | for (var y=0; y<puzzle.height; y++) { | ||
134 | var cell = puzzle.grid[x][y] | ||
135 | if (cell != null && cell.gap === window.GAP_FULL) continue | ||
136 | if (cell != null && cell.gap === window.GAP_BREAK) { | ||
137 | var params = { | ||
138 | 'width':58, | ||
139 | 'height':58, | ||
140 | 'x': x*41 + 23, | ||
141 | 'y': y*41 + 23, | ||
142 | 'class': target + '_' + x + '_' + y, | ||
143 | 'type': 'gap', | ||
144 | } | ||
145 | if (x%2 === 0 && y%2 === 1) params.rot = 1 | ||
146 | drawSymbolWithSvg(svg, params) | ||
147 | continue | ||
148 | } | ||
149 | |||
150 | var line = createElement('line') | ||
151 | line.setAttribute('stroke-width', 24) | ||
152 | line.setAttribute('stroke-linecap', 'round') | ||
153 | line.setAttribute('stroke', window.FOREGROUND) | ||
154 | if (x%2 === 1 && y%2 === 0) { // Horizontal | ||
155 | if (cell.gap === window.GAP_BREAK) continue | ||
156 | line.setAttribute('x1', (x-1)*41 + 52) | ||
157 | // Adjust the length if it's a pillar -- the grid is not as wide! | ||
158 | if (puzzle.pillar === true && x === puzzle.width - 1) { | ||
159 | line.setAttribute('x2', (x+1)*41 + 40) | ||
160 | } else { | ||
161 | line.setAttribute('x2', (x+1)*41 + 52) | ||
162 | } | ||
163 | line.setAttribute('y1', y*41 + 52) | ||
164 | line.setAttribute('y2', y*41 + 52) | ||
165 | svg.appendChild(line) | ||
166 | } else if (x%2 === 0 && y%2 === 1) { // Vertical | ||
167 | if (cell.gap === window.GAP_BREAK) continue | ||
168 | line.setAttribute('x1', x*41 + 52) | ||
169 | line.setAttribute('x2', x*41 + 52) | ||
170 | line.setAttribute('y1', (y-1)*41 + 52) | ||
171 | line.setAttribute('y2', (y+1)*41 + 52) | ||
172 | svg.appendChild(line) | ||
173 | } else if (x%2 === 0 && y%2 === 0) { // Intersection | ||
174 | var surroundingLines = 0 | ||
175 | if (cell.end != null) surroundingLines++ | ||
176 | var leftCell = puzzle.getCell(x - 1, y) | ||
177 | if (leftCell != null && leftCell.gap !== window.GAP_FULL) surroundingLines++ | ||
178 | var rightCell = puzzle.getCell(x + 1, y) | ||
179 | if (rightCell != null && rightCell.gap !== window.GAP_FULL) surroundingLines++ | ||
180 | var topCell = puzzle.getCell(x, y - 1) | ||
181 | if (topCell != null && topCell.gap !== window.GAP_FULL) surroundingLines++ | ||
182 | var bottomCell = puzzle.getCell(x, y + 1) | ||
183 | if (bottomCell != null && bottomCell.gap !== window.GAP_FULL) surroundingLines++ | ||
184 | |||
185 | if (surroundingLines === 1) { | ||
186 | // Add square caps for dead ends which are non-endpoints | ||
187 | var rect = createElement('rect') | ||
188 | rect.setAttribute('x', x*41 + 40) | ||
189 | rect.setAttribute('y', y*41 + 40) | ||
190 | rect.setAttribute('width', 24) | ||
191 | rect.setAttribute('height', 24) | ||
192 | rect.setAttribute('fill', window.FOREGROUND) | ||
193 | svg.appendChild(rect) | ||
194 | } else if (surroundingLines > 1) { | ||
195 | // Add rounding for other intersections (handling gap-only corners) | ||
196 | var circ = createElement('circle') | ||
197 | circ.setAttribute('cx', x*41 + 52) | ||
198 | circ.setAttribute('cy', y*41 + 52) | ||
199 | circ.setAttribute('r', 12) | ||
200 | circ.setAttribute('fill', window.FOREGROUND) | ||
201 | svg.appendChild(circ) | ||
202 | } | ||
203 | } | ||
204 | } | ||
205 | } | ||
206 | // Determine if left-side needs a 'wrap indicator' | ||
207 | if (puzzle.pillar === true) { | ||
208 | var x = 0; | ||
209 | for (var y=0; y<puzzle.height; y+=2) { | ||
210 | var cell = puzzle.getCell(x-1, y) | ||
211 | if (cell == null || cell.gap === window.GAP_FULL) continue | ||
212 | var line = createElement('line') | ||
213 | line.setAttribute('stroke-width', 24) | ||
214 | line.setAttribute('stroke-linecap', 'round') | ||
215 | line.setAttribute('stroke', window.FOREGROUND) | ||
216 | line.setAttribute('x1', x*41 + 40) | ||
217 | line.setAttribute('x2', x*41 + 52) | ||
218 | line.setAttribute('y1', y*41 + 52) | ||
219 | line.setAttribute('y2', y*41 + 52) | ||
220 | svg.appendChild(line) | ||
221 | } | ||
222 | } | ||
223 | } | ||
224 | |||
225 | function drawSymbols(puzzle, svg, target) { | ||
226 | for (var x=0; x<puzzle.width; x++) { | ||
227 | for (var y=0; y<puzzle.height; y++) { | ||
228 | var cell = puzzle.grid[x][y] | ||
229 | if (cell == null) continue | ||
230 | var params = { | ||
231 | 'width':58, | ||
232 | 'height':58, | ||
233 | 'x': x*41 + 23, | ||
234 | 'y': y*41 + 23, | ||
235 | 'class': target + '_' + x + '_' + y, | ||
236 | } | ||
237 | if (cell.dot > window.DOT_NONE) { | ||
238 | params.type = 'dot' | ||
239 | if (cell.dot === window.DOT_BLACK) params.color = 'black' | ||
240 | else if (cell.dot === window.DOT_BLUE) params.color = window.LINE_PRIMARY | ||
241 | else if (cell.dot === window.DOT_YELLOW) params.color = window.LINE_SECONDARY | ||
242 | else if (cell.dot === window.DOT_INVISIBLE) { | ||
243 | params.color = window.FOREGROUND | ||
244 | // This makes the invisible dots visible, but only while we're in the editor. | ||
245 | if (document.getElementById('metaButtons') != null) { | ||
246 | params.stroke = 'black' | ||
247 | params.strokeWidth = '2px' | ||
248 | } | ||
249 | } | ||
250 | drawSymbolWithSvg(svg, params) | ||
251 | } else if (cell.gap === window.GAP_BREAK) { | ||
252 | // Gaps were handled above, while drawing the grid. | ||
253 | } else if (x%2 === 1 && y%2 === 1) { | ||
254 | // Generic draw for all other elements | ||
255 | Object.assign(params, cell) | ||
256 | window.drawSymbolWithSvg(svg, params, puzzle.settings.CUSTOM_MECHANICS) | ||
257 | } | ||
258 | } | ||
259 | } | ||
260 | } | ||
261 | |||
262 | function drawStartAndEnd(puzzle, svg) { | ||
263 | for (var x=0; x<puzzle.width; x++) { | ||
264 | for (var y=0; y<puzzle.height; y++) { | ||
265 | var cell = puzzle.grid[x][y] | ||
266 | if (cell == null) continue | ||
267 | if (cell.end != null) { | ||
268 | window.drawSymbolWithSvg(svg, { | ||
269 | 'type': 'end', | ||
270 | 'width': 58, | ||
271 | 'height': 58, | ||
272 | 'dir': cell.end, | ||
273 | 'x': x*41 + 23, | ||
274 | 'y': y*41 + 23, | ||
275 | }) | ||
276 | } | ||
277 | |||
278 | if (cell.start === true) { | ||
279 | var symStart = null | ||
280 | if (puzzle.symType != SYM_TYPE_NONE) { | ||
281 | var sym = puzzle.getSymmetricalPos(x, y) | ||
282 | window.drawSymbolWithSvg(svg, { | ||
283 | 'type': 'start', | ||
284 | 'width': 58, | ||
285 | 'height': 58, | ||
286 | 'x': sym.x*41 + 23, | ||
287 | 'y': sym.y*41 + 23, | ||
288 | }) | ||
289 | symStart = svg.lastChild | ||
290 | symStart.style.display = 'none' | ||
291 | symStart.id = 'symStart_' + svg.id + '_' + x + '_' + y | ||
292 | } | ||
293 | |||
294 | window.drawSymbolWithSvg(svg, { | ||
295 | 'type': 'start', | ||
296 | 'width': 58, | ||
297 | 'height': 58, | ||
298 | 'x': x*41 + 23, | ||
299 | 'y': y*41 + 23, | ||
300 | }) | ||
301 | var start = svg.lastChild | ||
302 | start.id = 'start_' + svg.id + '_' + x + '_' + y | ||
303 | |||
304 | // ;(function(a){}(a)) | ||
305 | // This syntax is used to forcibly copy all of the arguments | ||
306 | ;(function(puzzle, x, y, start, symStart) { | ||
307 | start.onpointerdown = function(event) { | ||
308 | window.trace(event, puzzle, {'x':x, 'y':y}, start, symStart) | ||
309 | } | ||
310 | }(puzzle, x, y, start, symStart)) | ||
311 | } | ||
312 | } | ||
313 | } | ||
314 | } | ||
315 | |||
316 | }) | ||