【项目技术点总结之一】vue集成d3.js利用svg加载图片实现缩放拖拽功能

前言

概述

最近项目开发过程中,前端需要有一个图片预览的组件,支持图片放大、缩小、拖拽等地图的基本功能,并且需要考虑后期扩展,可以在预览过程中添加标注。最初觉得这得用操作地图的插件才可以搞定,但仅仅是图片预览,没必要这样处理,于是就选用的d3.js来实现这一功能,发现完全满足所有的需求。
项目用的前端还是vue+elementui全家桶的模式,发现elementui本身就有一个图片预览的组件,个人觉得不是特别好用,有感兴趣的人可以去看看。
vue项目图片预览组件:

  • 基于element-ui中自带的一个组件(el-image-viewer)
  • vue图片预览组件(viewerjs )

技术介绍

很多人对d3.js的印象是一个前端的可视化库,与hightchart、echarts等差不多是一样,但是随着使用的进一步深入,就会发现d3的功能不仅于此。前面那chart类库局限的地方在于基本不可定制,即不同的图表必须严格按照文档来;而D3呢,你说了算,你想画出什么样的图,你说了算,自由度很大;当然最终还是需要根据项目需求选择。
回归正题,D3.js堪称SVG中的jQuery,你如果想用D3输出Canvas图也可以,但SVG图操作起来更加灵活,更加方便调试,基于这个思路,就萌生出使用d3.js操作svg,加载图片显示,实现其它组件不具备的能力。

实现过程

插件安装

npm install d3 --save-dev

需要注意的是,默认安装的应该是最新版本,其中有很多函数的调用逻辑会有变化,尤其是大版本不同的时候,本人就遇到因为版本问题很多函数不起作用的问题,所以最好注意安装后版本。
本人使用的5.5.0版本,不同版本说明d3.js版本说明,安装方法:

npm install d3@5.5.0 --save-dev

引用组件

  • 在组件(单vue文件)中引用
import * as d3 from "d3";

之后就可以在方法中直接使用。
2.注册到全局变量,在main.js中引入

import * as d3 from "d3";
Vue.prototype.$d3 = d3;
window.d3 = d3;   //暂时设置为全局变量

初始化组件

import * as d3 from "d3";
export default {
  name: "ViewImage",
  data() {
    return {
      zoom_:null,
      svg_:null,
      container:null,
      svg_width:500,
      svg_height:500
    };
  },
  mounted() {
      this.hwInit();
      this.svgInit();
  },
  created() {
  },
  methods: {
    /** 动态获取svg面板的宽高*/
    hwInit:function(){
        this.svg_width = window.innerWidth-260;
        this.svg_height = window.innerHeight -120;
    },
    /** 初始化svg面板*/
    svgInit: function () {
      this.zoom_ = d3.zoom().scaleExtent([0.5, 3]).on("zoom", this.zoomed);
      this.svg_ = d3
        .select("#img_content")
        .append("svg")
        .attr("width", this.svg_width)
        .attr("height", this.svg_height)
        .call(this.zoom_);
      this.container = this.svg_.append("g").attr("fill","#ffffff");
    },
    /** 定义缩放的方法*/
    zoomed: function (e) {
      this.container.attr(
        "transform",
        "translate(" +
          d3.event.transform.x +
          "," +
          d3.event.transform.y +
          ")scale(" +
          d3.event.transform.k +
          ")"
      );
    },
    /** 在svg上绘制图片*/
    drawImg:function(bg_img){
        this.container
            .attr("class", "all")
            .append("image")
            .attr("xlink:href", bg_img)
            .attr("x", "0")
            .attr("y", "0")
            .attr("width",this.svg_width)
            .attr("height",this.svg_height);
    },
  },
};

至此,在页面中即可对应实现不同的业务了。

实现效果

效果图
底图是一张png的图片,通过d3+svg加载之后,获取对应点的坐标生成数据,既可以实现相应的效果,顺便说一句,d3操作svg有很多方法,需要慢慢摸索,所以最好了解svg本身有的属性会事半功倍。

简单理解

基于从网上查询的资料结合开发中的思考,简单记录一下个人理解:

  • 使用svg加载图片,是因为svg会给图片建立一个坐标空间,所有绘制的图形都是基于这个坐标空间来处理。
  • 为什么要使用d3.js呢?svg虽然有坐标空间,不支持缩放拖拽等功能,且d3能在代码中操作svg,从而可以实现编程式的开发。
    有了以上两点,其实就不难看出为什么会这样去组合使用了,目前也在论证是否使用别的js库能达到同样的效果,以下就分别讲解下d3操作svg的一些思路:

使用d3创建一个svg

var svgContainer = d3.select("body").append("svg")
                                .attr("width",200)
   		                     .attr("width",200)
   		                     .style("border","1px solid black");

以上代码就是创建了一个200*200的svg面板。

在svg中提添加元素

暂且较原生添加svg元素:

<svg width="50" height="50">
  <circle cx="25" cy="25" r="25" fill="purple" />
</svg>

使用d3.js添加svg元素:

var circleSelection = svgSelection.append("circle")
                                  .attr("cx",25)
                                  .attr("cy",25)
                                  .attr("r",25)
                                  .style("fill","purple");

实现了同样的效果,其中,.attr(“cx”,25)和.attr(“cy”,25)让我们可以设置SVG圆形的属性。

函数使用

D3.js允许我们在.style()操作符和.attr()内部使用函数,比如:

var circleAttributes = circles
            .attr("cx",function(d){return d;})
            .attr("cy",function(d){return d;})
            .attr("r",20)
                    .style("fill",function(d){return d;});

以此,我们就可以很轻松的实现以下定制化的需求。

使用总结

当然此处只是大致分步骤梳理了下d3结合svg的用法,基于此添加上d3.js的事件、方法等即可灵活的定制开发。
d3.js中文文档【3.0】,虽然版本迭代会有很多更改,但是很多方法还是可以参考:
d3.js 3.0版本的中文翻译文档

说在最后

本文只是将自己实现的效果做了一下整理,深究之后才发现对d3.js的api以及使用还不是特别熟悉,仍然是停留在表面上,很多官方的api也是一知半解,所以后续也会在慢慢深入。

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
当使用 Vue 3 结合 D3.js实现可视化时,经常需要对 SVG 视图进行缩放操作。下面是一个基于 Vue 3 和 D3.jsSVG 视图缩放示例代码: ``` <template> <div ref="container"> <svg :width="width" :height="height" ref="svg"> <g :transform="`translate(${margin.left}, ${margin.top})`"> <circle cx="50" cy="50" r="50" fill="red"/> </g> </svg> </div> </template> <script> import * as d3 from 'd3'; import { ref, onMounted } from 'vue'; export default { setup() { const container = ref(null); const svg = ref(null); const width = 500; const height = 500; const margin = { top: 20, right: 20, bottom: 20, left: 20 }; const zoom = d3.zoom().on('zoom', zoomed); function zoomed() { const transform = d3.event.transform; d3.select(svg.value) .select('g') .attr('transform', transform); } onMounted(() => { d3.select(container.value) .call(zoom) .call(zoom.transform, d3.zoomIdentity.translate(margin.left, margin.top)); }); return { container, svg, width, height, margin, }; }, }; </script> ``` 在这个示例代码中,我们使用了 Vue 3 的 `ref` 函数来声明了一个指向容器元素和 SVG 元素的引用 `container` 和 `svg`,并且定义了 SVG 视图的大小 `width` 和 `height`,以及 SVG 视图内部的边距 `margin`。 在 `setup` 函数中,我们使用 D3.js 的 `zoom` 函数来创建一个缩放操作,并将其绑定到容器元素上。在 `zoomed` 函数中,我们使用当前缩放的变换矩阵来更新 SVG 视图中的 `g` 元素的变换属性。 最后,在 `onMounted` 钩子函数中,我们使用 D3.js 的 `select` 函数来选中容器元素,并将缩放操作应用到其中。同时,我们使用 `transform` 函数将 SVG 视图平移初始的 `margin` 边距大小。 在模板中,我们使用插值绑定 `:width` 和 `:height` 来设置 SVG 视图的大小,使用 `:transform` 绑定来设置 `g` 元素的变换属性。最后,我们在 `g` 元素中添加了一个圆形元素来测试缩放效果。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值