D3JS 画布缩放与平移(默认:鼠标左键为平移,滚动轮滑为缩放)

目录

实现逻辑

1、创建一个SVG容器:

2、创建一个主分组:

3、添加背景:

4、定义缩放和平移行为:

5、应用缩放和平移行为:

完整代码

缩放API方法

d3.zoom()

zoom(选择)

zoom.transform(selection, transform)

zoom.translateBy(selection,x,y)

zoom.translateTo(selection, x, y)

zoom.scaleTo(selection, k)

zoom.scaleBy(selection,k)

zoom.filter([filter])

zoom.wheelDelta(δ)

zoom.extent([extent])

zoom.scaleExtent([extent])

zoom.translateExtent([extent])

zoom .clickDistance([distance])

zoom.duration([duration])

zoom.interpolate([interpolate])

zoom.on(typenames [,listener])


 D3.js绘图工具系列文章总提纲:【传送门】

修改d3默认事件(进阶):按住轮滑为平移,滚动轮滑为缩放【传送门】

效果图(包含了画布的拖拽与缩放及圆的拖拽,其中圆的拖拽效果可在【传送门】查看):

实现逻辑

1、创建一个SVG容器:

使用d3.js创建一个SVG容器(h5代码中须有相关id标签),用于呈现图表和图形;

let svg = reactive({});

// 生成画布的dom节点id为d3Canvas;须在html代码中添加
svg = d3
    .select('#d3Canvas')
    .append("svg")
    .attr("id", "svg")
    .attr("width", 500)
    .attr("height", 500)
    .attr("viewBox", "0 0 500 500");

2、创建一个主分组:

使用d3.js对所创建的SVG容器,添加一个g标签,用于控制整体缩放;不将事件直接绑定于svg上,是因为会出现bug:画面呈现出一闪一闪的,解决方案是将所有元素使用g标签进行包裹。

let g = reactive({});

g = svg.append("g").attr("id", "svg-grid");

3、添加背景:

用于让拖拽缩放效果更明显;

g.insert("rect", ":first-child")
    .attr("width", "100%")
    .attr("height", "100%")
    .attr("fill", "url(#grid)");

// 使用网格样式填充 SVG 元素背景
var pattern = svg.insert("defs", ":first-child")
    .append("pattern")
    .attr("id", "grid")
    .attr("width", 20)
    .attr("height", 20)
    .attr("patternUnits", "userSpaceOnUse");

// 添加网格线
pattern.append("path")
    .attr("d", "M 20 0 L 0 0 0 20")
    .attr("stroke", "lightgray")
    .attr("stroke-width", 0.5)
    .attr("fill", "none");

4、定义缩放和平移行为:

使用d3.zoom()函数创建一个缩放和平移行为,可以通过设置缩放比例和平移偏移量来控制缩放和平移的效果;

function zoomed(event, svg) {
    // 对g进行偏移赋值
    g.attr("transform", event.transform);
}
var zoom = d3
    .zoom()
    .scaleExtent([0.3, 10])
    .on("zoom", (event) => zoomed(event));

5、应用缩放和平移行为:

将缩放和平移行为应用到SVG容器上,使得图表可以响应鼠标事件。

g.call(zoom)

注:若需对画布进行缩放及平移则修改两个参数:

scale:缩放;

translate:平移;


initZoom(svg) {
    ……
    g.call(zoom.transform, d3.zoomIdentity.scale(0.6).translate(0, 150));
}

完整代码

let svg = reactive({});

// 生成画布的dom节点id为d3Canvas;须在html代码中添加
svg = d3
    .select('#d3Canvas')
    .append("svg")
    .attr("id", "svg")
    .attr("width", 500)
    .attr("height", 500)
    .attr("viewBox", "0 0 500 500");

let g = reactive({});

g = svg.append("g").attr("id", "svg-grid");

g.insert("rect", ":first-child")
    .attr("width", "100%")
    .attr("height", "100%")
    .attr("fill", "url(#grid)");

// 使用网格样式填充 SVG 元素背景
var pattern = svg.insert("defs", ":first-child")
    .append("pattern")
    .attr("id", "grid")
    .attr("width", 20)
    .attr("height", 20)
    .attr("patternUnits", "userSpaceOnUse");

// 添加网格线
pattern.append("path")
    .attr("d", "M 20 0 L 0 0 0 20")
    .attr("stroke", "lightgray")
    .attr("stroke-width", 0.5)
    .attr("fill", "none");

function zoomed(event, svg) {
    // 对g进行偏移赋值
    g.attr("transform", event.transform);
}
var zoom = d3
    .zoom()
    .scaleExtent([0.3, 10])
    .on("zoom", (event) => zoomed(event));

g.call(zoom)

g.append("circle")
    .attr("cx", 50)
    .attr("cy", 50)
    .attr("r", 20)
    .style("fill", "blue")
    .attr("id", `circle-1`)

缩放API方法

以下是一些最常用的缩放API方法(放于此便于查阅,为引用内容【原文传送门】):

  • d3.zoom()

  • zoom(selection)

  • zoom.transform(selection, transform)

  • zoom.translateBy(selection, x, y)

  • zoom.translateTo(selection, x, y)

  • zoom.scaleTo(selection, k)

  • zoom.scaleBy(selection, k)

  • zoom.filter([filter])

  • zoom.wheelDelta([delta])

  • zoom.extent([extent])

  • zoom.scaleExtent([extent])

  • zoom.translateExtent([extent])

  • zoom.clickDistance([distance])

  • zoom.duration([duration])

  • zoom.interpolate([interpolate])

  • zoom.on(typenames[, listener])

让我们简单介绍一下这些Zooming API方法.

d3.zoom()

它会创建一个新的缩放行为.我们可以使用下面的脚本访问它.

<script>
   var zoom = d3.zoom();
</script>

zoom(选择)

它用于对选定元素应用缩放变换.例如,您可以使用以下语法实例化mousedown.zoom行为.

selection.call(d3.zoom().on(" mousedown.zoom",mousedowned));

zoom.transform(selection, transform)

它用于设置所选元素的当前缩放变换到指定的转换.例如,我们可以使用以下语法将缩放变换重置为标识变换.

selection.call(zoom.transform,d3.zoomIdentity );

我们还可以使用以下语法将缩放变换重置为标识变换1000毫秒.

selection.transition().duration(1000).call(zoom.transform,d3.zoomIdentity);

zoom.translateBy(selection,x,y)

通俗点讲对 selection 进行 [x, y] 的偏移,若放于实际应用时,应为两点之间的差值,即:

x = x2 - x1;
y = y2 - y1;

源代码定义如下.

zoom.translateBy = function(selection, x, y, event) {
    zoom.transform(selection, function() {
      return constrain(this.__zoom.translate(
        typeof x === "function" ? x.apply(this, arguments) : x,
        typeof y === "function" ? y.apply(this, arguments) : y
      ), extent.apply(this, arguments), translateExtent);
    }, null, event);
  };

zoom.translateTo(selection, x, y, p)

用于对 selection 进行 x1,y1 到 p: [x2, y2] 的偏移,其中 [x1, y1] 为起点,[x2, y2] 为终点。

源代码定义如下:

  zoom.translateTo = function(selection, x, y, p, event) {
    zoom.transform(selection, function() {
      var e = extent.apply(this, arguments),
          t = this.__zoom,
          p0 = p == null ? centroid(e) : typeof p === "function" ? p.apply(this, arguments) : p;
      console.log("translateTo", e, t, p0);
      return constrain(identity.translate(p0[0], p0[1]).scale(t.k).translate(
        typeof x === "function" ? -x.apply(this, arguments) : -x,
        typeof y === "function" ? -y.apply(this, arguments) : -y
      ), e, translateExtent);
    }, p, event);
  };

zoom.scaleTo(selection, k)

它用于将所选元素的当前缩放变换缩放为 k .这里, k 是一个比例因子,指定为数字或函数.

zoom.scaleTo = function(selection, k) {
   zoom.transform(selection, function() {
      k = = = "function" ? k.apply(this, arguments) : k;
   });
};

zoom.scaleBy(selection,k)

它用于按 k 缩放所选元素的当前zoon变换.这里, k 是一个比例因子,指定为数字或返回数字的函数.

zoom.scaleBy = function(selection, k) {
   zoom.scaleTo(selection, function() {
      var k0 = this.__zoom.k,
      k1 = k = = = "function" ? k.apply(this, arguments) : k;
      return k0 * k1;
   });
};

zoom.filter([filter])

它用于将过滤器设置为指定的缩放功能行为.如果未指定过滤器,则返回当前过滤器,如下所示.

function filter() {
   return !d3.event.button;
}

zoom.wheelDelta(δ)

&Delta的值由轮三角函数返回.如果未指定delta,则返回当前的wheel delta函数.

zoom.extent([extent])

用于设置指定数组点的范围.如果未指定范围,则返回当前范围访问器,默认为[[0,0],[width,height]],其中width是元素的客户端宽度,height是其客户端高度.

zoom.scaleExtent([extent])

用于将比例范围设置为指定的数字数组[k0,k1].这里, k0 是允许的最小比例因子.而 k1 是允许的最大比例因子.如果未指定extent,则返回当前缩放范围,默认为[0,&infin;].考虑下面定义的示例代码.

selection
   .call(zoom)
   .on("wheel", function() { d3.event.preventDefault(); });

当已经处于比例范围的相应限制时,用户可以尝试通过转动进行缩放.如果我们想要阻止滚轮输入滚动而不管刻度范围如何,请注册滚轮事件监听器以防止浏览器默认行为.

zoom.translateExtent([extent])

如果指定了范围,则将translate范围设置为指定的点数组.如果未指定范围,则返回当前的翻译范围,默认为[[ - &infin;, - &infin;],[+&infin;,+&infin;]].

zoom .clickDistance([distance])

此方法用于设置可缩放区域在向上和向下之间移动的最大距离,这将触发后续点击事件.

zoom.duration([duration])

此方法用于设置双击时缩放过渡的持续时间,然后双击指定的数量毫秒并返回缩放行为.如果未指定持续时间,则返回当前持续时间,默认为250毫秒,定义如下.

selection
   .call(zoom)
   .on("dblclick.zoom", null);

zoom.interpolate([interpolate])

此方法用于内插缩放过渡到指定的函数.如果未指定interpolate,则返回当前插值工厂,默认为d3.interpolateZoom.

zoom.on(typenames [,listener])

如果指定了侦听器,它将为指定的类型名设置事件侦听器并返回缩放行为.类型名是一个包含一个或多个由空格分隔的类型名的字符串.每个typename都是一个类型,可选地后跟句点(.)和名称,例如zoom.one和zoom.second.该名称允许为同一类型注册多个侦听器.此类型必须来自以下其中一项;

  • 开始 : 缩放开始后(例如在mousedown上).

  • 缩放 : 更改缩放变换后(例如在mousemove上).

  • 结束 : 缩放结束后(例如在鼠标上).

感谢阅读!在您离开之前,不妨留下您的足迹:

👍 点个赞,让我知道您喜欢这篇文章!

📝 有任何想法、建议或问题?欢迎在下方评论区分享您的想法!

🔁 分享给您的朋友们,让更多人受益!

💌 喜欢我的内容?立即订阅我的博客,获取更多精彩内容!

谢谢您的支持与参与,让我们一起创造更好的内容体验!

  • 32
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值