Spaces:
Runtime error
Runtime error
File size: 4,226 Bytes
70b8e47 6a839c1 66ed450 03bb246 b4efffa be26971 423b87b 32561d8 be26971 560b99e 809d458 66ed450 560b99e 423b87b aa3e783 560b99e 66ed450 a677067 66ed450 a677067 e5b9b7e 32561d8 e5b9b7e a677067 e5b9b7e a392773 66ed450 c2163fa 560b99e a677067 a392773 66ed450 560b99e c2163fa a677067 c2163fa 70b8e47 6a839c1 423b87b 5fc8a26 423b87b 6a839c1 5fc8a26 6a839c1 be26971 423b87b 5fc8a26 423b87b be26971 423b87b 03bb246 5fc8a26 03bb246 aa3e783 560b99e 66ed450 32561d8 6a839c1 be26971 423b87b 32561d8 423b87b 66ed450 32561d8 7c37442 70b8e47 6a839c1 be26971 560b99e 70b8e47 560b99e 70b8e47 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
<script lang="ts">
import { zoom } from 'd3-zoom';
import { select } from 'd3-selection';
import { onMount } from 'svelte';
import { PUBLIC_UPLOADS } from '$env/static/public';
import { currZoomTransform } from '$lib/store';
import { round } from '$lib/utils';
import { useMyPresence, useObject } from '$lib/liveblocks';
import type { PromptImgObject } from '$lib/types';
const myPresence = useMyPresence();
const promptImgStorage = useObject('promptImgStorage');
const height = 512 * 4;
const width = 512 * 4;
let canvasEl: HTMLCanvasElement;
export { canvasEl as value };
let containerEl: HTMLDivElement;
let canvasCtx: CanvasRenderingContext2D;
// keep track of images already rendered
const imagesOnCanvas = new Set();
function getpromptImgList(promptImgList: PromptImgObject[]): PromptImgObject[] {
if (promptImgList) {
const list: PromptImgObject[] = Object.values(promptImgList).sort((a, b) => a.date - b.date);
return list.filter(({ id }) => !imagesOnCanvas.has(id));
}
return [];
}
let promptImgList: PromptImgObject[] = [];
$: promptImgList = getpromptImgList($promptImgStorage?.toObject());
$: if (promptImgList) {
renderImages(promptImgList);
}
onMount(() => {
const scale = width / containerEl.clientWidth;
const translatePadding = 0.1;
const scalePadding = 1.2;
const zoomHandler = zoom()
.scaleExtent([1 / scale / scalePadding, 1])
// .extent([
// [0, 0],
// [width, height]
// ])
.translateExtent([
[-width * translatePadding, -height * translatePadding],
[width * (1 + translatePadding), height * (1 + translatePadding)]
])
.tapDistance(10)
.on('zoom', zoomed);
const selection = select(canvasEl.parentElement)
.call(zoomHandler as any)
.call(zoomHandler.scaleTo as any, 1 / scale / scalePadding)
.on('pointermove', handlePointerMove)
.on('pointerleave', handlePointerLeave);
canvasCtx = canvasEl.getContext('2d') as CanvasRenderingContext2D;
function zoomReset() {
console.log('zoom reset');
const scale = width / containerEl.clientWidth;
zoomHandler.scaleExtent([1 / scale / scalePadding, 1])
selection.call(zoomHandler.scaleTo as any, 1 / scale / scalePadding);
}
window.addEventListener('resize', zoomReset);
return () => {
window.removeEventListener('resize', zoomReset);
};
});
type ImageRendered = {
img: HTMLImageElement;
position: { x: number; y: number };
id: string;
};
function renderImages(promptImgList: PromptImgObject[]) {
Promise.all(
promptImgList.map(
({ imgURL, position, id }) =>
new Promise<ImageRendered>((resolve) => {
const img = new Image();
img.crossOrigin = 'anonymous';
img.onload = () => {
const res: ImageRendered = { img, position, id };
canvasCtx.drawImage(img, position.x, position.y, img.width, img.height);
resolve(res);
};
const url = imgURL.split('/');
img.src = `${PUBLIC_UPLOADS}/${url.slice(3).join('/')}`;
})
)
).then((images) => {
images.forEach(({ img, position, id }) => {
// keep track of images already rendered
//re draw in order
imagesOnCanvas.add(id);
canvasCtx.drawImage(img, position.x, position.y, img.width, img.height);
});
});
}
function zoomed(e: Event) {
const transform = ($currZoomTransform = e.transform);
canvasEl.style.transform = `translate(${transform.x}px, ${transform.y}px) scale(${transform.k})`;
}
// Update cursor presence to current pointer location
function handlePointerMove(event: PointerEvent) {
event.preventDefault();
const x = round($currZoomTransform.invertX(event.clientX));
const y = round($currZoomTransform.invertY(event.clientY));
myPresence.update({
cursor: {
x,
y
}
});
}
// When the pointer leaves the page, set cursor presence to null
function handlePointerLeave() {
// myPresence.update({
// cursor: null
// });
}
</script>
<div
bind:this={containerEl}
class="absolute top-0 left-0 right-0 bottom-0 overflow-hidden z-0 bg-gray-800"
>
<canvas bind:this={canvasEl} {width} {height} class="absolute top-0 left-0 bg-white" />
<slot />
</div>
<style lang="postcss" scoped>
canvas {
transform-origin: 0 0;
}
</style>
|