Delta differential coding

This commit is contained in:
Yaro Kasear 2026-01-12 15:12:11 -06:00
parent 5a2f480ef7
commit cc32b2214c
2 changed files with 128 additions and 44 deletions

View file

@ -157,44 +157,100 @@ function initGridWidget(root, opts = {}) {
} }
function computeDeltas(shapes) { function computeDeltas(shapes) {
return shapes.map(shape => { const q = 100;
if (shape.type === 'stateChange') return shape;
const s = { ...shape }; const out = [];
let points = []; let prevKind = null;
if (s.type === 'path') { let prevBR = null;
if (!Array.isArray(s.points) || s.points.length === 0) return s;
points = [Math.round(s.points[0].x * 100), Math.round(s.points[0].y * 100)]; let prevLineEnd = null;
let prev = s.points[0];
for (let i = 1; i < s.points.length; i++) { const toInt = (n) => Math.round(Number(n) * q);
const cur = s.points[i];
points.push(Math.round((cur.x - prev.x) * 100), Math.round((cur.y - prev.y) * 100)); const resetRun = () => {
prev = cur; prevKind = null;
} prevBR = null;
} else if (s.type === 'line') { prevLineEnd = null;
points = [ };
Math.round(s.x1 * 100),
Math.round(s.y1 * 100), for (const shape of shapes) {
Math.round((s.x2 - s.x1) * 100), if (shape.type === "stateChange") {
Math.round((s.y2 - s.y1) * 100) out.push(shape);
]; resetRun();
delete s.x1; delete s.y1; delete s.x2; delete s.y2; continue;
} else if (s.type === 'rect' || s.type === 'ellipse') {
points = [
Math.round(s.x * 100),
Math.round(s.y * 100),
Math.round(s.w * 100),
Math.round(s.h * 100)
];
delete s.x; delete s.y; delete s.w; delete s.h;
} }
s.points = points; if (shape.type === "path") {
return s; const s = { ...shape };
}); if (!Array.isArray(s.points) || s.points.length === 0) {
out.push(s);
resetRun();
continue;
}
const pts = [toInt(s.points[0].x), toInt(s.points[0].y)];
let prev = s.points[0];
for (let i = 1; i < s.points.length; i++) {
const cur = s.points[i];
pts.push(toInt(cur.x - prev.x), toInt(cur.y - prev.y));
prev = cur;
}
s.points = pts;
out.push(s);
resetRun();
continue;
}
if (shape.type === "line") {
const s = { ...shape };
const x1 = toInt(s.x1), y1 = toInt(s.y1);
const x2 = toInt(s.x2), y2 = toInt(s.y2);
let arr;
if (prevKind !== "line" || !prevLineEnd) {
arr = [x1, y1, x2 - x1, y2 - y1];
} else {
arr = [x1 - prevLineEnd.x2, y1 - prevLineEnd.y2, x2 - x1, y2 - y1];
}
prevKind = "line";
prevLineEnd = { x2, y2 };
delete s.x1; delete s.y1; delete s.x2; delete s.y2;
s.points = arr;
out.push(s);
continue;
}
if (shape.type === "rect" || shape.type === "ellipse") {
const s = { ...shape };
const x = toInt(s.x), y = toInt(s.y);
const w = toInt(s.w), h = toInt(s.h);
let arr;
if (prevKind !== s.type || !prevBR) {
arr = [x, y, w, h];
} else {
arr = [x - prevBR.x, y - prevBR.y, w, h];
}
prevKind = s.type;
prevBR = { x: x + w, y: y + h };
delete s.x; delete s.y; delete s.w; delete s.h;
s.points = arr;
out.push(s);
continue;
}
out.push(shape);
resetRun();
}
return out;
} }
function encodeRuns(shapes) { function encodeRuns(shapes) {
@ -332,37 +388,65 @@ function initGridWidget(root, opts = {}) {
if ((arr.length % 4) !== 0) continue; if ((arr.length % 4) !== 0) continue;
if (t === "l") { if (t === "l") {
let prevX2 = null, prevY2 = null;
for (let i = 0; i < arr.length; i += 4) { for (let i = 0; i < arr.length; i += 4) {
const seg = decodeLine(arr.slice(i, i + 4), q); const a = arr[i], b = arr[i + 1], c = arr[i + 2], d = arr[i + 3];
let x1, y1;
if (i === 0) {
x1 = a; y1 = b;
} else {
x1 = prevX2 + a;
y1 = prevY2 + b;
}
const x2 = x1 + c;
const y2 = y1 + d;
outShapes.push({ outShapes.push({
type: "line", type: "line",
x1: seg.x1, y1: seg.y1, x2: seg.x2, y2: seg.y2, x1: x1 / q, y1: y1 / q, x2: x2 / q, y2: y2 / q,
color: state.color, color: state.color,
strokeWidth: state.strokeWidth, strokeWidth: state.strokeWidth,
strokeOpacity: state.strokeOpacity strokeOpacity: state.strokeOpacity
}); });
prevX2 = x2; prevY2 = y2;
} }
continue; continue;
} }
if (t === "r" || t === "e") { if (t === "r" || t === "e") {
let prevBRx = null, prevBRy = null;
for (let i = 0; i < arr.length; i += 4) { for (let i = 0; i < arr.length; i += 4) {
const x = arr[i] / q; const a = arr[i], b = arr[i + 1], c = arr[i + 2], d = arr[i + 3];
const y = arr[i + 1] / q;
const w = arr[i + 2] / q; let x, y;
const h = arr[i + 3] / q; if (i === 0) {
x = a; y = b;
} else {
x = prevBRx + a;
y = prevBRy + b;
}
const w = c, h = d;
outShapes.push({ outShapes.push({
type: (t === "r") ? "rect" : "ellipse", type: (t === "r") ? "rect" : "ellipse",
x, y, w, h, x: x / q, y: y / q, w: w / q, h: h / q,
color: state.color, color: state.color,
fill: state.fill, fill: state.fill,
fillOpacity: state.fillOpacity, fillOpacity: state.fillOpacity,
strokeWidth: state.strokeWidth, strokeWidth: state.strokeWidth,
strokeOpacity: state.strokeOpacity strokeOpacity: state.strokeOpacity
}); });
prevBRx = x + w;
prevBRy = y + h;
} }
continue continue;
} }
} }

View file

@ -8,21 +8,21 @@
{% block main %} {% block main %}
{% set jsonImage %} {% set jsonImage %}
{"v":1,"cs":5,"q":100,"d":{"cl":"#000000","f":false,"sw":12,"so":100,"fo":100},"s":[{"t":"s","cl":"#e8af11","f":true},{"t":"e","p":[1000,500,2500,2500]},{"t":"s","cl":"#f7a6f4"},{"t":"e","p":[1100,600,2300,2300]},{"t":"s","cl":"#e2b128"},{"t":"e","p":[1600,1100,1300,1300]},{"t":"s","cl":"#ffffff"},{"t":"e","p":[1700,1200,1100,1100]},{"t":"s","cl":"#000000","f":false},{"t":"e","p":[1000,500,2500,2500,1100,600,2300,2300,1600,1100,1300,1300,1700,1200,1100,1100]},{"t":"s","sw":30,"cl":"#ff0000"},{"t":"l","p":[2900,1100,100,0,3100,1700,0,100,3000,2200,100,0,2700,2600,0,-100,2000,2600,100,100,1600,2300,-100,0,1400,1900,0,-100,1300,1400,100,0,1600,1100,0,100,1900,900,100,-100,2300,900,100,100,2600,900,100,-100,3000,1400,100,0,2800,2300,100,0,2500,2600,-100,100,1700,2600,100,-100]},{"t":"s","cl":"#00ff00"},{"t":"l","p":[2700,1100,100,-100,2000,1000,100,0,1400,1600,100,-100,1400,2200,100,0,1300,1900,-100,100,1900,2700,0,-100,2100,2600,100,0,2300,2800,100,0,2500,2400,100,100,2900,2500,100,-100,3200,2000,-100,0,3100,1600,100,-100,3100,1300,-100,0,2400,700,-100,100,1700,900,100,100]},{"t":"s","cl":"#6188ff"},{"t":"l","p":[1500,1300,100,0,1200,1700,100,0,1500,2100,0,-100,1600,2600,0,-100,2000,2500,-100,-100,2400,2500,-100,0,2700,2400,100,0,2900,2100,100,-100,3300,1800,0,100,3000,1600,-100,-100,3200,1700,0,-100,2900,1200,-100,0,2500,900,0,100,2200,900,0,-100,1800,1100,-100,0,1500,1100,-100,100,1700,2400,0,-100,1300,2300,100,100,2600,2800,100,-100,2100,2800,100,-100,3100,2300,100,0,3200,2100,100,-100,2700,1200,100,100,1500,1700,100,-100]}]} {"v":1,"cs":5,"q":100,"d":{"cl":"#000000","f":false,"sw":12,"so":100,"fo":100},"s":[{"t":"s","cl":"#ffff00","f":true},{"t":"e","p":[0,0,2500,2500]},{"t":"s","cl":"#ffffff"},{"t":"e","p":[500,600,600,600,300,-600,600,600]},{"t":"s","cl":"#000000"},{"t":"e","p":[700,800,200,200,700,-200,200,200,-800,300,500,1000]},{"t":"s","f":false},{"t":"e","p":[500,600,600,600,300,-600,600,600,-2000,-1200,2500,2500]},{"t":"l","p":[400,700,500,-300,1200,300,-500,-300]}]}
{% endset %} {% endset %}
{% set jsonImage2 %} {% set jsonImage2 %}
{"v":1,"cs":5,"q":100,"d":{"cl":"#000000","f":false,"sw":12,"so":100,"fo":100},"s":[{"t":"r","p":[1000,500,1500,1500,1000,500,500,500,1500,500,500,500,2000,500,500,500,2000,1000,500,500,1500,1000,500,500,1000,1000,500,500,1000,1500,500,500,1500,1500,500,500,2000,1500,500,500]},{"t":"s","so":0,"fo":50,"cl":"#ff0000","f":true},{"t":"r","p":[1000,500,500,500,2000,1500,500,500,2000,500,500,500,1000,1500,500,500]},{"t":"s","cl":"#00ff00"},{"t":"r","p":[1500,1000,500,500]},{"t":"s","cl":"#0000ff"},{"t":"r","p":[1500,500,500,500,2000,1000,500,500,1500,1500,500,500,1000,1000,500,500]},{"t":"s","sw":2,"so":100,"cl":"#000000","f":false},{"t":"e","p":[1100,600,300,300,1600,600,300,300,2100,600,300,300,2100,1100,300,300,1600,1100,300,300,1100,1100,300,300,1100,1600,300,300,1600,1600,300,300,2100,1600,300,300]},{"t":"s","sw":12},{"t":"r","p":[500,0,2500,2500]},{"t":"s","so":5,"f":true},{"t":"r","p":[500,0,500,2500,1000,2000,2000,500,2500,0,500,2000,1000,0,1500,500]},{"t":"s","so":100},{"t":"l","p":[1000,500,1500,1500,1000,2000,1500,-1500,2000,500,500,500,1500,500,1000,1000,1000,1000,1000,1000,1000,1500,500,500,1500,2000,1000,-1000,2000,2000,500,-500,1000,1500,1000,-1000,1000,1000,500,-500]}]} {"v":1,"cs":5,"q":100,"d":{"cl":"#000000","f":false,"sw":12,"so":100,"fo":100},"s":[{"t":"s","cl":"#ffe59e","f":true},{"t":"e","p":[0,0,2500,2500]},{"t":"s","cl":"#fdc8fe"},{"t":"e","p":[100,100,2300,2300]},{"t":"s","cl":"#fbe6a1"},{"t":"e","p":[600,600,1300,1300]},{"t":"s","cl":"#ffffff"},{"t":"e","p":[700,700,1100,1100]},{"t":"s","cl":"#000000","f":false},{"t":"e","p":[0,0,2500,2500,-2400,-2400,2300,2300,-1800,-1800,1300,1300,-1200,-1200,1100,1100]},{"t":"s","sw":37,"cl":"#ff0000"},{"t":"l","p":[600,500,100,-100,500,0,100,0,500,200,100,100,200,200,100,-100,-600,-400,0,-100,-800,300,-100,100,-400,800,0,-100,100,-400,-100,-100,200,1000,100,0,-100,-600,-100,-100,500,1000,100,-100,-200,-200,0,100,500,200,100,-100,200,-200,100,100,-500,0,-100,100,800,-400,100,100,0,-400,100,100,0,-300,100,0,-200,-100,0,-100,0,-400,0,100,-400,-200,100,0,-600,-200,100,-100,-300,100,0,100,-300,500,-100,-100,0,900,100,-100,1300,400,100,-100,200,-200,0,-100,100,-200,0,-100]},{"t":"s","cl":"#00ff00"},{"t":"l","p":[400,700,100,0,500,-200,0,-100,400,-200,0,100,100,200,100,100,200,-200,100,100,300,600,100,0,-400,-300,100,100,100,400,100,0,100,200,-100,0,-200,100,100,100,0,200,100,-100,-400,100,0,-100,-100,300,100,0,-200,200,0,-100,-100,-200,0,100,-200,200,100,0,-300,0,0,-100,200,-100,100,-100,-400,0,100,0,-300,100,100,0,-200,-300,0,100,-200,-100,100,0,-200,-100,0,-100,100,-100,0,-100,-300,-100,100,0,0,-200,100,0,100,-200,0,100,100,-400,100,0]},{"t":"s","cl":"#0000ff"},{"t":"l","p":[800,400,0,100,300,0,100,0,200,-100,100,-100,200,0,0,100,300,100,100,100,0,200,0,-100,0,300,100,0,-200,300,0,-100,100,200,100,0,-300,100,0,100,0,200,0,100,-200,-100,0,100,200,200,-100,-100,0,200,-100,0,-100,-100,0,-100,-100,200,-100,0,-200,100,0,-100,-300,100,100,-100,-100,-300,0,100,-300,100,100,0,-200,-100,100,0,-200,-100,-100,-100,0,-200,100,-100,0,-200,-100,-100,100,-400,-100,0,200,300,100,-100,100,-200,-100,-100,300,-100,100,0,-500,-100,-100,100,1300,100,100,100,-1200,900,100,0]}]}
{% endset %} {% endset %}
<div class="row"> <div class="row">
<div class="col" style="height: 80vh;"> <div class="col" style="height: 80vh;">
{{ draw.drawWidget('test1') }} {{ draw.drawWidget('test1') }}
</div> </div>
<!-- div class="col" style="height: 80vh;"> <div class="col" style="height: 80vh;">
I am testing a thing. I am testing a thing.
{{ draw.viewWidget('test2', jsonImage) }} {{ draw.viewWidget('test2', jsonImage) }}
{{ draw.viewWidget('test3', jsonImage2) }} {{ draw.viewWidget('test3', jsonImage2) }}
The thing has been tested. The thing has been tested.
</div --> </div>
</div> </div>
{% endblock %} {% endblock %}