Viewer is working, in theory!

This commit is contained in:
Yaro Kasear 2026-01-07 10:03:17 -06:00
parent e4b59b124e
commit 6ab8ce4069
3 changed files with 184 additions and 12 deletions

View file

@ -299,8 +299,26 @@ function initGridWidget(root, opts = {}) {
resizeAndSetupCanvas();
redrawAll();
// ✅ viewer mode still needs to respond to layout/resize
if (mode !== 'editor') {
return { setDoc, redraw: redrawAll };
const ro = new ResizeObserver(() => resizeAndSetupCanvas());
ro.observe(gridEl);
ro.observe(gridWrapEl);
// optional, but helps with viewport changes
window.addEventListener('resize', resizeAndSetupCanvas, { passive: true });
// also optional: if it's inside tabs/collapses, kick one extra redraw
requestAnimationFrame(() => resizeAndSetupCanvas());
return {
setDoc,
redraw: redrawAll,
destroy() {
ro.disconnect();
window.removeEventListener('resize', resizeAndSetupCanvas);
}
};
}
const MAX_HISTORY = 100;
@ -344,6 +362,12 @@ function initGridWidget(root, opts = {}) {
let currentStrokeOpacity = clamp01(strokeOpacityEl?.value ?? 1, 1);
let currentStrokeWidth = Number(strokeWidthEl?.value ?? 0.12) || 0.12;
selectedColor = colorEl?.value || '#000000';
if (dotSVGEl) {
const circle = dotSVGEl.querySelector('circle');
circle?.setAttribute('fill', selectedColor);
}
let currentShape = null;
const history = [structuredClone(shapes)];
let historyIndex = 0
@ -887,15 +911,6 @@ function initGridWidget(root, opts = {}) {
const simplified = simplifyRDP(coarse, epsilon);
if (simplified.length >= 2) {
const renderPoints = catmullRomResample(simplified, {
alpha: 0.5,
samplesPerSeg: 10,
maxSamplesPerSeg: 40,
minSamplesPerSeg: 6,
closed: false,
maxOutputPoints: 4000 // also fix your option name, see below
});
finalShape = {
type: 'path',
points: simplified,
@ -922,7 +937,7 @@ function initGridWidget(root, opts = {}) {
if (finalShape) commit([...shapes, finalShape]);
currentShape = null;
renderAllWithPreview(null); // clean final render
renderAllWithPreview(null);
}
gridEl.addEventListener('pointerup', finishPointer);

View file

@ -244,4 +244,22 @@
{% endmacro %}
{% macro viewWidget(uid, json) %}
{% endmacro %}
<div class="grid-widget" data-grid-widget data-mode="viewer" data-storage-key="gridDoc:{{ uid }}">
<div class="grid-wrap" data-grid-wrap>
<span class="position-absolute p-0 m-0 d-none dot" data-dot>
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32" data-dot-svg>
<circle cx="16" cy="16" r="4" fill="black" />
</svg>
</span>
<div class="position-relative overflow-hidden grid" data-grid>
<div class="border border-black position-absolute d-none bg-warning-subtle px-1 py-0 user-select-none coords"
data-coords></div>
<canvas class="position-absolute w-100 h-100" data-canvas></canvas>
</div>
</div>
<script type="application/json" data-grid-doc>
{{ json | safe }}
</script>
</div>
{% endmacro %}

View file

@ -7,10 +7,149 @@
{% endblock %}
{% block main %}
{% set jsonImage %}
{
"version": 1,
"cellSize": 8,
"shapes": [
{
"type": "ellipse",
"x": 5,
"y": 5,
"w": 15,
"h": 15,
"color": "#ffff00",
"fill": true,
"fillOpacity": 1,
"strokeOpacity": 1,
"strokeWidth": 0.12
},
{
"type": "ellipse",
"x": 5,
"y": 5,
"w": 15,
"h": 15,
"color": "#000000",
"fill": false,
"fillOpacity": 1,
"strokeOpacity": 1,
"strokeWidth": 0.12
},
{
"type": "ellipse",
"x": 8,
"y": 9,
"w": 3,
"h": 3,
"color": "#ffffff",
"fill": true,
"fillOpacity": 1,
"strokeOpacity": 1,
"strokeWidth": 0.12
},
{
"type": "ellipse",
"x": 14,
"y": 9,
"w": 3,
"h": 3,
"color": "#ffffff",
"fill": true,
"fillOpacity": 1,
"strokeOpacity": 1,
"strokeWidth": 0.12
},
{
"type": "ellipse",
"x": 8,
"y": 9,
"w": 3,
"h": 3,
"color": "#000000",
"fill": false,
"fillOpacity": 1,
"strokeOpacity": 1,
"strokeWidth": 0.12
},
{
"type": "ellipse",
"x": 14,
"y": 9,
"w": 3,
"h": 3,
"color": "#000000",
"fill": false,
"fillOpacity": 1,
"strokeOpacity": 1,
"strokeWidth": 0.12
},
{
"type": "ellipse",
"x": 9,
"y": 10,
"w": 1,
"h": 1,
"color": "#000000",
"fill": true,
"fillOpacity": 1,
"strokeOpacity": 1,
"strokeWidth": 0.12
},
{
"type": "ellipse",
"x": 15,
"y": 10,
"w": 1,
"h": 1,
"color": "#000000",
"fill": true,
"fillOpacity": 1,
"strokeOpacity": 1,
"strokeWidth": 0.12
},
{
"type": "ellipse",
"x": 11,
"y": 13,
"w": 3,
"h": 5,
"color": "#000000",
"fill": true,
"fillOpacity": 1,
"strokeOpacity": 1,
"strokeWidth": 0.12
},
{
"type": "line",
"x1": 7,
"y1": 9,
"x2": 10,
"y2": 8,
"color": "#000000",
"strokeWidth": 0.12,
"strokeOpacity": 1
},
{
"type": "line",
"x1": 15,
"y1": 8,
"x2": 18,
"y2": 9,
"color": "#000000",
"strokeWidth": 0.12,
"strokeOpacity": 1
}
]
}
{% endset %}
<div class="row">
<div class="col" style="min-height: 80vh">
{{ draw.drawWidget('test1') }}
</div>
<div class="col" style="min-height: 80vh">
{{ draw.viewWidget('test2', jsonImage) }}
</div>
</div>
{% endblock %}