Bootstrap

在Vue3.0里面动态创建svg(d3.js)

前言

要做动态渲染svg的效果, 在网上查了好多资料,(都没有vue3的版本), 有很多的地方都是坑, 写了也用不了, 所以我自己整合了一下。

vue3+js,没有用到ts


1. 首先定义一个svg, <svg>我是直接写死的,一个大容器嘛。

我差不多把能写的属性都写进去, 这个<defs>我看到有帖子说要加的, 但是可加可不加, 我也没有用到过。

里面 id="rectold" 这里开始我都是动态去渲染的。

<svg ref="svgcanvas" id="svgcanvas"

        height="76vh" width="90%"

        viewBox="0 0 600 1100"

        version="1.1"  x="0px" y="0px"

        xml:space="preserve" xmlns="http://www.w3.org/2000/svg"

        xmlns:xlink="http://www.w3.org/1999/xlink"

        @mousewheel.prevent="zoomimg"

      >

        <defs>

          <marker

            id="end-arrow1"

            class="end-arrow"

            fill="#008CFF"

            markerUnits="strokeWidth"

            viewBox="0 0 10 10"

            refX="9"

            refY="3.5"

            markerWidth="10"

            markerHeight="10"

            orient="auto"

          >

            <polygon points="0 0, 10 3.5, 0 7" />

          </marker>

        </defs>

        <g ref="image" transform="translate(0,0) rotate(0)" id="rectold">

          <g id="btectBord" />

          <g id="columnText" />

          <g id="lattice" />

          <g id="linetitle" />

          <g id="layertitle" />

        </g>

      </svg>

 2. 引入d3.js, 我是根据d3来实现的, 还有可以用其他的,我没去研究了。

首先下载d3依赖: npm install d3 --save-dev

然后再main.js里面定义

import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)

import * as d3 from 'd3'
app.config.globalProperties.$d3 = d3
window.d3 = d3 //暂时设置为全局变量

最后在组件里面引入进来

题外: jquery和echarts的引入是一样的方法。

<script>

import {

  defineComponent,

  getCurrentInstance,

  onMounted,

  reactive,

  ref,

  toRefs,

  onBeforeMount,

} from 'vue'

import * as d3 from 'd3'

<script>

3. 先定义数据 ,这一步平平无奇

setup() {
     const state = reactive({

                locationcolumn: 18, //列

                locationline: 10, //行

                locationlayer: 8, //层

                locationData: [], //获取数据

    })
}

4.  @mousewheel.prevent="zoomimg"放大缩小拖拽的鼠标事件, 然后不知道vue3什么原因,死活定义不了这个方法, 后面是加了prevent这个之后才可以使用的。

什么原因还不太清除, 有知道的大佬可以告诉我一下下。

setup() {

        const state = reactive({

                locationcolumn: 18, //列

                locationline: 10, //行

                locationlayer: 8, //层

                locationData: [], //获取数据

        })

        // 这个方法还没有完全搞懂, 但是有效

        const zoomimg = e => {

              // 放大缩小

              var svg = d3.select('#svgcanvas')

              svg.call(

                d3

                  .zoom()

                  .extent([

                    [0, 0],

                    [600, 1100], 

                  ])

                  .scaleExtent([0.1, 100])  // 缩小放大的区间

                  .on('zoom', zoomed)

              )

                function zoomed({ transform }) {

                        let g = d3.selectAll('g')  // 查找所有的<d>

                        let text = d3.selectAll('text')  // 查找所有的<text>

                        let rect = d3.selectAll('rect')  // 查找所有的<rect> (我用到的所有标签我都查了一遍)

                       rect.attr('transform', transform)  // 给他定义属性就可以方法缩小了

                        text.attr('transform', transform)

                }

        }

         const svgcanvas = ref(null)  // 这里需要ref一下

        return { ...toRefs(state), zoomimg, svgcanvas }  // 统一return, 没毛病

}

5. 动态创建每一列的框框<rect> , 外边框

var rectX = 280

var rectY = 0 // 变化的值

var svgRect = d3.select('#btectBord')

let Yitem = ''

svgRect

            .append('rect')

            .attr('fill', '#ccc')  // 定义颜色

            .attr('width', 756)

            .attr('height', 200)

            .attr('x', rectX)  // 变化的值在这里  横向的

            .attr('y', Yitem)  // 变化的值在这里  竖向的

            .attr('stroke', 'black')  

            .attr('stroke-width', 2)   

            .attr('rx', 8) 

            .attr('ry', 8)

6. 动态创建每一列的文字<text>

var textY = 100 // 变化的

var transform = 'rotate(0)'

var textSvg = d3.select('#columnText') // 列

      textSvg

            .append('text')

            .attr('x', 100)  // 横向的位置

            .attr('y', Ycolumn)  // 竖向的位置

            .attr('font-family', 'Arial')

            .attr('font-size', '40px')  // 字体

            .attr('transform', transform)

            .attr('id', `columnitem${i}`)   // id要是不唯一的, 可以放在列循环里面

// 重点!!!!!!!!!!

// 自定义text里面的内容

           let textnode = document.getElementById(`columnitem${i}`)

                textnode.textContent = i + '列'

7. 动态创建每一层的文字, <text>

var layerY = 320 //层的竖轴

var layerX = 240 //层的横轴

;