Shape Tooltips
HTML5 Canvas Shape Tooltips with Konva
This demo shows how to create tooltips that follow the mouse cursor when hovering over shapes. It demonstrates:
- Creating custom shapes using the sceneFunc
- Handling mouse events (mousemove, mouseout)
- Using multiple layers for better organization
- Creating dynamic tooltips that follow the cursor
- Vanilla
- React
- Vue
import Konva from 'konva'; const stage = new Konva.Stage({ container: 'container', width: window.innerWidth, height: window.innerHeight, }); const shapesLayer = new Konva.Layer(); const tooltipLayer = new Konva.Layer(); // Create custom triangle shape const triangle = new Konva.Shape({ stroke: 'black', fill: '#00D2FF', strokeWidth: 1, sceneFunc: function (context) { context.beginPath(); context.moveTo(120, 50); context.lineTo(250, 80); context.lineTo(150, 170); context.closePath(); context.fillStrokeShape(this); }, }); // Create circle const circle = new Konva.Circle({ x: 250, y: stage.height() / 2, fill: 'red', stroke: 'black', strokeWidth: 4, radius: 70, }); // Create tooltip const tooltip = new Konva.Text({ text: '', fontFamily: 'Calibri', fontSize: 12, padding: 5, textFill: 'white', fill: 'black', alpha: 0.75, visible: false, }); // Add event listeners for triangle triangle.on('mousemove', () => { const mousePos = stage.getPointerPosition(); tooltip.position({ x: mousePos.x + 5, y: mousePos.y + 5, }); tooltip.text('Cyan Triangle'); tooltip.show(); }); triangle.on('mouseout', () => { tooltip.hide(); }); // Add event listeners for circle circle.on('mousemove', () => { const mousePos = stage.getPointerPosition(); tooltip.position({ x: mousePos.x + 5, y: mousePos.y + 5, }); tooltip.text('Red Circle'); tooltip.show(); }); circle.on('mouseout', () => { tooltip.hide(); }); // Add shapes and tooltip to layers shapesLayer.add(triangle); shapesLayer.add(circle); tooltipLayer.add(tooltip); // Add layers to stage stage.add(shapesLayer); stage.add(tooltipLayer);
import React from 'react'; import { Stage, Layer, Shape, Circle, Text } from 'react-konva'; const CustomShape = ({ onMouseMove, onMouseOut }) => { return ( <Shape stroke="black" fill="#00D2FF" strokeWidth={1} sceneFunc={(context, shape) => { context.beginPath(); context.moveTo(120, 50); context.lineTo(250, 80); context.lineTo(150, 170); context.closePath(); context.fillStrokeShape(shape); }} onMouseMove={onMouseMove} onMouseOut={onMouseOut} /> ); }; const App = () => { const [tooltipPos, setTooltipPos] = React.useState({ x: 0, y: 0 }); const [tooltipText, setTooltipText] = React.useState(''); const [isTooltipVisible, setTooltipVisible] = React.useState(false); const handleMouseMove = (e, text) => { const stage = e.target.getStage(); const pos = stage.getPointerPosition(); setTooltipPos({ x: pos.x + 5, y: pos.y + 5, }); setTooltipText(text); setTooltipVisible(true); }; const handleMouseOut = () => { setTooltipVisible(false); }; return ( <Stage width={window.innerWidth} height={window.innerHeight}> <Layer> <CustomShape onMouseMove={(e) => handleMouseMove(e, 'Cyan Triangle')} onMouseOut={handleMouseOut} /> <Circle x={250} y={window.innerHeight / 2} radius={70} fill="red" stroke="black" strokeWidth={4} onMouseMove={(e) => handleMouseMove(e, 'Red Circle')} onMouseOut={handleMouseOut} /> </Layer> <Layer> <Text x={tooltipPos.x} y={tooltipPos.y} text={tooltipText} fontFamily="Calibri" fontSize={12} padding={5} textFill="white" fill="black" alpha={0.75} visible={isTooltipVisible} /> </Layer> </Stage> ); }; export default App;
<template> <v-stage :config="stageConfig"> <v-layer> <v-shape :config="{ stroke: 'black', fill: '#00D2FF', strokeWidth: 1, sceneFunc: drawTriangle, }" @mousemove="(e) => handleMouseMove(e, 'Cyan Triangle')" @mouseout="handleMouseOut" /> <v-circle :config="{ x: 250, y: stageConfig.height / 2, radius: 70, fill: 'red', stroke: 'black', strokeWidth: 4, }" @mousemove="(e) => handleMouseMove(e, 'Red Circle')" @mouseout="handleMouseOut" /> </v-layer> <v-layer> <v-text :config="{ ...tooltipConfig, visible: isTooltipVisible, }" /> </v-layer> </v-stage> </template> <script setup> import { ref, computed } from 'vue'; const stageConfig = { width: window.innerWidth, height: window.innerHeight, }; const tooltipPos = ref({ x: 0, y: 0 }); const tooltipText = ref(''); const isTooltipVisible = ref(false); const tooltipConfig = computed(() => ({ x: tooltipPos.value.x, y: tooltipPos.value.y, text: tooltipText.value, fontFamily: 'Calibri', fontSize: 12, padding: 5, textFill: 'white', fill: 'black', alpha: 0.75, })); const drawTriangle = (context, shape) => { context.beginPath(); context.moveTo(120, 50); context.lineTo(250, 80); context.lineTo(150, 170); context.closePath(); context.fillStrokeShape(shape); }; const handleMouseMove = (e, text) => { const stage = e.target.getStage(); const pos = stage.getPointerPosition(); tooltipPos.value = { x: pos.x + 5, y: pos.y + 5, }; tooltipText.value = text; isTooltipVisible.value = true; }; const handleMouseOut = () => { isTooltipVisible.value = false; }; </script>
Instructions: Move your mouse over the shapes to see tooltips appear. The tooltips will follow your cursor and display information about each shape.