Skip to content

Commit

Permalink
fix some bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
rejth committed May 21, 2024
1 parent fe6f8fe commit 5c0eca2
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 63 deletions.
39 changes: 37 additions & 2 deletions src/App.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,42 @@
<script lang="ts">
import { ColorDropper } from './ui';
import { onMount } from 'svelte';
import { ColorDropper, Layer, Spinner } from './ui';
let imageSource: CanvasImageSource | null = null;
onMount(async () => {
const image = new Image();
image.src = 'images/sea.jpg';
image.onload = async () => {
const imageBitmap = await createImageBitmap(image);
imageSource = imageBitmap;
};
});
</script>

<main>
<ColorDropper />
{#if !imageSource}
<div class="spinner">
<Spinner />
</div>
{:else}
<ColorDropper useWorker={false}>
<Layer
render={({ ctx, width, height }) => {
if (!imageSource) return;
ctx.drawImage(imageSource, 0, 0, width, height);
}}
/>
</ColorDropper>
{/if}
</main>

<style>
.spinner {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
</style>
1 change: 1 addition & 0 deletions src/custom.d.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
declare module 'json-fn';
declare module 'json-fns';
14 changes: 9 additions & 5 deletions src/model/RenderWorker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ export class RenderWorker {
this.worker = new Worker();
this.geometryManager = geometryManager;

this.drawers.subscribe((value) => {
this.update(value);
this.drawers.subscribe(() => {
this.update();
});
}

Expand Down Expand Up @@ -58,20 +58,24 @@ export class RenderWorker {
};
}

stringifyDrawers() {
return JSONfn.stringify(Array.from(get(this.drawers)))
}

resize() {
this.worker.postMessage({
action: WorkerActionEnum.RESIZE,
drawers: JSONfn.stringify(Array.from(get(this.drawers))),
drawers: this.stringifyDrawers(),
width: this.width,
height: this.height,
pixelRatio: this.pixelRatio,
});
}

update(drawers: Map<LayerId, Render>) {
update() {
this.worker.postMessage({
action: WorkerActionEnum.UPDATE,
drawers: JSONfn.stringify(Array.from(drawers)),
drawers: this.stringifyDrawers(),
width: this.width,
height: this.height,
pixelRatio: this.pixelRatio,
Expand Down
27 changes: 15 additions & 12 deletions src/model/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,14 @@ let needsRedraw = true;

const settings: CanvasRenderingContext2DSettings = {
willReadFrequently: true,
alpha: false,
};

const startRenderLoop = () => {
function startRenderLoop() {
render();
frame = requestAnimationFrame(() => startRenderLoop());
};
}

const render = () => {
function render() {
if (!context) return;

width = width!;
Expand All @@ -39,39 +38,43 @@ const render = () => {
drawers.forEach((draw) => {
draw({ ctx: context!, width: width!, height: height! });
});
};
}

function parseDrawers(drawers: string): Map<LayerId, Render> {
return new Map(JSONfn.parse(drawers));
}

self.onmessage = function (e: MessageEvent<WorkerEvent>) {
const { action } = e.data;

switch (action) {
case WorkerActionEnum.INIT:
offscreenCanvas = e.data.canvas;
drawers = new Map(JSONfn.parse(e.data.drawers));
drawers = parseDrawers(e.data.drawers);
width = e.data.width;
height = e.data.height;
pixelRatio = e.data.pixelRatio;

context = offscreenCanvas!.getContext('2d', settings);
context = offscreenCanvas.getContext('2d', settings);
startRenderLoop();

break;
case WorkerActionEnum.RESIZE:
if (!e.data.width || !e.data.height) break;

drawers = new Map(JSONfn.parse(e.data.drawers));
drawers = parseDrawers(e.data.drawers);
width = e.data.width;
height = e.data.height;
pixelRatio = e.data.pixelRatio;

if (offscreenCanvas) {
offscreenCanvas.width = width!;
offscreenCanvas.height = height!;
offscreenCanvas.width = width * pixelRatio;
offscreenCanvas.height = height * pixelRatio;
}

needsRedraw = true;
break;
case WorkerActionEnum.UPDATE:
drawers = new Map(JSONfn.parse(e.data.drawers));
drawers = parseDrawers(e.data.drawers);
break;
case WorkerActionEnum.GET_COLOR:
self.postMessage({
Expand Down
72 changes: 28 additions & 44 deletions src/ui/ColorDropper.svelte
Original file line number Diff line number Diff line change
@@ -1,36 +1,33 @@
<script lang="ts">
import { onMount, setContext } from 'svelte';
import { setContext } from 'svelte';
import Canvas from './Canvas.svelte';
import Layer from './Layer.svelte';
import ColorPicker from './ColorPicker.svelte';
import ColorCircle from './ColorCircle.svelte';
import Spinner from './Spinner.svelte';
import { RenderManager, RenderWorker, type AppContext, GeometryManager } from '../model';
import { KEY } from '../lib';
const renderManager = new RenderManager(new GeometryManager());
const { selectedColor } = renderManager;
export let width: number | null = null;
export let height: number | null = null;
export let pixelRatio: 'auto' | number | null = null;
export let contextSettings: CanvasRenderingContext2DSettings | undefined = undefined;
export let style = '';
export let useWorker = false;
const geometryManager = new GeometryManager();
const renderManager = useWorker
? new RenderWorker(geometryManager)
: new RenderManager(geometryManager);
setContext<AppContext>(KEY, {
renderManager,
});
let imageSource: CanvasImageSource | null = null;
const { selectedColor } = renderManager;
let isEntered = false;
let needsPickColor = false;
onMount(async () => {
const image = new Image();
image.src = 'images/texture.jpg';
image.onload = async () => {
const imageBitmap = await createImageBitmap(image);
imageSource = imageBitmap;
};
});
const onEnter = () => {
isEntered = true;
};
Expand All @@ -53,27 +50,21 @@
</span>
<strong class="selected-color">{$selectedColor}</strong>
</div>
{#if !imageSource}
<div class="spinner">
<Spinner />
</div>
{:else}
<ColorCircle isActive={isEntered && needsPickColor} />
<Canvas
isActive={needsPickColor}
on:mouseenter={onEnter}
on:mouseleave={onLeave}
on:pointerenter={onEnter}
on:pointerleave={onLeave}
>
<Layer
render={({ ctx, width, height }) => {
if (!imageSource) return;
ctx.drawImage(imageSource, 0, 0, width, height);
}}
/>
</Canvas>
{/if}
<ColorCircle isActive={isEntered && needsPickColor} />
<Canvas
{style}
{width}
{height}
{pixelRatio}
{contextSettings}
isActive={needsPickColor}
on:mouseenter={onEnter}
on:mouseleave={onLeave}
on:pointerenter={onEnter}
on:pointerleave={onLeave}
>
<slot />
</Canvas>
</div>

<style>
Expand All @@ -82,13 +73,6 @@
height: calc(100vh - 2em);
}
.spinner {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
.toolbar {
display: flex;
flex-direction: row;
Expand Down
2 changes: 2 additions & 0 deletions src/ui/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import ColorDropper from './ColorDropper.svelte';
import Layer from './Layer.svelte';
import Spinner from './Spinner.svelte';

export { ColorDropper };
export { Layer };
export { Spinner }

0 comments on commit 5c0eca2

Please sign in to comment.