Skip to content

Commit

Permalink
fix(Canvas): Change registration API. Pass config instead of simple f…
Browse files Browse the repository at this point in the history
…unction to enable `retainState` use case (fix `Group` translate() use case). Return `unregister` function
  • Loading branch information
techniq committed Jan 10, 2025
1 parent a9c16ba commit 6e91781
Show file tree
Hide file tree
Showing 13 changed files with 62 additions and 39 deletions.
5 changes: 3 additions & 2 deletions packages/layerchart/src/lib/components/Arc.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -216,8 +216,9 @@
});
}
let canvasUnregister: ReturnType<typeof canvasContext.register>;
$: if (renderContext === 'canvas') {
canvasContext.register(render);
canvasUnregister = canvasContext.register({ name: 'Arc', render });
}
$: if (renderContext === 'canvas') {
Expand All @@ -228,7 +229,7 @@
onDestroy(() => {
if (renderContext === 'canvas') {
canvasContext.deregister(render);
canvasUnregister();
}
});
</script>
Expand Down
5 changes: 3 additions & 2 deletions packages/layerchart/src/lib/components/Area.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,9 @@
});
}
let canvasUnregister: ReturnType<typeof canvasContext.register>;
$: if (renderContext === 'canvas') {
canvasContext.register(render);
canvasUnregister = canvasContext.register({ name: 'Area', render });
tweened_d.subscribe(() => {
canvasContext.invalidate();
Expand All @@ -152,7 +153,7 @@
onDestroy(() => {
if (renderContext === 'canvas') {
canvasContext.deregister(render);
canvasUnregister();
}
});
</script>
Expand Down
5 changes: 3 additions & 2 deletions packages/layerchart/src/lib/components/Circle.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,9 @@
});
}
let canvasUnregister: ReturnType<typeof canvasContext.register>;
$: if (renderContext === 'canvas') {
canvasContext.register(render);
canvasUnregister = canvasContext.register({ name: 'Circle', render });
}
$: if (renderContext === 'canvas') {
Expand All @@ -57,7 +58,7 @@
onDestroy(() => {
if (renderContext === 'canvas') {
canvasContext.deregister(render);
canvasUnregister();
}
});
</script>
Expand Down
5 changes: 3 additions & 2 deletions packages/layerchart/src/lib/components/GeoPath.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,9 @@
}
}
let canvasUnregister: ReturnType<typeof canvasContext.register>;
$: if (renderContext === 'canvas') {
canvasContext.register(_render);
canvasUnregister = canvasContext.register({ name: 'GeoPath', render: _render });
}
$: if (renderContext === 'canvas') {
Expand All @@ -101,7 +102,7 @@
onDestroy(() => {
if (renderContext === 'canvas') {
canvasContext.deregister(_render);
canvasUnregister();
}
});
</script>
Expand Down
5 changes: 3 additions & 2 deletions packages/layerchart/src/lib/components/GeoPoint.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,14 @@
render(ctx, { x, y });
}
let canvasUnregister: ReturnType<typeof canvasContext.register>;
$: if (renderContext === 'canvas') {
canvasContext.register(_render);
canvasUnregister = canvasContext.register({ name: 'GeoPoint', render: _render });
}
onDestroy(() => {
if (renderContext === 'canvas') {
canvasContext.deregister(_render);
canvasUnregister();
}
});
</script>
Expand Down
5 changes: 3 additions & 2 deletions packages/layerchart/src/lib/components/GeoTile.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@
});
}
let canvasUnregister: ReturnType<typeof canvasContext.register>;
$: if (renderContext === 'canvas') {
canvasContext.register(render);
canvasUnregister = canvasContext.register({ name: 'GeoTile', render });
}
$: if (renderContext === 'canvas') {
Expand All @@ -57,7 +58,7 @@
onDestroy(() => {
if (renderContext === 'canvas') {
canvasContext.deregister(render);
canvasUnregister();
}
});
</script>
Expand Down
5 changes: 3 additions & 2 deletions packages/layerchart/src/lib/components/Group.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,9 @@
ctx.translate($tweened_x ?? 0, $tweened_y ?? 0);
}
let canvasUnregister: ReturnType<typeof canvasContext.register>;
$: if (renderContext === 'canvas') {
canvasContext.register(render);
canvasUnregister = canvasContext.register({ name: 'Group', render, retainState: true });
}
$: if (renderContext === 'canvas') {
Expand All @@ -64,7 +65,7 @@
onDestroy(() => {
if (renderContext === 'canvas') {
canvasContext.deregister(render);
canvasUnregister();
}
});
</script>
Expand Down
5 changes: 3 additions & 2 deletions packages/layerchart/src/lib/components/Line.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,9 @@
});
}
let canvasUnregister: ReturnType<typeof canvasContext.register>;
$: if (renderContext === 'canvas') {
canvasContext.register(render);
canvasUnregister = canvasContext.register({ name: 'Line', render });
}
$: if (renderContext === 'canvas') {
Expand All @@ -77,7 +78,7 @@
onDestroy(() => {
if (renderContext === 'canvas') {
canvasContext.deregister(render);
canvasUnregister();
}
});
</script>
Expand Down
5 changes: 3 additions & 2 deletions packages/layerchart/src/lib/components/Points.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -169,13 +169,14 @@
}
}
let canvasUnregister: ReturnType<typeof canvasContext.register>;
$: if (renderContext === 'canvas') {
canvasContext.register(_render);
canvasUnregister = canvasContext.register({ name: 'Points', render: _render });
}
onDestroy(() => {
if (renderContext === 'canvas') {
canvasContext.deregister(_render);
canvasUnregister();
}
});
</script>
Expand Down
5 changes: 3 additions & 2 deletions packages/layerchart/src/lib/components/Rect.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,9 @@
);
}
let canvasUnregister: ReturnType<typeof canvasContext.register>;
$: if (renderContext === 'canvas') {
canvasContext.register(render);
canvasUnregister = canvasContext.register({ name: 'Rect', render });
}
$: if (renderContext === 'canvas') {
Expand All @@ -68,7 +69,7 @@
onDestroy(() => {
if (renderContext === 'canvas') {
canvasContext.deregister(render);
canvasUnregister();
}
});
</script>
Expand Down
5 changes: 3 additions & 2 deletions packages/layerchart/src/lib/components/Spline.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,9 @@
});
}
let canvasUnregister: ReturnType<typeof canvasContext.register>;
$: if (renderContext === 'canvas') {
canvasContext.register(render);
canvasUnregister = canvasContext.register({ name: 'Spline', render });
tweened_d.subscribe(() => {
canvasContext.invalidate();
Expand All @@ -180,7 +181,7 @@
onDestroy(() => {
if (renderContext === 'canvas') {
canvasContext.deregister(render);
canvasUnregister();
}
});
Expand Down
5 changes: 3 additions & 2 deletions packages/layerchart/src/lib/components/Text.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -193,8 +193,9 @@
});
}
let canvasUnregister: ReturnType<typeof canvasContext.register>;
$: if (renderContext === 'canvas') {
canvasContext.register(render);
canvasUnregister = canvasContext.register({ name: 'Text', render });
}
$: if (renderContext === 'canvas') {
Expand All @@ -205,7 +206,7 @@
onDestroy(() => {
if (renderContext === 'canvas') {
canvasContext.deregister(render);
canvasUnregister();
}
});
</script>
Expand Down
41 changes: 26 additions & 15 deletions packages/layerchart/src/lib/components/layout/Canvas.svelte
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
<script lang="ts" context="module">
import { getContext, onDestroy, setContext } from 'svelte';
type DrawFunction = (ctx: CanvasRenderingContext2D) => any;
type ComponentRender = {
name: string;
render: (ctx: CanvasRenderingContext2D) => any;
retainState?: boolean;
};
export type CanvasContext = {
register(fn: DrawFunction): void;
deregister(fn: DrawFunction): void;
/** Register component to render. Returns method to unregister on component destory */
register(component: ComponentRender): () => void;
invalidate(): void;
};
Expand Down Expand Up @@ -64,7 +68,7 @@
*/
export let center: boolean | 'x' | 'y' = false;
const drawFunctions: DrawFunction[] = [];
let components = new Map<Symbol, ComponentRender>();
let pendingInvalidation = false;
let frameId: number | undefined;
Expand Down Expand Up @@ -106,24 +110,31 @@
context.scale($scale, $scale);
}
drawFunctions.forEach((fn) => {
// TODO: `.save()` / `.restore()` breaks `Group`. Is this needed for resetting styles or other unidentified cases?
// context.save();
fn(context);
// context.restore();
components.forEach((c) => {
if (c.retainState) {
// Do not call save/restore canvas draw state (https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/save) (ex. Group ctx.translate() affecting children)
c.render(context);
} else {
context.save();
c.render(context);
context.restore();
}
});
pendingInvalidation = false;
}
const canvasContext: CanvasContext = {
register(fn) {
drawFunctions.push(fn);
this.invalidate();
},
deregister(fn) {
drawFunctions.splice(drawFunctions.indexOf(fn), 1);
register(component) {
const key = Symbol();
components.set(key, component);
this.invalidate();
// Unregister
return () => {
components.delete(key);
this.invalidate();
};
},
invalidate() {
if (pendingInvalidation) return;
Expand Down

0 comments on commit 6e91781

Please sign in to comment.