I have created polymer 1.x custom elements using d3 v3 before. I want to update them to polymer 3 and d3 v5.
Here is a base polymer 3 element that I want to include d3 v5 into:
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);
I call npm install d3
How shall I import d3 into this PolymerElement? I have two different types of polymer elements using d3. I have done both force and hierarchy polymer elements.
I am figuring that I need to do something in the constructor() or ready() functions within the polymer element to utilize the d3 library.
I was trying the following import:
import 'd3/dist/d3.js';
Since d3
has ship with ES Modules. So you can import as you want.
import { select, scaleOrdinal } from 'd3'
// or
import * as d3 from 'd3'
Then you can use d3
as usual.
Example:
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)
Note: Polymer use Shadow DOM which normal selector (e.g. d3.select
) cannot go through.
In this example I modify from Force-Directed Graph.