Appearance
指南
基本示例
初始化画布,并添加图形
点击查看代码
vue
<script setup lang="ts">
import GRender, { Rect, Line, Arrow, Circle, Ellipse, Polygon } from "grender";
import { ref, onMounted, onUnmounted } from "vue";
let grender: GRender | undefined;
const $canvas = ref();
const resize = () => {
grender.resize();
};
onMounted(() => {
grender = new GRender($canvas.value);
const x = $canvas.value.offsetWidth / 2 - 30;
const rect = new Rect({
shape: {
x,
y: 40,
width: 80,
height: 40,
},
});
const line = new Line({
shape: {
x1: x - 50,
y1: 40,
x2: x + 50,
y2: 160,
},
});
const arrow = new Arrow({
shape: {
x1: x - 30,
y1: 40,
x2: x + 10,
y2: 160,
},
});
const circle = new Circle({
shape: {
x,
y: 100,
r: 40,
},
});
const ellipse = new Ellipse({
shape: {
x: x + 60,
y: 120,
rx: 60,
ry: 30,
},
});
const polygon = new Polygon({
shape: {
points: [
[x - 130, 40],
[x - 110, 10],
[x - 80, 10],
[x - 60, 40],
[x - 80, 70],
[x - 110, 70],
],
},
});
grender.add(rect);
grender.add(line);
grender.add(arrow);
grender.add(circle);
grender.add(ellipse);
grender.add(polygon);
window.addEventListener("resize", resize);
});
onUnmounted(() => {
window.removeEventListener("resize", resize);
grender.destroy();
});
</script>
<template>
<div class="demo1" ref="$canvas"></div>
</template>
<style>
.demo1 {
height: 180px;
background-color: #fff;
}
</style>
图形样式
默认情况下,图形添加到画布中后会有默认样式,我们可以在初始化时设置图形的样式
TIP
图形在画布中的层级关系,默认是添加到画布中的顺序,后添加的层级更高,我们也可以在初始化化时指定z
值,从而调整某个图形的层级。 上图中我们手动指定了矩形的层级为1
,所以它会被绘制到最上层。图形默认z
值为0
点击查看代码
vue
<script setup lang="ts">
import GRender, { Rect, Circle, Ellipse } from "grender";
import { ref, onMounted, onUnmounted } from "vue";
let grender: GRender | undefined;
const $canvas = ref();
const resize = () => {
grender.resize();
};
onMounted(() => {
grender = new GRender($canvas.value);
const x = $canvas.value.offsetWidth / 2 - 30;
const rect = new Rect({
brush: {
fillStyle: "green",
strokeStyle: "green",
globalAlpha: 0.9,
},
shape: {
x,
y: 40,
width: 80,
height: 40,
},
z: 1,
});
const circle = new Circle({
brush: {
lineWidth: 4,
strokeStyle: "blue",
},
shape: {
x,
y: 100,
r: 40,
},
});
const ellipse = new Ellipse({
brush: {
lineWidth: 0,
fillStyle: "red",
globalAlpha: 0.9,
},
shape: {
x: x + 60,
y: 120,
rx: 60,
ry: 30,
},
});
grender.add(rect);
grender.add(circle);
grender.add(ellipse);
window.addEventListener("resize", resize);
});
onUnmounted(() => {
window.removeEventListener("resize", resize);
grender.destroy();
});
</script>
<template>
<div class="demo2" ref="$canvas"></div>
</template>
<style>
.demo2 {
height: 180px;
background-color: #fff;
}
</style>
图形变换
图形目前支持translate(移动)
,scale(缩放)
和rotate(旋转)
三种变换
矩形变换
椭圆变换
TIP
图形变换(rotate、scale)的中心点默认为图形为所在局部坐标的原点(0,0)
,我们也可以通过origin
参数指定变换中心
点击查看代码
vue
<script setup lang="ts">
import GRender, { Rect, Ellipse } from "grender";
import { ref, onMounted, onUnmounted } from "vue";
let grender1: GRender | undefined;
let grender2: GRender | undefined;
const $rect = ref();
const $ellipse = ref();
let rect;
let ellipse;
const resize = () => {
grender1.resize();
grender2.resize();
};
const translateX = (shape) => {
const [x, y] = shape.T;
shape.translate(x + 10, y);
};
const translateY = (shape) => {
const [x, y] = shape.T;
shape.translate(x, y + 10);
};
const rotate = (shape) => {
const r = shape.R;
shape.rotate(r + 30);
};
const scale = (shape, val) => {
const [x, y] = shape.S;
shape.scale(x * val, y * val);
};
onMounted(() => {
grender1 = new GRender($rect.value);
rect = new Rect({
origin: [40, 20],
brush: {
fillStyle: "red",
strokeStyle: "red",
},
shape: {
x: 0,
y: 0,
width: 80,
height: 40,
},
});
grender1.add(rect);
grender2 = new GRender($ellipse.value);
ellipse = new Ellipse({
origin: [100, 100],
brush: {
fillStyle: "red",
strokeStyle: "red",
},
shape: {
x: 100,
y: 100,
rx: 60,
ry: 30,
},
});
grender2.add(ellipse);
window.addEventListener("resize", resize);
});
onUnmounted(() => {
window.removeEventListener("resize", resize);
grender1.destroy();
grender2.destroy();
});
</script>
<template>
<div class="demo3">
<h5>矩形变换</h5>
<div class="demo3-btns">
<button @click="translateX(rect)">x + 10</button>
<button @click="translateY(rect)">y + 10</button>
<button @click="rotate(rect)">旋转30°</button>
<button @click="scale(rect, 1.2)">放大1.2倍</button>
<button @click="scale(rect, 1 / 1.2)">缩小1.2倍</button>
</div>
<div class="demo3-canvas" ref="$rect"></div>
<h5>椭圆变换</h5>
<div class="demo3-btns">
<button @click="translateX(ellipse)">x + 10</button>
<button @click="translateY(ellipse)">y + 10</button>
<button @click="rotate(ellipse)">旋转30°</button>
<button @click="scale(ellipse, 1.2)">放大1.2倍</button>
<button @click="scale(ellipse, 1 / 1.2)">缩小1.2倍</button>
</div>
<div class="demo3-canvas" ref="$ellipse"></div>
</div>
</template>
<style>
.demo3-btns {
margin: 10px 0;
}
.demo3 button {
background-color: #08f;
color: #fff;
padding: 2px 8px;
border-radius: 4px;
}
.demo3 button:not(:last-child) {
margin-right: 8px;
}
.demo3-canvas {
height: 300px;
background-color: #fff;
}
</style>
鼠标事件
图形目前支持click
、dblclick
、wheel
、mousedown
、mousemove
、mouseup
、mouseover
、mouseout
、mouseenter
和与mouseleave
事件。同时也支持dragstart
、dragging
和dragend
等复合事件
当前触发事件:
点击查看代码
vue
<script setup lang="ts">
import GRender, { Rect, Line, Arrow, Circle, Ellipse, Polygon } from "grender";
import { ref, onMounted, onUnmounted } from "vue";
let grender: GRender | undefined;
const $canvas = ref();
const event = ref();
const resize = () => {
grender.resize();
};
onMounted(() => {
grender = new GRender($canvas.value);
const x = $canvas.value.offsetWidth / 2 - 30;
const rect = new Rect({
shape: {
x,
y: 40,
width: 80,
height: 40,
},
});
const line = new Line({
brush: {
lineWidth: 2,
},
shape: {
x1: x - 50,
y1: 40,
x2: x + 50,
y2: 160,
},
});
const arrow = new Arrow({
brush: {
lineWidth: 10,
},
shape: {
x1: x - 30,
y1: 40,
x2: x - 40,
y2: 160,
},
});
const circle = new Circle({
shape: {
x,
y: 100,
r: 40,
},
});
const ellipse = new Ellipse({
shape: {
x: x + 60,
y: 120,
rx: 60,
ry: 30,
},
});
const polygon = new Polygon({
shape: {
points: [
[x - 130, 40],
[x - 110, 10],
[x - 80, 10],
[x - 60, 40],
[x - 80, 70],
[x - 110, 70],
],
},
});
grender.add(rect);
grender.add(line);
grender.add(arrow);
grender.add(circle);
grender.add(ellipse);
grender.add(polygon);
grender.shapes.forEach((shape) => {
shape.on("dragging", (e) => {
shape.translate(e.x, e.y);
event.value = "dragging";
});
shape.on("mouseenter", (e) => {
shape.brush.fillStyle = "red";
shape.brush.strokeStyle = "blue";
event.value = "mouseenter";
$canvas.value.style.cursor = "pointer";
grender.refresh();
});
shape.on("mouseleave", (e) => {
shape.brush.fillStyle = "rgba(0,0,0,0)";
shape.brush.strokeStyle = "#000";
event.value = "mouseleave";
$canvas.value.style.cursor = "default";
grender.refresh();
});
});
window.addEventListener("resize", resize);
});
onUnmounted(() => {
window.removeEventListener("resize", resize);
grender.destroy();
});
</script>
<template>
<div class="demo4">
<div>当前触发事件:{{ event }}</div>
<div class="demo4-canvas" ref="$canvas"></div>
</div>
</template>
<style>
.demo4 {
border: 2px solid #000;
}
.demo4-canvas {
height: 240px;
background-color: #fff;
}
</style>