Skip to content

指南

基本示例

初始化画布,并添加图形

点击查看代码
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>

鼠标事件

图形目前支持clickdblclickwheelmousedownmousemovemouseupmouseovermouseoutmouseenter和与mouseleave事件。同时也支持dragstartdraggingdragend等复合事件

当前触发事件:
点击查看代码
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>