How to implement D3 for Vue.js

There are various implementations of D3 with React. One of the most interesting uses the reaction-faux-dom project. The advantages of this approach are that React knows about the DOM elements created by D3 and the possibility of creating isomorphic diagrams.

Refer to the following:

What does it take to implement D3 in Vue.js with the same benefits?

Is there a need to create something similar to a faux-dom reaction, or does Vue already have something to use for this?

How does this approach make sense (or not) given the Vues architecture?

+6
source share
2 answers

Starting with version 4, D3 is highly modular, and the computing parts are well isolated by small librairies, such as d3-force . One approach that I like is to let Vue.js handle DOM and event manipulation and use d3.js for computation. The visualization component is similar to your other components and is easier to understand for someone familiar with Vue.js but not d3.js.

I created a codepen to show the implementation of a power graph:

HTML:

<div id="app"> <svg xmlns="http://www.w3.org/2000/svg" :width="width+'px'" :height="height+'px'" @mousemove="drag($event)" @mouseup="drop()" v-if="bounds.minX"> <line v-for="link in graph.links" :x1="coords[link.source.index].x" :y1="coords[link.source.index].y" :x2="coords[link.target.index].x" :y2="coords[link.target.index].y" stroke="black" stroke-width="2"/> <circle v-for="(node, i) in graph.nodes" :cx="coords[i].x" :cy="coords[i].y" :r="20" :fill="colors[Math.ceil(Math.sqrt(node.index))]" stroke="white" stroke-width="1" @mousedown="currentMove = {x: $event.screenX, y: $event.screenY, node: node}"/> </svg> </div> 

Javascript:

 new Vue({ el: '#app', data: { graph: { nodes: d3.range(100).map(i => ({ index: i, x: null, y: null })), links: d3.range(99).map(i => ({ source: Math.floor(Math.sqrt(i)), target: i + 1 })) }, width: Math.max(document.documentElement.clientWidth, window.innerWidth || 0), height: Math.max(document.documentElement.clientHeight, window.innerHeight || 0) - 40, padding: 20, colors: ['#2196F3', '#E91E63', '#7E57C2', '#009688', '#00BCD4', '#EF6C00', '#4CAF50', '#FF9800', '#F44336', '#CDDC39', '#9C27B0'], simulation: null, currentMove: null }, computed: { bounds() { return { minX: Math.min(...this.graph.nodes.map(n => nx)), maxX: Math.max(...this.graph.nodes.map(n => nx)), minY: Math.min(...this.graph.nodes.map(n => ny)), maxY: Math.max(...this.graph.nodes.map(n => ny)) } }, coords() { return this.graph.nodes.map(node => { return { x: this.padding + (node.x - this.bounds.minX) * (this.width - 2*this.padding) / (this.bounds.maxX - this.bounds.minX), y: this.padding + (node.y - this.bounds.minY) * (this.height - 2*this.padding) / (this.bounds.maxY - this.bounds.minY) } }) } }, created(){ this.simulation = d3.forceSimulation(this.graph.nodes) .force('charge', d3.forceManyBody().strength(d => -100)) .force('link', d3.forceLink(this.graph.links)) .force('x', d3.forceX()) .force('y', d3.forceY()) }, methods: { drag(e) { if (this.currentMove) { this.currentMove.node.fx = this.currentMove.node.x - (this.currentMove.x - e.screenX) * (this.bounds.maxX - this.bounds.minX) / (this.width - 2 * this.padding) this.currentMove.node.fy = this.currentMove.node.y -(this.currentMove.y - e.screenY) * (this.bounds.maxY - this.bounds.minY) / (this.height - 2 * this.padding) this.currentMove.x = e.screenX this.currentMove.y = e.screenY } }, drop(){ delete this.currentMove.node.fx delete this.currentMove.node.fy this.currentMove = null this.simulation.alpha(1) this.simulation.restart() } } }) 

The main drawback that I see is that you have a large d3.js database that you want to reuse in your Vue.js application, since you will have to rewrite it. You will also find many examples written in pure d3.js syntax, and you will have to adapt them.

+11
source

Nicholas Bonnel: That's great - thanks a lot! The codepen example was a particular pleasure. Note that I get the error message β€œd3.range is not a function” until I added:

Best wishes!

0
source

Source: https://habr.com/ru/post/1261064/


All Articles