How to access native 2d context
How to access the native 2D canvas context from Konva
Konva gives you an object model for drawing shapes on a canvas. An application starts with a Stage in a div. The Stage contains one or more Layers. Each Layer uses Canvas elements.
You can access the internal Canvas context and draw without Konva shapes. This method is not safe. Konva controls Layer drawing, so it can erase the manual drawing. Exports such as stage.toDataURL() can also omit it.
Use one of these methods for manual drawing:
- Use a custom shape.
- Create a Canvas element and use it as the source of a
Konva.Image.
Both methods keep the drawing in Konva's scene graph and export process.
- Vanilla
- React
- Vue
import Konva from 'konva';
const width = window.innerWidth;
const height = window.innerHeight;
const stage = new Konva.Stage({
container: 'container',
width: width,
height: height,
});
const layer = new Konva.Layer();
stage.add(layer);
// if you want to make something with native 2d canvas
// we can create it and use it for Konva.Image
const canvas = document.createElement('canvas');
canvas.width = 200;
canvas.height = 150;
const ctx = canvas.getContext('2d');
const image = new Konva.Image({
x: 50,
y: 50,
image: canvas,
draggable: true,
});
layer.add(image);
// make manual drawings
ctx.fillStyle = 'blue';
ctx.fillRect(5, 5, canvas.width - 10, canvas.height / 2);
ctx.fillStyle = 'red';
ctx.beginPath();
ctx.arc(100, 75, 50, 0, 2 * Math.PI);
ctx.fill();
// such as canvas is updated we need to redraw the layer
layer.batchDraw();
import { Stage, Layer, Image } from 'react-konva';
import { useMemo, useState } from 'react';
const App = () => {
const [position, setPosition] = useState({ x: 50, y: 50 });
const canvas = useMemo(() => {
const canvas = document.createElement('canvas');
canvas.width = 200;
canvas.height = 150;
const ctx = canvas.getContext('2d');
// make manual drawings
ctx.fillStyle = 'blue';
ctx.fillRect(5, 5, canvas.width - 10, canvas.height / 2);
ctx.fillStyle = 'red';
ctx.beginPath();
ctx.arc(100, 75, 50, 0, 2 * Math.PI);
ctx.fill();
return canvas;
}, []);
return (
<Stage width={window.innerWidth} height={window.innerHeight}>
<Layer>
<Image
x={position.x}
y={position.y}
image={canvas}
draggable
onDragEnd={(e) => {
setPosition({
x: e.target.x(),
y: e.target.y(),
});
}}
/>
</Layer>
</Stage>
);
};
export default App;
<template>
<v-stage :config="stageSize">
<v-layer>
<v-image
:config="{
x: position.x,
y: position.y,
image: canvas,
draggable: true,
}"
@dragend="handleDragEnd"
/>
</v-layer>
</v-stage>
</template>
<script setup>
import { ref, onMounted } from 'vue';
const stageSize = {
width: window.innerWidth,
height: window.innerHeight
};
const position = ref({ x: 50, y: 50 });
const canvas = ref(null);
onMounted(() => {
const canvasEl = document.createElement('canvas');
canvasEl.width = 200;
canvasEl.height = 150;
const ctx = canvasEl.getContext('2d');
// make manual drawings
ctx.fillStyle = 'blue';
ctx.fillRect(5, 5, canvasEl.width - 10, canvasEl.height / 2);
ctx.fillStyle = 'red';
ctx.beginPath();
ctx.arc(100, 75, 50, 0, 2 * Math.PI);
ctx.fill();
canvas.value = canvasEl;
});
const handleDragEnd = (e) => {
position.value = {
x: e.target.x(),
y: e.target.y(),
};
};
</script>