前言
要做动态渲染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 //层的横轴