# 介绍

插件基于Canvas渲染图形,用法简单,极易上手。内置了较为丰富的基础图形,能够极大提升开发效率,在此基础上,你也可以十分容易的扩展新图形。

点击以重新播放。

点击以展开或折叠
<template>
  <div class="show-animation">
    <canvas class="canvas" ref="canvas" @click="animation" />
  </div>
</template>

<script>
import CRender, { GRAPHS, Graph } from '../../../es'

export default {
  name: 'ShowAnimation',
  data() {
    return {
      render: null,

      playing: false,

      fragment1Ring1: null,
      fragment1Ring2: null,
      fragment1Polyline1: null,
      fragment1Polyline2: null,

      fragment2Ring1: null,
      fragment2Ring2: null,
      fragment2Arc1: null,
      fragment2Arc2: null,
      fragment2Arc3: null,
      fragment2Arc4: null,
      fragment2Ring12: null,
      fragment2Ring22: null,

      fragment3Circle1: null,
      fragment3Circle2: null,

      fragment5Rings: [],
      fragment5Text: null,
      fragment5Polyline1: null,

      color: ['#e86830', '#e83a30', '#e8308c', '#8930e8', '#30c9e8', '#30e8bd', '#e8e230'],
    }
  },
  methods: {
    init() {
      const { $refs, animation } = this

      this.render = new CRender($refs['canvas'])

      animation()
    },
    async animation() {
      const { render, playing } = this

      if (playing) return

      this.playing = true

      render.delAllGraph()

      await this.fragment1(render)

      await this.fragment2(render)

      await this.fragment3(render)

      await this.fragment4(render)

      await this.fragment5(render)

      this.playing = false
    },
    fragment1(render) {
      const [w, h] = render.area

      const fragment1Ring1 = (this.fragment1Ring1 = new GRAPHS.Ring({
        animationCurve: 'easeInOutBack',
        shape: {
          rx: 0,
          ry: h / 2,
          r: 6,
        },
        style: {
          stroke: '#eeca54',
          lineWidth: 10,
        },
      }))

      const fragment1Ring2 = (this.fragment1Ring2 = new GRAPHS.Ring({
        animationCurve: 'easeInOutBack',
        shape: {
          rx: w,
          ry: h / 2,
          r: 6,
        },
        style: {
          stroke: '#eeca54',
          lineWidth: 10,
        },
      }))

      const fragment1Polyline1 = (this.fragment1Polyline1 = new GRAPHS.Polyline({
        animationCurve: 'easeInOutBack',
        shape: {
          points: [
            [-150, h / 2],
            [0, h / 2],
          ],
        },
        style: {
          stroke: '#eeca54',
          lineWidth: 1,
        },
      }))

      const fragment1Polyline2 = (this.fragment1Polyline2 = new GRAPHS.Polyline({
        animationCurve: 'easeInOutBack',
        shape: {
          points: [
            [w + 150, h / 2],
            [w, h / 2],
          ],
        },
        style: {
          stroke: '#eeca54',
          lineWidth: 1,
        },
      }))

      render.add([fragment1Ring1, fragment1Ring2, fragment1Polyline1, fragment1Polyline2])

      fragment1Ring1.animation('shape', { rx: w / 2 - 80 }, true)
      fragment1Ring2.animation('shape', { rx: w / 2 + 80 }, true)

      fragment1Polyline1.animation(
        'shape',
        {
          points: [
            [w / 2 - 230, h / 2],
            [w / 2 - 80, h / 2],
          ],
        },
        true
      )

      fragment1Polyline2.animation(
        'shape',
        {
          points: [
            [w / 2 + 230, h / 2],
            [w / 2 + 80, h / 2],
          ],
        },
        true
      )

      return render.launchAnimation()
    },
    fragment2(render) {
      const [w, h] = render.area

      this.fragment1Polyline1.animation(
        'shape',
        {
          points: [
            [w / 2 - 80, h / 2],
            [w / 2 - 80, h / 2],
          ],
        },
        true
      )

      this.fragment1Polyline2.animation(
        'shape',
        {
          points: [
            [w / 2 + 80, h / 2],
            [w / 2 + 80, h / 2],
          ],
        },
        true
      )

      this.fragment1Ring1.animationFrame = 60
      this.fragment1Ring1.animation('shape', { r: 20 }, true)

      this.fragment1Ring1.animation(
        'style',
        {
          opacity: 0,
          lineWidth: 0.5,
        },
        true
      )

      this.fragment1Ring2.animationFrame = 60
      this.fragment1Ring2.animation('shape', { r: 20 }, true)

      this.fragment1Ring2.animation(
        'style',
        {
          opacity: 0,
          lineWidth: 0.5,
        },
        true
      )

      const fragment2Ring1 = (this.fragment2Ring1 = new GRAPHS.Ring({
        animationCurve: 'easeOutCubic',
        animationFrame: 60,
        shape: {
          rx: w / 2 - 80,
          ry: h / 2,
          r: 6,
        },
        style: {
          stroke: '#ee66aa',
          lineWidth: 1,
        },
      }))

      const fragment2Ring2 = (this.fragment2Ring2 = new GRAPHS.Ring({
        animationCurve: 'easeOutCubic',
        animationFrame: 60,
        shape: {
          rx: w / 2 + 80,
          ry: h / 2,
          r: 6,
        },
        style: {
          stroke: '#ee66aa',
          lineWidth: 1,
        },
      }))

      render.add([fragment2Ring1, fragment2Ring2])

      fragment2Ring1.animation('shape', { r: 30 }, true)
      fragment2Ring1.animation('style', { opacity: 0 }, true)

      fragment2Ring2.animation('shape', { r: 30 }, true)
      fragment2Ring2.animation('style', { opacity: 0 }, true)

      const fragment2Arc1 = (this.fragment2Arc1 = new GRAPHS.Arc({
        animationFrame: 90,
        animationCurve: 'easeOutCubic',
        shape: {
          rx: w / 2,
          ry: h / 2,
          r: 60,
          startAngle: -Math.PI,
          endAngle: -Math.PI + 0.01,
        },
        style: {
          stroke: '#30c9e8',
          lineWidth: 2,
          rotate: 0,
        },
      }))

      const fragment2Arc2 = (this.fragment2Arc2 = new GRAPHS.Arc({
        animationFrame: 90,
        animationCurve: 'easeOutCubic',
        shape: {
          rx: w / 2,
          ry: h / 2,
          r: 60,
          startAngle: 0,
          endAngle: 0.01,
        },
        style: {
          stroke: '#30c9e8',
          lineWidth: 2,
          rotate: 0,
        },
      }))

      render.add([fragment2Arc1, fragment2Arc2])

      const fragment2Arc3 = (this.fragment2Arc3 = new GRAPHS.Arc({
        animationFrame: 90,
        animationCurve: 'easeOutCubic',
        shape: {
          rx: w / 2,
          ry: h / 2,
          r: 100,
          startAngle: -Math.PI,
          endAngle: -Math.PI + 0.01,
        },
        style: {
          stroke: '#eeca54',
          lineWidth: 2,
          lineCap: 'round',
          rotate: 0,
        },
      }))

      const fragment2Arc4 = (this.fragment2Arc4 = new GRAPHS.Arc({
        animationFrame: 90,
        animationCurve: 'easeOutCubic',
        shape: {
          rx: w / 2,
          ry: h / 2,
          r: 100,
          startAngle: 0,
          endAngle: 0.01,
        },
        style: {
          stroke: '#eeca54',
          lineWidth: 2,
          lineCap: 'round',
          rotate: 0,
        },
      }))

      render.add([fragment2Arc3, fragment2Arc4])

      fragment2Arc1.animation(
        'shape',
        {
          startAngle: -Math.PI,
          endAngle: 0,
        },
        true
      )

      fragment2Arc2.animation(
        'shape',
        {
          startAngle: 0,
          endAngle: Math.PI,
        },
        true
      )

      fragment2Arc1.animation('style', { rotate: 360 }, true)

      fragment2Arc2.animation('style', { rotate: 360 }, true)

      fragment2Arc3.animation(
        'shape',
        {
          startAngle: -Math.PI,
          endAngle: 0,
          r: 20,
        },
        true
      )

      fragment2Arc4.animation(
        'shape',
        {
          startAngle: 0,
          endAngle: Math.PI,
          r: 20,
        },
        true
      )

      fragment2Arc3.animation('style', { rotate: 360 }, true)

      fragment2Arc4.animation('style', { rotate: 360 }, true)

      return render.launchAnimation()
    },
    fragment3(render) {
      const [w, h] = render.area

      const fragment2Ring12 = (this.fragment2Ring12 = new GRAPHS.Ring({
        animationCurve: 'easeOutCubic',
        animationFrame: 60,
        shape: {
          rx: w / 2 - 60,
          ry: h / 2,
          r: 10,
        },
        style: {
          stroke: '#c71f16',
          lineWidth: 1,
        },
      }))

      const fragment2Ring22 = (this.fragment2Ring22 = new GRAPHS.Ring({
        animationCurve: 'easeOutCubic',
        animationFrame: 60,
        shape: {
          rx: w / 2 + 60,
          ry: h / 2,
          r: 10,
        },
        style: {
          stroke: '#c71f16',
          lineWidth: 1,
        },
      }))

      render.add([fragment2Ring12, fragment2Ring22])

      fragment2Ring12.animation('shape', { r: 40 }, true)
      fragment2Ring22.animation('shape', { r: 40 }, true)

      fragment2Ring12.animation('style', { opacity: 0 }, true)
      fragment2Ring22.animation('style', { opacity: 0 }, true)

      this.fragment2Arc1.animation('shape', { r: 100 }, true)
      this.fragment2Arc2.animation('shape', { r: 100 }, true)

      this.fragment2Arc3.animation('shape', { r: 10 }, true)
      this.fragment2Arc4.animation('shape', { r: 10 }, true)

      this.fragment2Arc1.animation('style', { opacity: 0 }, true)
      this.fragment2Arc2.animation('style', { opacity: 0 }, true)

      this.fragment2Arc3.animation('style', { opacity: 0 }, true)
      this.fragment2Arc4.animation('style', { opacity: 0 }, true)

      const fragment3Circle1 = (this.fragment3Circle1 = new GRAPHS.Circle({
        animationFrame: 90,
        animationCurve: 'easeInOutBack',
        shape: {
          rx: 0,
          ry: 0,
          r: 10,
        },
        style: {
          fill: '#e9c752',
          graphCenter: [w / 2, h / 2],
          rotate: 30,
        },
        setGraphCenter() {},
      }))

      const fragment3Circle2 = (this.fragment3Circle2 = new GRAPHS.Circle({
        animationFrame: 90,
        animationCurve: 'easeInOutBack',
        shape: {
          rx: w,
          ry: h,
          r: 10,
        },
        style: {
          fill: '#e9c752',
          graphCenter: [w / 2, h / 2],
          rotate: -30,
        },
        setGraphCenter() {},
      }))

      render.add([fragment3Circle1, fragment3Circle2])

      fragment3Circle1.animation('shape', { rx: w / 2, ry: h / 2 }, true)
      fragment3Circle2.animation('shape', { rx: w / 2, ry: h / 2 }, true)

      fragment3Circle1.animation('style', { rotate: 360 }, true)
      fragment3Circle2.animation('style', { rotate: 360 }, true)

      return render.launchAnimation()
    },
    fragment4(render) {
      const [w, h] = render.area

      const randomXArea = [w / 2 - 80, w / 2 + 80]
      const randomYArea = [h / 2 - 80, h / 2 + 80]

      this.fragment3Circle1.attr('style', {
        fill: 'rgba(0, 0, 0, 0)',
        stroke: '#e9c752',
      })

      this.fragment3Circle2.attr('style', {
        fill: 'rgba(0, 0, 0, 0)',
        stroke: '#e9c752',
      })

      this.fragment3Circle1.animation('shape', { r: 50 }, true)
      this.fragment3Circle2.animation('shape', { r: 1 }, true)

      this.fragment3Circle1.animation('style', { opacity: 0 }, true)
      this.fragment3Circle2.animation('style', { opacity: 0 }, true)

      return render.launchAnimation()
    },
    fragment5(render) {
      const { randomNum, color } = this

      const [w, h] = render.area

      const randomXArea = [w / 2 - 80, w / 2 + 80]
      const randomYArea = [h / 2 - 100, h / 2 + 100]

      const fragment5Rings = (this.fragment5Rings = new Array(10).fill(0).map(_ => {
        return new GRAPHS.Ring({
          animationCurve: 'easeOutCubic',
          animationFrame: 150,
          shape: {
            rx: randomNum(...randomXArea),
            ry: randomNum(...randomYArea),
            r: 1,
          },
          style: {
            stroke: color[randomNum(0, 6)],
          },
        })
      }))

      render.add(fragment5Rings)

      this.fragment5Rings.forEach(ring => {
        ring.animation('shape', { r: randomNum(40, 50) }, true)
        ring.animation('style', { opacity: 0 }, true)
      })

      const fragment5Text = (this.fragment5Text = new GRAPHS.Text({
        animationCurve: 'easeOutBack',
        shape: {
          content: 'CRender',
          position: [w / 2, h / 2],
          maxWidth: 200,
        },
        style: {
          fill: '#66d7ee',
          fontSize: 50,
          shadowBlur: 0,
          shadowColor: '#66eece',
          scale: [0.5, 0.5],
          rotate: -90,
          opacity: 0,
        },
      }))

      render.add(fragment5Text)

      fragment5Text.animation(
        'style',
        {
          opacity: 1,
          rotate: 0,
          scale: [1.4, 1.4],
          shadowBlur: 20,
        },
        true
      )

      const fragment5Polyline1 = (this.fragment1Polyline1 = new GRAPHS.Polyline({
        animationCurve: 'easeOutBack',
        shape: {
          points: [
            [w / 2, h / 2],
            [w / 2, h / 2],
          ],
        },
        style: {
          lineWidth: 7,
          stroke: '#66d7ee',
          shadowColor: '#66eece',
          shadowBlur: 20,
        },
      }))

      render.add(fragment5Polyline1)

      fragment5Polyline1.animation(
        'shape',
        {
          points: [
            [w / 2 - 200, h / 2 + 40],
            [w / 2 + 200, h / 2 + 40],
          ],
        },
        true
      )

      return render.launchAnimation()
    },
    randomNum(minNum, maxNum) {
      switch (arguments.length) {
        case 1:
          return parseInt(Math.random() * minNum + 1, 10)
          break
        case 2:
          return parseInt(Math.random() * (maxNum - minNum + 1) + minNum, 10)
          break
      }
    },
  },
  mounted() {
    this.init()
  },
}
</script>

<style lang="less">
.show-animation {
  height: 300px;
  box-shadow: 0 0 3px #46bd87;

  .canvas {
    width: 100%;
    height: 100%;
    cursor: pointer;
  }
}
</style>

# 特点

  • 动效

基于transition插件提供了动效支持,调用图形实例的animation方法去更改其状态,CRender将自动渲染图形状态过渡动画,动画——轻而易举

Transition

  • 交互

内置的基础图形都提供了dragonMouseEnteronMouseOuteronClick等功能及事件的支持

# 安装

  • npm 安装
npm install @jiaminghi/c-render
  • yarn 安装
yarn add @jiaminghi/c-render

# UMD 版

UMD版可直接使用 script 标签引入,UMD 版文件下载请移步 UMD

点击以展示/隐藏UMD版使用示例
<!DOCTYPE html>
<html>
  <head>
    <title>CRender</title>
    <!--调试版-->
    <script src="https://unpkg.com/@jiaminghi/c-render/dist/index.js"></script>
    <!--压缩版 生产版本-->
    <!-- <script src="https://unpkg.com/@jiaminghi/c-render/dist/index.min.js"></script> -->
    <style>
      html,
      body,
      canvas {
        width: 100%;
        height: 100%;
        margin: 0px;
        padding: 0px;
      }
    </style>
  </head>
  <body>
    <canvas></canvas>

    <script>
      const { CRender, GRAPHS } = window.CRender

      const canvas = document.querySelector('canvas')
      const render = new CRender(canvas)
      const [w, h] = render.area

      const graph = new GRAPHS.Text({
        animationCurve: 'easeOutBounce',
        shape: {
          content: 'Welcome to CRender',
          position: [w / 2, h / 2],
        },
        style: {
          fontSize: 80,
          fill: '#34e4ab',
          opacity: 0,
        },
      })

      render.add(graph)

      graph.animation('style', {
        opacity: 1,
        fontSize: 120,
      })
    </script>
  </body>
</html>

# 扩展

要为CRender扩展新的图形请参阅扩展