gpt4 book ai didi

d3.js - dv.js中svg和canvas之间的区别

转载 作者:行者123 更新时间:2023-12-04 00:05:49 25 4
gpt4 key购买 nike

我是d3.js的新手。我发现有两种方法可以绘制对象-SVG和Canvas。
我的用例是在<100个节点和边缘附近。我已经尝试了一些使用 Canvas 的示例,它看起来很棒。

我看到the difference between SVG and Canvas周围有一个SO帖子。

两者都适合我使用,但是,我倾向于使用 Canvas (因为我已经没有几个示例可以工作了)。如果我在d3.js上下文中缺少任何内容,请纠正我吗?

最佳答案

链接的问题/答案中列出的差异说明了svg和 Canvas ( vector /光栅等)之间的一般差异。但是,对于d3,这些差异还具有其他含义,尤其是考虑到d3的核心部分是数据绑定(bind)。

数据绑定(bind)

d3的最主要特征可能是数据绑定(bind)。 Mike Bostock指出,一旦将数据加入元素,他就需要创建d3:

The defining moment was when I got the data-join working for the first time. It was magic. I wasn’t even sure I understood how it worked, but it was a blast to use. I realized there could be a practical tool for visualization that didn’t needlessly restrict the types of visualizations you could make. link



使用SVG,数据绑定(bind)很容易-我们可以为单个svg元素分配一个基准,然后使用该基准设置其属性/更新它等。这是基于svg的状态性-我们可以重新选择一个圆并对其进行修改或访问其属性。

使用Canvas,canvas是无状态的,因此我们无法将数据绑定(bind)到Canvas中的形状,因为Canvas仅包含像素。因此,我们无法在 Canvas 中选择和更新元素,因为 Canvas 没有任何元素可供选择。

基于以上内容,我们可以看到惯用D3中的svg需要输入/更新/退出循环(或基本的附加语句):我们需要输入元素才能看到它们,并经常根据其基准对它们进行样式设置。使用canvas,我们不需要输入任何内容,就像退出/更新一样。没有要追加的元素以供查看,因此我们可以根据需要绘制可视化 View ,而无需使用d3 svg可视化 View 中使用的enter / update / exit或append / insert方法。

没有数据绑定(bind)的 Canvas

我将在最后一个问题 here中使用示例bl.ock。因为我们根本不需要附加任何元素(或向其附加数据),所以我们使用forEach循环绘制每个功能(这与SVG的惯用D3相反)。由于没有要更新的元素,因此我们必须在每个刻度上重绘每个功能-重绘整个框架(注意在每个刻度上清除 Canvas )。关于拖动,d3.drag和d3.force具有一些预期可与 Canvas 一起使用的功能,并且可以允许我们通过拖动事件直接修改数据数组-绕开了DOM中对节点元素直接与鼠标进行交互的任何需求(d3 .force还直接修改了数据数组-但它也在 svg example中进行了修改)。

如果没有数据绑定(bind),我们将直接基于数据绘制元素:
data.forEach(function(d) {
// drawing instructions:
context.beginPath()....
})

如果数据更改,我们可能会重绘数据。

带有数据绑定(bind)的 Canvas

也就是说,您可以使用 Canvas 实现数据绑定(bind),但是它需要使用伪元素的另一种方法。我们经历了常规的更新/退出/输入周期,但是当我们使用虚拟元素时,不会呈现任何内容。我们可以在需要时重新渲染 Canvas (如果使用过渡,则可以连续渲染),并根据虚拟元素进行绘制。

要创建一个虚拟的父容器,我们可以使用:
// container for dummy elements:
var faux = d3.select(document.createElement("custom"));

然后,我们可以根据需要使用Enter / exit / update / append / remove / transition / etc进行选择:
// treat as any other DOM elements:
var bars = faux.selectAll(".bar").data(data).enter()....

但是,由于未呈现这些选择中的元素,因此我们需要指定如何以及何时绘制它们。在没有数据绑定(bind)和Canvas的情况下,我们直接基于数据绘制元素,而在数据绑定(bind)和Canvas的情况下,我们基于人造DOM中的选择/元素绘制:
bars.each(function() {
var selection = d3.select(this);
context.beginPath();
context.fillRect(selection.attr("x"), selection.attr("y")...
...
})

在这里,只要我们退出/进入/更新等,我们就可以重绘元素,这可能会有一些优势。这也允许通过连续重绘同时在人造元素上转换属性来进行D3转换。

以下示例具有一个完整的带有过渡的输入/退出/更新周期,演示了具有数据绑定(bind)的 Canvas :

var canvas = d3.select("body")
.append("canvas")
.attr("width", 600)
.attr("height", 200);

var context = canvas.node().getContext("2d");

var data = [1,2,3,4,5];

// container for dummy elements:
var faux = d3.select(document.createElement("custom"));

// normal update exit selection with dummy elements:
function update() {
// modify data:
manipulateData();


var selection = faux.selectAll("circle")
.data(data, function(d) { return d;});

var exiting = selection.exit().size();
var exit = selection.exit()
.transition()
.attr("r",0)
.attr("cy", 70)
.attr("fill","white")
.duration(1200)
.remove();

var enter = selection.enter()
.append("circle")
.attr("cx", function(d,i) {
return (i + exiting) * 20 + 20;
})
.attr("cy", 50)
.attr("r", 0)
.attr("fill",function(d) { return ["orange","steelblue","crimson","violet","yellow"][d%5]; });

enter.transition()
.attr("r", 8)
.attr("cx", function(d,i) {
return i * 20 + 20;
})
.duration(1200);

selection
.transition()
.attr("cx", function(d,i) {
return i * 20 + 20;
})
.duration(1200);

}


// update every 1.3 seconds
setInterval(update,1300);


// rendering function, called repeatedly:
function render() {
context.clearRect(0, 0, 600, 200);
faux.selectAll("circle").each(function() {
var sel = d3.select(this);
context.beginPath();
context.arc(sel.attr("cx"),sel.attr("cy"),sel.attr("r"),0,2*Math.PI);
context.fillStyle = sel.attr("fill");
context.fill();
context.stroke();
})
window.requestAnimationFrame(render)
}

window.requestAnimationFrame(render)

// to manipulate data:
var index = 6; // to keep track of elements.
function manipulateData() {
data.forEach(function(d,i) {
var r = Math.random();
if (r < 0.5 && data.length > 1) {
data.splice(i,1);
}
else {
data.push(index++);
}
})
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>


Block version

摘要

使用canvas,数据绑定(bind)需要一组伪元素,但是一旦绑定(bind),您就可以轻松使用过渡和更新/输入/退出周期。但是,渲染与更新/输入/退出和过渡是分离的-由您决定如何以及何时重新绘制可视化效果。该绘图发生在更新/输入/退出和过渡方法之外。

使用svg,进入/更新/退出循环和过渡会更新可视化中的元素,从而一步一步链接渲染和数据。

在具有在人造元素上绑定(bind)数据的 Canvas 中,可视化表示人造节点。在svg中,可视化是节点。

数据绑定(bind)是一个根本的区别,惯用D3在SVG中需要它,但使我们可以选择是否要在使用Canvas时使用它。
但是,Canvas和SVG之间与下面提到的D3有其他区别:

互动性

使用Canvas可能最令人担心的是它是无状态的,只是像素的集合而不是元素的集合。与特定的渲染形状进行交互时,这会使鼠标事件变得困难。尽管鼠标可以与Canvas交互,但是会触发标准事件以与特定像素进行交互。

因此,在使用SVG的同时,我们可以为强制布局中的每个节点分配一个单击侦听器(例如),对于Canvas,我们可以在整个 Canvas 上设置一个单击侦听器,然后根据位置确定应该将哪个节点视为“单击” 。

上面提到的D3力 Canvas example使用力布局的 .find方法,并使用该方法找到最接近鼠标单击的节点,然后将拖动主题设置到该节点。

我们可以通过几种方法来确定正在与哪些渲染形状进行交互:
  • 创建一个隐藏的 Canvas ,为渲染的形状提供引用图

  • 可见 Canvas 中的每个形状都绘制在不可见 Canvas 上,但是在不可见 Canvas 上具有唯一的颜色。以可见 Canvas 上的鼠标事件的xy值为例,我们可以使用它来获得与不可见 Canvas 上相同xy的像素颜色。由于颜色是HTML中的数字,因此我们可以将颜色转换为基准的索引。
  • 热图/栅格数据的反转比例(将xy位置的比例缩放到未缩放的输入值)(example)
  • 使用未呈现的Voronoi图的.find方法查找距事件最近的节点(对于点,圆)
  • 使用强制布局的.find方法查找距事件最近的节点(对于点,圆,主要是在强制布局的上下文中)
  • 使用直接数学,四叉树或其他方法

  • 第一个可能是最常见的,当然也可能是最灵活的,但是其他情况可能取决于上下文。

    性能

    我会很快介绍性能。在问题的链接文章“ What's the difference between SVG and Canvas”中,答案可能不够大胆,但是通常,canvas和svg在处理成千上万个节点时,尤其是在渲染成千上万个正在动画的节点时,渲染时间有所不同。

    随着渲染更多的节点以及节点执行更多的操作(转换,移动等), Canvas 的性能变得越来越高。

    这是Canvas(在人造节点上具有数据绑定(bind))和SVG以及19200个同时转换的快速比较:
  • Canvas Test
  • SVG Test

  • Canvas 应该是两者中较平滑的一个。

    D3模块

    最后,我将介绍D3的模块。其中大多数根本不与DOM交互,并且可以轻松地用于SVG或Canvas。例如,d3-quadtree或d3-time-format不是SVG或Canvas专用的,因为它们根本不处理DOM或渲染。诸如d3-hierarchy之类的模块实际上也不渲染任何东西,但是提供了在Canvas或SVG中渲染所需的信息。

    提供SVG路径数据的大多数模块和方法也可以用于生成 Canvas 路径方法调用,因此可以相对轻松地用于SVG和Canvas。

    我将在这里专门提到几个模块:

    D3选择

    显然,此模块需要选择,选择需要元素。因此,要将其与Canvas一起用于输入/更新/退出循环或选择.append / remove / lower / raise之类的内容,我们希望在Canvas中使用人造元素。

    使用Canvas,分配有 selection.on()的事件监听器可以使用或不使用数据绑定(bind),上面提到了鼠标交互的挑战。

    D3转换

    此模块可转换元素的属性,因此通常仅在我们将数据与人造元素绑定(bind)时才能与Canvas一起使用。

    D3轴

    该模块严格来说是SVG,除非愿意做大量工作以将其拔除成Canvas使用。在使用SVG时,尤其是在转换轴时,该模块非常有用。

    D3路径

    这将使用Canvas路径命令并将其转换为SVG路径数据。对于将 Canvas 代码用于SVG情况很有用。通常在D3内部使用,以生成SVG路径数据。

    关于d3.js - dv.js中svg和canvas之间的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50141324/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com