zoukankan      html  css  js  c++  java
  • d3 + geojson in node

    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();
  • 相关阅读:
    Java多线程运行机制的基本原理
    JAVA IO中的设计模式
    C++ 内存泄露处理方法 (转)
    使用PageHeap.EXE或GFlags.EXE检查内存越界错误 (转)
    32位Windows7上8G内存使用感受+xp 32位下使用8G内存 (转)
    windows 32位系统中进程最大可用内存空间为3GB (转)
    OpenGL 4.0 GLSL 实现 投影纹理映射(Projective Texture Mapping) (转)
    DebugView 调试工具
    剑桥中国史:“571”——林彪的未遂政变(转)
    邱会作与儿子对话:林彪的莫须有之罪(转)
  • 原文地址:https://www.cnblogs.com/xuanmanstein/p/9889568.html
Copyright © 2011-2022 走看看