angular7 + d3 显示svg

汇总一些之前没有注意到的问题

总体思路:

app只是显示svg为主,接收后端推送的数据改变,显示变化后的svg。

因此,只用d3的数据绑定更新组件里<svg></svg>节点. 而不用 ng的数据绑定。

组件view 的svg部分由d3负责。 根据数据service接收到的"不可变数据”,让d3 判断绑定数据的改变,然后去更新view。

d3的用法类似react 

selection.data()   类似react的虚拟dom。 enter()  exit() 子集类似diff 处理的callback。

这样,可以把d3渲染功能封到1个service里。svg的操作部分在web组件里就没有了,在生命周期钩子里调用服务即可。

 

定制d3导入子模块,attrs:

一般用d3 都是:

import * as d3 from 'd3';

但是有2个问题:

1 d3现在特别大,这样import的绝大多数用不上,没必要

2 d3的子模块太多了,默认并没有把全部子模块都安装上,我很喜欢用的 .attrs()多个属性,就在d3-selection-multi里,默认安装d3是没有安装这个的。

想用这个,要手工安装

npm i d3-selection-multi

d3 官网https://github.com/d3/d3 只给出了node下的导入方式:

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

在ts里要稍微变一下, 不得不每个命名1次,然后再Object.assign({}

import * as d3Selection from 'd3-selection';
import * as d3Attrs from 'd3-selection-multi';
import * as d3Geo from 'd3-geo';
export const d3 = Object.assign({}, d3Selection, d3Attrs, d3Geo);

然后后面就照用了。我用了export导出,可以给别的模块用。

 

ng使用d3.select()的渲染时机:

要在 ngAfterViewInit之后,不然view还没创建好 选不到任何元素。

 

svg的style

参考https://stackoverflow.com/questions/36214546/styles-in-component-for-d3-js-do-not-show-in-angular-2/36214723#36214723

  这个略坑。很多地方给出的解决方案是在组件元数据里设置:

encapsulation: ViewEncapsulation.None,

但这样的坏处是,d3.select('svg') 会找到全局全部svg,我恰好全局有多张svg,结果选中了多个组件里的svg。后面的数据绑定到每个svg上去了。(刚开始还怀疑是不是负责d3渲染的service是不是每个组件都要单独注入一个,后来一想这样太傻了,不可能。)

1 如果设置

ViewEncapsulation.None
那么,选中svg元素,就要设置一个id
    this.svg = d3.select(`#${this.name}`);
 
2如果不设置ViewEncapsulation.None
 那么 默认style没法应用到shallow dom的svg上
要这样改 组件里的.css 加一行:
::ng-deep
g#marsh path {
    fill: rgb(21, 63, 13);
    fill-opacity: 0.5;
    stroke: rgb(21, 63, 13);
    stroke-width: 3;
}

这样就OK了,个人认为这样最好。

——附注:ng7的 ViewEncapsulation 默认是 Emulated。

MemberDescription
Emulated: 0

Emulate Native scoping of styles by adding an attribute containing surrogate id to the Host Element and pre-processing the style rules provided via styles orstyleUrls, and adding the new Host Element attribute to all selectors.

This is the default option.

Native: 1  
None: 2

Don't provide any template or style encapsulation.

ShadowDom: 3

Use Shadow DOM to encapsulate styles.

For the DOM this means using modern Shadow DOM and creating a ShadowRoot for Component's Host Element.

默认效果用 ::ng-deep 就够了

Native在chrome 72上提示,马上要过期

None 说过了效果,各组件就串了,不推荐

ShadowDom    好像svg用不了。

 

posted @ 2019-03-18 15:29  永远的幻想  阅读(647)  评论(0编辑  收藏  举报