如何将 d3.js v5 模块导入到聚合物 3 元素中?

How to import the d3.js v5 module into a polymer 3 element?

我之前使用 d3 v3 创建了聚合物 1.x 自定义元素。我想将它们更新为 polymer 3 和 d3 v5。

这是我想将 d3 v5 包含在其中的基础聚合物 3 元素:

import {html, PolymerElement} from '@polymer/polymer/polymer-element.js';

/**
 * `foo-bar`
 * 
 *
 * @customElement
 * @polymer
 * @demo demo/index.html
 */
class FooBar extends PolymerElement {
  static get template() {
    return html`
      <style>
        :host {
          display: block;
        }
      </style>
      <h2>Hello [[prop1]]!</h2>
    `;
  }
  static get properties() {
    return {
      prop1: {
        type: String,
        value: 'foo-bar',
      },
    };
  }
  constructor() {
    super();
  }

  ready() {
    super.ready();
    console.log('foo-bar is ready!');
  }

}

window.customElements.define('foo-bar', FooBar);

我打电话给npm install d3

如何将 d3 导入到这个 PolymerElement 中?我有两种不同类型的使用 d3 的聚合物元素。力和层级聚合物元素我都做过。

我想我需要在聚合物元素中的 constructor()ready() 函数中做一些事情以利用d3 库。

我正在尝试以下导入:

import 'd3/dist/d3.js';

因为 d3 已经附带了 ES 模块。所以你可以 import 随心所欲。

import { select, scaleOrdinal } from 'd3'
// or
import * as d3 from 'd3'

那你就可以照常使用d3了。

示例:

index.html

<foo-bar></foo-bar>
<script type='module' src='app.js'></script>

app.js

import { PolymerElement, html } from '@polymer/polymer/polymer-element.js'
import * as d3 from 'd3'

class FooBar extends PolymerElement {
  static get template () {
    return html`
      <style>
        .links line {
          stroke: #999;
          stroke-opacity: 0.6;
        }

        .nodes circle {
          stroke: #fff;
          stroke-width: 1.5px;
        }
      </style>

      <svg width='960' height='600'></svg>
    `
  }

  ready () {
    super.ready()
    this.initGraph()
  }

  initGraph () {
    let svg = d3.select(this.shadowRoot.querySelector('svg'))
    let width = +svg.attr('width')
    let height = +svg.attr('height')

    let color = d3.scaleOrdinal(d3.schemeCategory10)

    let simulation = d3.forceSimulation()
      .force('link', d3.forceLink().id(d => d.id))
      .force('charge', d3.forceManyBody())
      .force('center', d3.forceCenter(width / 2, height / 2))

    d3.json('miserables.json').then(graph => {
      let link = svg.append('g')
        .attr('class', 'links')
        .selectAll('line')
        .data(graph.links)
        .enter().append('line')
        .attr('stroke-width', d => Math.sqrt(d.value))

      let node = svg.append('g')
        .attr('class', 'nodes')
        .selectAll('circle')
        .data(graph.nodes)
        .enter().append('circle')
        .attr('r', 5)
        .attr('fill', d => color(d.group))
        .call(d3.drag()
          .on('start', dragstarted)
          .on('drag', dragged)
          .on('end', dragended))

      node.append('title').text(d => d.id)

      simulation.nodes(graph.nodes)
        .on('tick', () => {
          link
            .attr('x1', d => d.source.x)
            .attr('y1', d => d.source.y)
            .attr('x2', d => d.target.x)
            .attr('y2', d => d.target.y)
          node
            .attr('cx', d => d.x)
            .attr('cy', d => d.y)
        })

      simulation.force('link').links(graph.links)
    })

    function dragstarted (d) {
      if (!d3.event.active) simulation.alphaTarget(0.3).restart()
      d.fx = d.x
      d.fy = d.y
    }

    function dragged (d) {
      d.fx = d3.event.x
      d.fy = d3.event.y
    }

    function dragended (d) {
      if (!d3.event.active) simulation.alphaTarget(0)
      d.fx = null
      d.fy = null
    }
  }
}

customElements.define('foo-bar', FooBar)

注意:Polymer 使用普通选择器(例如 d3.select)无法通过的阴影 DOM。

在这个例子中,我修改自 Force-Directed Graph