d3.js本来主要是用于用“数据驱动dom”,在浏览器端,接收后端数据,数据绑定,渲染出svg。

即使是在ng中用,也是会由框架打包,供客户端下载。

那么,如果用所谓后端渲染,发布静态的svg,那就要在node里用d3。

几个遇到的点:

1 d3+jsdom实现后端渲染svg

node和前端的区别,就是没有全局window.document 这个对象。d3选择器无从选起。

1 创建jsdom对象

const { JSDOM } = require("jsdom");

const my_jsdom = new JSDOM(
`
<html>
<head>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
</body>
</html>
`, {
resources: 'usable'
}
);

反引号中是一个空白网页模板,用过flask的jinja2 和ng的 templates的不会陌生,模拟浏览器里的window.document全局对象。

2 导入d3模块,并让d3获得这个模拟的网页。

//按需导入d3
var d3 = Object.assign({}, require("d3-selection"), require("d3-selection-multi"), require("d3-geo"));
//导入模拟的geojson数据
import {default as gdf} from './mock_polygon_gdf.json'; //让d3绑定到模拟的网页
const d3n = d3.select(my_jsdom.window.document); const svg = d3n.select('body')
.insert('svg','records')
.attr('width', 2400)
.attr('height', 3000);
.append('g')
.selectAll('path')
.data(gdf['features'])
.enter()
.append('path')
.attr("d", d3.geoPath()

写这么长,是想说明,注意绑定当前网页后的对象命名为d3n, 不要和开始导入的d3库混淆。

在浏览器里,d3是通过html里写另外一个<script>引入d3.min.js  直接都导入好了,而且是直接d3.select('body')的。

在node这里加了一步,而且后面主要是用d3n来做后面的工作。

前面导入的d3库对象,也是有用的。比如后面的d3.geoPath()方法

经过这样的d3一顿绑定,svg画好了。还差最后一步:

3把网页输出成string,保存到.html文件

const content = my_jsdom.serialize();

fs.writeFile('${fpath}/${fname}.html', content, { encoding: "utf8", flag: "w" }, (err) =>{ 
if (err) {
throw err;
}
});

2. 按需分模块导入d3 子module

d3发展到v4 v5之后,功能膨胀,体积变大,除了集中发布的d3 还分离成若干独立子组件,可以按需加载。

而且,有些子组件并没有打包到d3中,必须自己手动安装,按需加载

根据d3官网,node中按需加载是这样的:https://github.com/d3/d3/blob/master/README.md

In Node:

var d3 = require("d3");

You can also require individual modules and combine them into a d3 object using Object.assign:

var d3 = Object.assign({}, require("d3-format"), require("d3-geo"), require("d3-geo-projection"));

用Object.assign() 打包成一个d3对象

3 一次为selection添加多个attr

特别是不知道attr具体名字,但attr的{name:value}都在需要绑定的数据中的时候

要用到独立于d3的子组件d3-selection-multi

按上面的方式,分组导入(我只用到3个,d3-selection必选,d3-geo是为了绑定geojson)

var d3 = Object.assign({}, require("d3-selection"), require("d3-selection-multi"), require("d3-geo"));

这样就可以:

    const enter = g.selectAll('path')
.data(gjson['features'])
.enter()
.append('path')
.attrs(
(d)=> Object.assign({id: (d) => d['id']}, d['properties'])
);
通过assign拼接,把id 和 properties中的全部属性,都作为dom node的 attribute 一句话给添加好。这确实是比用py里的svgwrite方便很多的,很优雅,要是py里能这么调用d3,该多好啊!
 

4 绑定geojson格式数据

用d3-geo,把一切geometry统统转成svg里的path, 且path的 d字段自动完成,非常优雅。https://github.com/d3/d3-geo#paths
尤其是polygon ->path,  避免自己去 写d M L Z 多次拼接,虽然自己写代码也不长,但是毕竟能偷懒就偷懒:
    const enter = g.selectAll('path')
.data(gjson['features'])
.enter()
.append('path')
.attr("d", d3.geoPath());

通过数据绑定,enter新增数据,添加path,直接一句搞定。

5 d3选择集上消失的update()方法,改用merge()

《精通D3.js》里介绍的data数据绑定后,都是enter() update() exit()三件套。
但现在,v5了,selection上没有update()方法了。
官网有人报issue

给出的答案是用merge,确实更优雅了

把enter和update合并处理了

// Perform the data join and obtain the update selection.
const option = d3.select("#mySelect")
.selectAll("option")
.data(optionsData); // Append the entering nodes, and obtain the enter selection.
const enter = option.enter().append("option"); // Merge entering and updating nodes to apply some operations to both.
enter.merge(option)
.property("value", d => d.value)
.text(d => d.label); // Remove the exiting nodes.
option.exit().remove();

d3 + geojson in node的更多相关文章

  1. D3.js部署node环境开发

    总结一段D3.js部署node环境的安装过程 准备阶段: 首先电脑上要安装node环境,这个阶段过滤掉,如果node环境都不会装,那就别玩基于node环境搞的其他东西了. 搭建环境: 我在自己的F:系 ...

  2. D3.js学习记录 - 数据类型【转】【新】

    1.变量 JAVASCRIPT的变量是一种类型宽松的语言.定义变量不用指定数据类型.而且还是动态可变的. var value = 100;value = 99.9999;value = false;v ...

  3. D3 JS study notes

    如何使用d3来解析自定义格式的数据源? var psv = d3.dsvFormat("|"); // This parser can parse pipe-delimited t ...

  4. [D3] Build an Area Chart with D3 v4

    Similar to line charts, area charts are great for displaying temporal data. Whether you’re displayin ...

  5. [D3] Build a Line Chart with D3 v4

    Line charts are often used to plot temporal data, like a stock price over time. In this lesson we’ll ...

  6. [D3] Build a Scatter Plot with D3 v4

    Scatter plots, sometimes also known as bubble charts, are another common type of visualization. They ...

  7. [D3] Build a Column Chart with D3 v4

    Column and bar charts are staples of every visualization library. They also make a great project for ...

  8. [D3] Make D3 v4 Charts Responsive with the viewBox attribute

    Making SVGs responsive is unfortunately not as simple as adding some media queries. This lesson intr ...

  9. d3.js制作连线动画图和编辑器

    此文章为原创文章,原文地址:https://www.cnblogs.com/eagle1098/p/11431679.html 连线动画图 编辑器 效果如上图所示.本项目使用主要d3.jsv4制作,分 ...

随机推荐

  1. Golang字符串格式化

    Go对字符串格式化提供了良好的支持.下面我们看些常用的字符串格式化的例子. package main import ( "fmt" "os" ) type po ...

  2. RequestBody使用

    @RequestBody主要用来接收前端传递给后端的json字符串中的数据的(请求体中的数据的); GET方式无请求体,所以使用@RequestBody接收数据时,前端不能使用GET方式提交数据,而是 ...

  3. direct加载之ora-39782一例

    近日,我们有个环境在数据加载到oracle的时候出现ora-39782异常,版本是11.2.经google,几乎没有什么先例,因为我们是使用oci直接写的,可见现在还使用oci接口并不多,也或者我们的 ...

  4. [BeiJing wc2012]冻结 题解

    HYSBZ - 2662 这个题如果我们先想用平常的方法来建图,因为我们无法确定是否使用卡片,如果我们每个点每个边都建图,那么非常耗时占空间:注意到k是比较小的,所以我们可以把k拆开,把一个点分为k个 ...

  5. phpstorm中设置代码上传到github

    参考: https://blog.csdn.net/Knight_quan/article/details/54894691 https://www.300168.com/biancheng/show ...

  6. JavaScript中this的用法 及 如何改变this的指向

    要懂得JavaScript中this的用法,首先需要知道,JavaScript中的作用域相关知识. var fun = function(){ var flag = 1; console.log(fl ...

  7. tf.nn.relu

    tf.nn.relu(features, name = None) 这个函数的作用是计算激活函数 relu,即 max(features, 0).即将矩阵中每行的非最大值置0. import tens ...

  8. Static变量与代码块

    * static:是一个关键字,用于修饰成员变量和成员方法 * static的特点: * 被所有的对象所共享 * 可以使用类名调用 * 静态的加载优先于对象 * 随着类的加载而加载 * static的 ...

  9. Python3 tkinter基础 Label imag显示图片

             Python : 3.7.0          OS : Ubuntu 18.04.1 LTS         IDE : PyCharm 2018.2.4       Conda ...

  10. LuoguP2161 [SHOI2009]会场预约

    题目地址 题目链接 题解 用fhqtreap对区间进行维护. 可以注意到的是,对于当前存在的预约,他们一定是升序排列的(有重叠的都被删了). 那么就可以用按照位置分裂的fhqtreap搞了(预约无论按 ...