D3.js实战系列2--缩放&平移

本文系 D3.js 实战系列第二弹,主要讲述了如何让 svg 图形能够监听鼠标的事件进行缩放和平移,以及如何将对图形的初始化进行操作。

基础缩放

基本思想

  1. 创建 svg 元素及内部矩形元素
  2. 创建缩放函数
  3. 给 svg 元素绑定缩放事件

实例展示

1
2
3
4
5
6
7
8
9
10
11
12
13
// 创建一个svg元素,并设置宽高
const svg = d3.select('#canvas').append('svg').attr('width', 500).attr('height', 500);

// 创建一个矩形元素
const rect = svg.append('rect').attr('width', 200).attr('height', 100).attr('fill', 'red');

// 创建缩放函数
const zoom = d3.zoom().on('zoom', (e) => {
rect.attr('transform', e.transform); // 更新矩形的位置
});

// 给svg元素绑定缩放事件
svg.call(zoom);

初始图形居中

业务需求场景

现有一场景,绘制的 svg 的图的左上角坐标不是(0,0),并且绘制的 svg 图大于屏幕中的容器,需要将 svg 图初始展示缩小至全图可见的状态,且不能超过容器的范围。

基本思想

  1. 获取容器的长宽
  2. 获取 svg 图形的长宽和左上角的坐标
  3. 计算初始缩放比 scale 的值
  4. 计算在容器中居中所需的平移量
  5. 给 svg 绑定缩放事件

实例展示

现有的 div 容器:

1
<div id="canvas" style={{ width: '1200px', height: '1200px' }}></div>

在实现监听缩放事件的同时,实现首次缩放和首次平移至容器中心:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 创建svg
let svg = d3.select('#canvas').append('svg').attr('width', '1200px').attr('height', '1200px');

// svg绘制start
// ...
// svg绘制end

// 容器的节点元素
const element = document.getElementById('canvas');

// svg图片元素
const svgElement = svg.node()?.getBBox();
if (!element || !svgElement) return;

const boxWidth = element.clientWidth;
const boxHeight = element.clientHeight;
const svgWidth = svgElement.width;
const svgHeight = svgElement.height;

// 计算获取首次缩放值
const scaleX = boxWidth / svgWidth;
const scaleY = boxHeight / svgHeight;
const scale = Math.min(scaleX, scaleY);

// 计算首次偏移量
const translateX = (boxWidth - svgWidth * scale) / 2 - svgElement.x * scale;
const translateY = (boxHeight - svgHeight * scale) / 2 - svgElement.y * scale;

// 缩放函数
const handleZoom = (e: any) => {
d3.selectAll('svg g').attr('transform', e.transform);
};
let zoom = d3.zoom().on('zoom', handleZoom) as any;
const initIdentity = d3.zoomIdentity.translate(translateX, translateY).scale(scale);
// 实现首次缩放及平移
svg.call(zoom.transform, initIdentity);
// 监听缩放
svg.call(zoom);

结语

本文只是一种业务场景的实现,可以为其他场景提供参考思路,当然 zoom 的监听函数 handleZoom 也可以按业务需求自定义。此外,d3.zoom 还有其他很多 API 规范 zoom 的行为,去d3-zoom 官网可以查看更多。