之前还是想简单了, 现在重新写这篇。把逻辑拆分粒度的辨析,放到外面去。

问题提出:svg控制方案 基于 D3 还是 angular

根据这个,html 4种展现样式:普通的html,svg,2D canvas,webgl 3d canvas.

Angular和D3都有各自的数据绑定方式来操作dom,需要合适的方式让它们不打架,代码尽量优雅。

1个dom元素只让1个框架去操作。

尤其是svg中各元素,最好不要ng绑定了一些,d3又绑定另一些。

我需求是:用svg做图形化输入和图文混合的dom展现。不止是单向的输出展示visualization问题,还有图文混合输入的问题

1数据源用ng的service,数据结构为聚合根下辖若干种/若干数量的领域对象

2多个图层叠加,各自管理各自的显示效果。

3输出显示:当数据源发生改变时,图表刷新显示

4输入响应:当图表中元素被拖拽等情况,要保存更新位置等参数,数据源数据相应被更新。

用谁创建dom元素?

2种方案:

1 用D3。包括selectAll选择集/data()数据绑定/添加属性,添加drag等行为

this.tiles
.attr('transform', function (node) {
const piece = node.piece;
// console.log(piece);
return 'translate(' + piece.transform.x + ',' + piece.transform.y + ')';
});
this.images
.attr('xlink:href', function (node) {
const piece = node.piece;
return piece.image;
})
.attr('width', scale)
.attr('height', scale);

2  angular的template:

<svg viewBox="0 0 250 250"
(mousemove)="setCircleLocation($event)">
<svg:defs>
<svg:clipPath id="clip">
<svg:circle [attr.cx]="circle[0]" [attr.cy]="circle[1]" r="100" />
</svg:clipPath>
</svg:defs>
<svg:g clip-path="url(#clip)">
<svg:polygon points="125,30 125,30 125,30 31.9,63.2 46.1,186.3 125,230 125,230 125,230 203.9,186.3 218.1,63.2" />
<svg:polygon points="125,30 125,52.2 125,52.1 125,153.4 125,153.4 125,230 125,230 203.9,186.3 218.1,63.2 125,30" />
<svg:path d="M125,52.1L66.8,182.6h0h21.7h0l11.7-29.2h49.4l11.7,29.2h0h21.7h0L125,52.1L125,52.1L125,52.1L125,52.1
L125,52.1z M142,135.4H108l17-40.9L142,135.4z"/>
</svg:g>
</svg>

其实背后都隐含了创建dom的过程。angular在编译后会产生JavaScript DOM API,在运行时创建dom元素:

对HTML与SVG采用不同的API

document.createElement('div');

document.createElementNS('http://www.w3.org/2000/svg', 'path');

js有点相当于前端的汇编语言,不论用jquery,d3,还是angular,最终都是一样的js代码。

区别在于,越往汇编层,越暴露底层步骤(每个div操作,类似于操作每个寄存器);而越往高层走,更强调的是目的和最终要的结果。

高级程度最高的,当然是angular了。

这也就澄清了一个自己的误区,

D3≠svg。

虽然通常看到的svg操作案例,都是用d3或者基于d3的扩展包. 但绝不是说svg只能用d3来操作。

d3虽然名字是data driven document。 但其实里面的document指的是svg或canvas,d3更类似于openpyxl这样的操作xlsx的库,不等于xlsx格式标准。完全可以用xlwt来操作xlsx。

d3主要是实现了很多现成的layout(比如力导向图什么的),方便显示地图,定义动画/拖拽/圈选(用brush)比较方便。

从功能上说,angular 一样是data driven document,只不过是用模板+数据绑定的方式。

d3的data只能是array型,而angular绑定的数据格式就灵活多了,单个的class也可以,array型的用*NgFor。

用汇编还是脚本语言,都能写出同样功能程序来。在不考虑的性能的时候,无非是开发速度/复用难度。这些考虑。

结论:

还是老实一点,根据职责不同,读写分离,准备2种方案:

读:用D3单纯展示数据模型,数据变化时用d3重画

写:用ng双向绑定svg,加载数据模型,获取svg拖拽、圈选事件,修改数据模型。

1 如果仅仅需要数据->svg,展示、特别是简单的图、各种D3有的layout,或者地图这种作为底图,数据不变的图,(可以拖拽,但不要拖拽后的结果),那么就直接用D3,不用ng,或者ng简单封装即可。

2 如果需要把svg作为一种输入界面,工作图,如需要保存、分发拖拽后元素的位置,需要双向数据绑定(svg<->数据模型),不需要动画、过渡,那么就直接用ng,不用d3

d3类似matplotlab,做visualization非常舒服,做编辑图片像素区域的界面就非常难受,还是乖乖用qt的QImage,Qpixmap舒服。

ng的templates可以显式表达svg的结构,模板语法也类似jinja2。

——看文档、想、实做。。。好几天了,虽然略有纠结,磕磕绊绊的,但好在有读写分离的经验,对unity,qt,matplotlib都还算熟悉,得到现在的结论还算不纠结。

附录A,NG的小坑

SVG不是html,而是XML。ng在处理模板中自定义元素的时候,不能和html一样。

应该这样做

@Component({
selector: '[app-logo-left]',
templateUrl: './app-logo-left.component.html'
})
export class LogoLeftComponent {
}

把方括号写在selector里面,在模板里不写方括号

<svg viewBox="0 0 250 250">
<svg:g app-logo-left />
<svg:g app-logo-right />
<svg:g app-logo-a />
</svg> 

附录B,D3的小坑

1

In D3, data() accepts only 3 things: an array, a function or nothing

2 data带主键函数之前,必须先不带主键函数已经绑定过一次,才可以,否则报错

http://www.ourd3js.com/wordpress/811/

//数据
var persons = [ { id: 3 , name:"张三" },
{ id: 6 , name:"李四" },
{ id: 9 , name:"王五" }]; //选择body中的所有的p元素
var p = d3.select("body").selectAll("p"); //绑定数据,并修改p元素的内容
p.data(persons)
.text(function(d){
return d.id + " : " + d.name;
}); //更新persons里的数据
persons = [ { id: 6 , name:"张三" },
{ id: 9 , name:"李四" },
{ id: 3 , name:"王五" }]; //根据键函数的规则绑定数据,并修改内容
p.data(persons, function(d){ return d.id; })
.text(function(d){
return d.id + " : " + d.name;
});
</script>
</body>

3 要想使用d3.drag(),.必须首先用data()进行绑定

不可避免在angular里同时用数据绑定和d3了

4 d3.drag()的事件,v4里精简成了'start' 'drag','end'。书和搜索结果里很多都还是v3的,是'dragstart'  会报错。还是要多看最新的官方文档。

5 确实底层。比用matplotlib还底层,有点不适应。

坐标轴axis 都要自己手动调位置。

用path画图每个点都要自己调用scale设置比例尺。

边距留白,要自己考虑,设置在scale定义里

……

如果不是为了定制特殊效果的图,或者看中力导向图这些特殊的图,只是普通显示一下,可以用别的封装得高级些的库了。

另一篇Visualizing Data with Angular and D3的作者给出的数据绑定方案:

写了一个d3组件,封装了d3.js 图类型比如ForceDirectedGraph,然后 图上node 等等,把这些d3里的东西定义在models里,然后定义了D3.service。

然后,自己写的实际的图组件,就和d3隔离了,只调用自己写的d3组件

从自己写的d3组件实例化ForceDirectedGraph,而不是直接import * as d3 from 'd3';

svg操纵方案 基于 D3 还是 angular?的更多相关文章

  1. 在vue中使用基于d3为基础的dagre-d3.js搞定一个流程图组件

    项目中想搞定一个流程图,开始使用了阿里的G6,但是G6目前不支持手势,这样就很郁闷了,因为公司的领导都是使用iPad看的,你不支持手势是不行的,后来又想到了百度的echarts,试了试,感觉还不错,手 ...

  2. 基于SWFUpload的angular上传组件

    回顾 由于工作内容比较多,特别是架构方面,需要耗费很多的时间调整.重构,因此很久没有写文章了. 话就不多说了,直接进入主题. 实现 首先分析一下SWFUpload初始化的时候,需要传入当前触发上传的元 ...

  3. 世界各国GDP动态排名可视化实现(基于d3.js)

    一.说明 之前在抖音上看到GDP等各种排名的可视化,一直想知道是怎么实现的.之前也有研究过一次,但觉得太麻烦放弃了,昨天又心痒难耐研究了一翻. 先是看到这篇文章说是有人基于d3.js实现:https: ...

  4. SVG基础图形和D3.js

    使用D3.js画一个SVG 的 圆 circle 可以使用如下代码创建: <svg width="50" height="50"> <circ ...

  5. D3.js学习笔记(六)——SVG基础图形和D3.js

    目标 在这一章,我们将会重温SVG图形,学习如何使用D3.js来创建这些图形. 这里会包括前面例子中的SVG基础图形以及如何使用D3.js设置图形的属性. 使用D3.js画一个SVG 的 圆 circ ...

  6. vue项目中基于D3.js实现桑基图功能

    前端实现数据可视化的方案有很多种,以前都是使用百度的echarts,使用起来很方便,直接按照特定的数据格式输入,就能实现相应的效果,虽然使用方便,但是缺点就是无法自定义一些事件操作,可自由发挥的功能很 ...

  7. 基于requirejs和angular搭建spa应用

    接上篇,angular 实战部分,angular比较适合spa项目,这里不借助任何seed和构建工具,直接从零搭建,基本的angular项目结构大致包含如下几个部分: 1)app.js 入口 2)in ...

  8. Android屏幕适配方案——基于最小宽度(Smallest-width)限定符

    转自:https://www.cnblogs.com/error404/p/3815739.html 一.关于布局适配建议 1.不要使用绝对布局 2.尽量使用match_parent 而不是fill_ ...

  9. 主键生成器效率提升方案|基于雪花算法和Redis控制进程隔离

    背景 主键生成效率用数据库自增效率也是比较高的,为什么要用主键生成器呢?是因为需要insert主表和明细表时,明细表有个字段是主表的主键作为关联.所以就需要先生成主键填好主表明细表的信息后再一次过在一 ...

随机推荐

  1. c++中的构造(包括移动),赋值(包括移动),析构详解

    这五种操作:构造(包括移动),赋值(包括移动),析构其实就是定义了对一个对象进行构造,赋值,析构时的行为.理解这些行为并不复杂,复杂的是理解在继承下这些行为的表现.需要注意的是他们并不会被继承(传统意 ...

  2. 第六章 数据库设计之ER模型

    在ER图中实体用方框表示 实体其实就相当于一个二维表,实体实例就相当于二维表中的一行 属性在二维表中用椭圆表示,属性就是描述实体特征的数据项 概念:键(也被成为候选键):1,属性集合K上的行唯一   ...

  3. docker:搭建lamp应用

    (原文http://blog.csdn.net/smallfish1983/article/details/40108999?utm_source=tuicool) LAMP 指的 Linux(操作系 ...

  4. discuz模板引擎

    discuz是采用“编译型的模板”,就是指采用普通网页文件保存,在文件中插入需要动态显示数据的仿php的代码,最后进行编译成真正的php的文件保存为模板缓存文件,这个转换的过程就称为编译.在用户浏览页 ...

  5. 匹克定理pick

    与POJ1226为例 要知道在一个格点多边形内 知道期内部的点数 Q,边上的点数L,就可以知道他的面积pick定理及 S=Q+L/2-1; 然后 还有边上的点数除了多边形的顶点外,还有一些点该怎么求呢 ...

  6. Java设计模式应用——工厂模式

    工厂模式有三种:简单工厂.工厂方法.抽象工厂 一. 抽象工厂 1. 一个可以生产多种产品的工厂: 2. 不改变工厂无法生产新的产品. package com.coshaho.learn.factory ...

  7. python 采坑总结 调用键盘事件后导致键盘失灵的可能原因

    在练习python封装键盘事件的时候,实现一个keyDown和keyUp的功能: @staticmethod    def keyDown(keyName):        #按下按键        ...

  8. 怎样把QQ群降级(1000人降到200或500人,500人降到200)

    怎样把QQ群降级(1000人降到200或500人,500人降到200)QQ群只有升级的选项,没有降级选项,一旦升级为1000人,就无法直接降级为200人或500人,建群时选择了500人也无法降到200 ...

  9. 2018跳槽面试必备之深入理解 Java 多线程核心知识

    导语:多线程相对于其他 Java 知识点来讲,有一定的学习门槛,并且了解起来比较费劲.在平时工作中如若使用不当会出现数据错乱.执行效率低(还不如单线程去运行)或者死锁程序挂掉等等问题,所以掌握了解多线 ...

  10. String和StringBuffer和StringBuilder

    String类 Java语言中用String类代表不可变的字符串,它是由任意多个字符组成的序列.程序中需要存储大量的信息时,一般都用String对象. 1.字符串初始化 JavaSE API为字符串对 ...