zoom从字面上看是缩放的意思,但是d3中的zoom除了能缩放,还能平移,因为这两个操作总是不分家的

首先,整个显示区域中并不是所有的元素都要缩放和平移的,比如坐标轴、背景,这些都是不需要缩放和平移的,所以在设定zoom元素时,需要将其排除。最好的办法是使用svg的g标签对图形元素进行分组,把需要缩放的放在一个g标签里,其他的可以放在一个g标签里,也可以分开放。

在本示例代码中svgGraphContainer就是放置需要缩放的图形元素的容器,所以在添加其他元素时要使用

d3.select(svgGraphContainer).append('path')

 这里添加的是线条,如果是其他图形也按照这种方法添加到svgGraphContainer下。但是坐标轴和背景不要添加到svgGraphContainer,而要添加到svg根节点或者其他节点下。

在d3.zoom()中还要添加

.on('zoom', () => {
          this.svgGraphContainer.attr('transform', d3.event.transform) // 添加缩放功能
          this.axises.xContainer.call(this.axises.x.scale(d3.event.transform.rescaleX(this.axises.xScale))) // 设置坐标轴随zoom缩放
          this.axises.yContainer.call(this.axises.y.scale(d3.event.transform.rescaleY(this.axises.yScale)))
        })

 其中transform包含了缩放和平移两项功能,中键滚轮缩放,左键拖拽平移。以前的版本中,需要对zoom响应函数分别设定translate和scale,从v4版不用了,直接合二为一

d3.js - d3 zoom and pan upgrade to version 4 - Stack Overflow

transform必须要设定在svgGraphContainer上,如果设定在svg上,则整个svg的高宽都会随zoom变化,却不一定有平移功能。

随后还要把比例尺的比例重新设置,d3.zoom()自带了比例尺调整功能,该功能参照

https://bl.ocks.org/mbostock/db6b4335bf1662b413e7968910104f0f

这样缩放过程中坐标轴的tick和文字都会随着缩放一起调整

最后要把zoom放到整个svg上,而不是特定的元素上,才能保证在整个图形元素区域都起作用

import * as d3 from 'd3'
export default {
  data () {
    return {
      width: 0,
      height: 0,
      svgGraphContainer: null,
      splines: { node: null, lineGenerator: null, lines: [] },
      polylines: { node: null, lineGenerator: null, lines: [] },
      symbols: { node: null, lines: [] },
      svg: null,
      axises: {
        node: null,
        x: null,
        xScale: null,
        xContainer: null,
        y: null,
        yScale: null,
        yContainer: null },
      dragHandler: null,
      zoomHandler: null
    }
  },
  mounted () {
    this.addZoomBehavior()
  }
  methods: {
    addZoomBehavior () {
      this.zoomHandler = d3.zoom()
        .scaleExtent([0.1, 10]) // zoom limit
        .translateExtent([[-100, -100], [this.width + 90, this.height + 100]]) // translate limit
        .on('zoom', () => {
          this.svgGraphContainer.attr('transform', d3.event.transform)
          this.axises.xContainer.call(this.axises.x.scale(d3.event.transform.rescaleX(this.axises.xScale)))
          this.axises.yContainer.call(this.axises.y.scale(d3.event.transform.rescaleY(this.axises.yScale)))
        })
      this.svg.call(this.zoomHandler)
    }
  }
}

该样例代码来自于vue单文件组件,所以这里的this指的是vue上下文组件本身

Logo

前往低代码交流专区

更多推荐