Skip to content

Commit d7a755d

Browse files
committed
Move getting started guide of svelte-konva v0 into own file (legacy), create svelte-konva v1 migration guide (WIP)
1 parent 5c8c1f1 commit d7a755d

File tree

2 files changed

+297
-0
lines changed

2 files changed

+297
-0
lines changed

docs/svelte-konva-v0-guide.md

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
# svelte-konva v0 getting started guide (legacy)
2+
3+
This guide covers the basics of svelte-konva v0. For the newer svelte-konva v1 supporting Svelte v5, please consult the [README](../README.md).
4+
5+
## Compatibility
6+
7+
svelte-konva v0 is compatible with Svelte v3 & 4, SvelteKit v1 and Konva v8 & 9.
8+
9+
## Install
10+
11+
```npm
12+
npm i svelte-konva@0 konva
13+
```
14+
15+
## Quick start
16+
17+
```svelte
18+
<script>
19+
import { Stage, Layer, Rect } from 'svelte-konva';
20+
</script>
21+
22+
<Stage config={{ width: 1000, height: 1000 }}>
23+
<Layer>
24+
<Rect config={{ x: 100, y: 100, width: 400, height: 200, fill: 'blue' }} />
25+
</Layer>
26+
</Stage>
27+
```
28+
29+
### Events
30+
31+
You can listen to Konva events by using the Svelte `on:event` Syntax. All [Konva events](https://konvajs.org/docs/events/Binding_Events.html) are supported.
32+
33+
```svelte
34+
<script>
35+
import { Stage, Layer, Rect } from 'svelte-konva';
36+
37+
function handleClick(e) {
38+
const konvaEvent = e.detail;
39+
window.alert(`Clicked on rectangle: ${konvaEvent.type}`);
40+
}
41+
</script>
42+
43+
<Stage config={{ width: 1000, height: 1000 }}>
44+
<Layer>
45+
<Rect
46+
config={{ x: 100, y: 100, width: 400, height: 200, fill: 'blue' }}
47+
on:pointerclick={handleClick}
48+
/>
49+
</Layer>
50+
</Stage>
51+
```
52+
53+
### Accessing the underlying Konva node
54+
55+
In various cases it is useful and required to be able to access the underlying Konva node object. In svelte-konva you can do this by binding the `handle` prop.
56+
57+
```svelte
58+
<script>
59+
import { onMount, tick } from 'svelte';
60+
import { Stage, Layer, Rect } from 'svelte-konva';
61+
62+
let rectangle;
63+
64+
onMount(async () => {
65+
// Wait for dom update so the rectangle handle becomes defined
66+
await tick();
67+
68+
const json = rectangle.toJSON();
69+
window.alert(`Rectangle as JSON: ${json}`);
70+
});
71+
</script>
72+
73+
<Stage config={{ width: 1000, height: 1000 }}>
74+
<Layer>
75+
<Rect
76+
config={{ x: 100, y: 100, width: 400, height: 200, fill: 'blue' }}
77+
bind:handle={rectangle}
78+
/>
79+
</Layer>
80+
</Stage>
81+
```
82+
83+
### Binding the config prop
84+
85+
By default svelte-konva keeps your config in sync (position, rotation, scale, etc.) with the Konva node after `dragend` and `transformend` events. If you bind the config prop any reactive blocks depending on the config will also be triggered once such changes happen. In case you don't want svelte-konva to sync those changes you can pass the `staticConfig` prop to the component.
86+
87+
```svelte
88+
<script>
89+
import { Stage, Layer, Rect } from 'svelte-konva';
90+
91+
let rectangleConfig = {
92+
x: 100,
93+
y: 100,
94+
width: 400,
95+
height: 200,
96+
fill: 'blue',
97+
draggable: true
98+
};
99+
100+
$: console.log(
101+
`Rectangle was dragged. New x: ${rectangleConfig.x}. New y: ${rectangleConfig.y}.`
102+
);
103+
</script>
104+
105+
<Stage config={{ width: 1000, height: 1000 }}>
106+
<Layer>
107+
<Rect bind:config={rectangleConfig} />
108+
</Layer>
109+
</Stage>
110+
```
111+
112+
### Usage with SvelteKit
113+
114+
Generally svelte-konva is a client-side only library. When using SvelteKit, special care needs to be taken if svelte-konva/Konva functionality is used on prerendered and server side rendered (SSR) components. Prerendering and SSR happens in a Node.js environment which causes Konva to require the [canvas](https://www.npmjs.com/package/canvas) library as Konva can also be used in Node.js environments. When you use svelte-konva in such conditions you'll likely run into the following error:
115+
116+
> Error: Cannot find module 'canvas'
117+
118+
There are multiple solutions to this problem:
119+
120+
**Installing canvas:**
121+
122+
Simplest solution is to install canvas:
123+
124+
```npm
125+
npm i canvas
126+
```
127+
128+
This will satisfy the canvas dependency of Konva and you can use svelte-konva components in prerendered and SSR SvelteKit pages. The solution is a bit messy though, as you now have installed a package you don't really need which adds unnecessary overhead. Alternatively use one of the following solutions:
129+
130+
**Dynamically import your svelte-konva stage:**
131+
132+
A better approach is to dynamically import your svelte-konva canvas on the client-side only. Suppose you have a Svelte component containing your stage with various svelte-konva components:
133+
134+
_MyCanvas.svelte_
135+
136+
```svelte
137+
<script>
138+
import { Stage, Layer, Rect } from 'svelte-konva';
139+
import OtherComponentUsingSvelteKonva from './OtherComponentUsingSvelteKonva.svelte';
140+
141+
const rectangleConfig = {
142+
/*...*/
143+
};
144+
</script>
145+
146+
<Stage config={{ width: 1000, height: 1000 }}>
147+
<Layer>
148+
<Rect bind:config={rectangleConfig} />
149+
150+
<OtherComponentUsingSvelteKonva />
151+
</Layer>
152+
</Stage>
153+
```
154+
155+
To use this component inside a SvelteKit prerendered/SSR page you can dynamically import it inside `onMount()` and render it using `<svelte:component>`:
156+
157+
_+page.svelte_
158+
159+
```svelte
160+
<script>
161+
import { onMount } from 'svelte';
162+
// typescript:
163+
// import type MyCanvasComponent from '$lib/MyCanvas.svelte';
164+
165+
let MyCanvas;
166+
// typescript:
167+
// let MyCanvas: typeof MyCanvasComponent;
168+
169+
onMount(async () => {
170+
// Dynamically import your canvas component encapsulating all svelte-konva functionality inside onMount()
171+
MyCanvas = (await import('$lib/MyCanvas.svelte')).default;
172+
});
173+
</script>
174+
175+
<div>
176+
<p>This is my fancy server side rendered (or prerendered) page.</p>
177+
178+
<!-- Use your dynamically imported svelte-konva canvas component with a svelte:component block, you can pass any component props as usual -->
179+
<svelte:component this={MyCanvas} someProp="SomeString" />
180+
</div>
181+
```
182+
183+
**Dynamically import svelte-konva using vite:**
184+
185+
The [vite-plugin-iso-import](https://www.npmjs.com/package/vite-plugin-iso-import) allows you to make client-side only imports without needing the manual approach in `onMount()` described above. Please follow the installation instructions in the [README](https://www.npmjs.com/package/vite-plugin-iso-import) then you can dynamically import your component like so:
186+
187+
_+page.svelte_
188+
189+
```svelte
190+
<script>
191+
import MyCanvasComponent from '$lib/MyCanvas.svelte?client'; // Client-side only import
192+
193+
// Set component variable to null if page is rendered in SSR, otherwise use client-side only import
194+
let MyCanvas = import.meta.env.SSR ? null : MyCanvasComponent;
195+
</script>
196+
197+
<div>
198+
<p>This is my fancy server side rendered (or prerendered) page.</p>
199+
200+
<!-- Use your dynamically imported svelte-konva canvas component with a svelte:component block, you can pass any component props as usual -->
201+
<svelte:component this={MyCanvas} someProp="SomeString" />
202+
</div>
203+
```
204+
205+
Currently vite-plugin-iso-import cannot automatically fix intellisense inside .svelte files with TypeScript. Consult the [README](https://www.npmjs.com/package/vite-plugin-iso-import) for a workaround to this problem.
206+
207+
For further examples please consult the [docs](https://konvajs.org/docs/svelte) or clone the repo and run `npm i && npm run examples`.

docs/svelte-konva-v1-migration.md

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# Migration to svelte-konva v1
2+
3+
## Event handlers
4+
5+
In Svelte v5 usage of the `on:event` syntax is deprecated. svelte-konva provides all Konva events now as callback props using the `on<konva event name>` syntax. The deprecated `on:event` syntax will no longer work for svelte-konva events:
6+
7+
```diff
8+
<Rect
9+
config={{ x: 100, y: 100, width: 400, height: 200, fill: 'blue' }}
10+
- on:pointerclick={handleClick}
11+
+ onpointerclick={handleClick}
12+
/>
13+
```
14+
15+
### Event payloads
16+
17+
Additionally the event payload data has changed. Instead of being wrapped in a `CustomEvent` under the `detail` property the whole Konva event payload is now directly accessible:
18+
19+
```diff
20+
function handleClick(e) {
21+
- const konvaEvent = e.detail;
22+
- window.alert(`Clicked on rectangle: ${konvaEvent.type}`);
23+
+ window.alert(`Clicked on rectangle: ${e.type}`);
24+
}
25+
```
26+
27+
## Accessing the underlying Konva handle
28+
29+
The way to access the corresponding Konva handle in a svelte-konva component has changed. You can no longer bind the `handle` prop to access it. Instead `handle` is now exposed directly on the component instance. To access it use `bind:this` and then access the `handle` property on the component object:
30+
31+
```diff
32+
<script>
33+
import { onMount, tick } from 'svelte';
34+
import { Stage, Layer, Rect } from 'svelte-konva';
35+
36+
let rectangle;
37+
38+
onMount(async () => {
39+
- // Wait for dom update so the rectangle handle becomes defined
40+
- await tick();
41+
-
42+
- const json = rectangle.toJSON();
43+
+ const json = rectangle.handle.toJSON();
44+
window.alert(`Rectangle as JSON: ${json}`);
45+
});
46+
</script>
47+
48+
<Stage config={{ width: 1000, height: 1000 }}>
49+
<Layer>
50+
<Rect
51+
config={{ x: 100, y: 100, width: 400, height: 200, fill: 'blue' }}
52+
- bind:handle={rectangle}
53+
+ bind:this={rectangle}
54+
/>
55+
</Layer>
56+
</Stage>
57+
```
58+
59+
Additionally, you no longer need to wait a tick before accessing `handle` as it will be immediately defined on component instantiation.
60+
61+
## Stage handle
62+
63+
The stage `handle` needs special treatment, as it only becomes defined once the canvas HTML element has been rendered to the DOM. Due to this, the `handle` property on the stage component is a function which can be called to retrieve the Konva handle. It returns `null` if the stage object has not been created yet:
64+
65+
```svelte
66+
<script>
67+
import { onMount, tick } from 'svelte';
68+
import { Stage, Layer, Rect } from 'svelte-konva';
69+
70+
let stage;
71+
72+
onMount(async () => {
73+
// Wait for dom update so the stage handle becomes defined
74+
await tick();
75+
76+
const json = stage.handle().toJSON(); // Caution: handle() can return null if the stage has not been created yet (eg. canvas HTML component has not yet been rendered)
77+
window.alert(`Stage as JSON: ${json}`);
78+
});
79+
</script>
80+
81+
<Stage config={{ width: 1000, height: 1000 }} bind:this={stage}>
82+
<Layer>
83+
<Rect config={{ x: 100, y: 100, width: 400, height: 200, fill: 'blue' }} />
84+
</Layer>
85+
</Stage>
86+
```
87+
88+
## Svelte runes-only mode
89+
90+
svelte-konva is now fully compatible with Svelte's runes-only compile mode which means it will work out of the box for runes-only projects. It will also continue to work for all projects without runes-only mode enabled.

0 commit comments

Comments
 (0)