This example is using the d3.behavior.drag for moving a line via the line endpoints.
The example is using web component architecture (The library is: Polymer project)
This example is fork
The original example is: Moving the line via endpoints
| license: gpl-3.0 |
This example is using the d3.behavior.drag for moving a line via the line endpoints.
The example is using web component architecture (The library is: Polymer project)
This example is fork
The original example is: Moving the line via endpoints
| x1 | y1 | x2 | y2 | |
|---|---|---|---|---|
| 350 | 15 | 250 | 33 | |
| 420 | 420 | 250 | 333 | |
| 140 | 120 | 220 | 220 | |
| 180 | 55 | 330 | 320 | |
| 200 | 260 | 150 | 180 |
| <!DOCTYPE html> | |
| <meta charset="utf-8"> | |
| <script src="//polygit.org/components/webcomponentsjs/webcomponents-lite.min.js"></script> | |
| <link rel="import" href="line-endpoints.html"> | |
| <body> | |
| <script src="//d3js.org/d3.v3.min.js"></script> | |
| <line-endpoints></line-endpoints> |
| <link rel="import" href="//polygit.org/components/polymer/polymer.html"> | |
| <dom-module id="line-endpoints"> | |
| <template> | |
| <style> | |
| :host { | |
| position: relative; | |
| display: block; | |
| } | |
| :host line { | |
| shape-rendering: crispEdges; | |
| vector-effect: non-scaling-stroke; | |
| stroke: #000; | |
| stroke-width: 2px; | |
| } | |
| :host circle { | |
| shape-rendering: crispEdges; | |
| vector-effect: non-scaling-stroke; | |
| fill: lightsteelblue; | |
| stroke: steelblue; | |
| stroke-width: 1.5px; | |
| } | |
| :host circle:hover { | |
| cursor: pointer; | |
| } | |
| :host circle.active-d3-item { | |
| fill: red; | |
| } | |
| </style> | |
| </template> | |
| <script> | |
| Polymer({ | |
| is: 'line-endpoints', | |
| properties: { | |
| dimensions: { | |
| type: Object, | |
| value: { | |
| width: 960, | |
| height: 500 | |
| } | |
| }, | |
| svg: { | |
| type: Object | |
| }, | |
| data: { | |
| type: Array | |
| }, | |
| lines: { | |
| type: Object | |
| } | |
| }, | |
| observers: [ | |
| 'dataIsUpdated(data)' | |
| ], | |
| getActiveClassName: function() { | |
| return 'active-d3-item'; | |
| }, | |
| ready: function() { | |
| this.drawSVG(); | |
| // Get the csv information about the lines coordinates | |
| this.getData(); | |
| }, | |
| /** | |
| * Method is drawing a svg using reference to the current element | |
| */ | |
| drawSVG: function() { | |
| this.svg = d3.select(this) | |
| .append('svg') | |
| .attr('width', this.dimensions.width) | |
| .attr('height', this.dimensions.height); | |
| this.updateStyles(); | |
| }, | |
| /** | |
| * WARNING: | |
| * | |
| * If the subtree that you scope contains any Polymer elements with | |
| * local DOM, scopeSubtree will cause the descendants' | |
| * local DOM to be styled incorrectly. | |
| * | |
| * @see https://www.polymer-project.org/1.0/docs/devguide/styling | |
| */ | |
| updateStyles: function() { | |
| this.scopeSubtree(this, true); | |
| }, | |
| getData: function() { | |
| var self = this; | |
| d3.csv('data.csv', function (error, data) { | |
| self.data = data; | |
| }); | |
| }, | |
| /** | |
| * @param {Array} data Each array element has an Object. Object keys are line coordinates (x1, y1, x2, y2) | |
| */ | |
| dataIsUpdated: function(data) { | |
| // Draw svg lines | |
| this.drawLines(); | |
| // Draw lines endpoints | |
| this.drawEndPoints(); | |
| }, | |
| drawLines: function() { | |
| var lineAttributes = this.getLineAttributes(); | |
| this.lines = this.svg | |
| .selectAll('line') | |
| .data(this.data) | |
| .enter() | |
| .append('line') | |
| .attr(lineAttributes); | |
| }, | |
| /** | |
| * Method is generating the svg lines attributes | |
| */ | |
| getLineAttributes() { | |
| return { | |
| 'x1': function(d) { | |
| return d.x1; | |
| }, | |
| 'y1': function(d) { | |
| return d.y1; | |
| }, | |
| 'x2': function(d) { | |
| return d.x2; | |
| }, | |
| 'y2': function(d) { | |
| return d.y2; | |
| } | |
| }; | |
| }, | |
| drawEndPoints: function() { | |
| // Get the end points data | |
| var data = this.generateEndPointsData(); | |
| // Get the end points attributes | |
| var attributes = this.getEndPointsAttributes(); | |
| var drag = this.getDragBehavior(); | |
| var circles = this.svg | |
| .selectAll('circle') | |
| .data(data) | |
| .enter() | |
| .append('circle') | |
| .attr(attributes) | |
| .call(drag); | |
| }, | |
| /** | |
| * Method is interacting the line items and create: | |
| * 1. Array with x1 and y1 coordinates | |
| * 2. Array with x2 and y2 coordinates | |
| */ | |
| generateEndPointsData: function() { | |
| var topEndPoints = this.data.map(function(line, i) { | |
| return { | |
| 'x': line.x1, | |
| 'y': line.y1, | |
| 'marker': 'marker-start', | |
| 'lineIndex': i | |
| }; | |
| }); | |
| var bottomEndPoints = this.data.map(function(line, i) { | |
| return { | |
| 'x': line.x2, | |
| 'y': line.y2, | |
| 'marker': 'marker-end', | |
| 'lineIndex': i | |
| } | |
| }); | |
| return topEndPoints.concat(bottomEndPoints); | |
| }, | |
| /** | |
| * Method is generating the svg circles / end points attributes | |
| * | |
| * @return {Object} keys are r, cx and cy | |
| */ | |
| getEndPointsAttributes: function() { | |
| return { | |
| 'r': 7, | |
| 'cx': function(d) { | |
| return d.x; | |
| }, | |
| 'cy': function(d) { | |
| return d.y; | |
| } | |
| }; | |
| }, | |
| getDragBehavior: function() { | |
| var self = this; | |
| var drag = d3.behavior.drag() | |
| .origin(function(d) { return d; }) | |
| .on('dragstart', function() { | |
| self.dragstarted(this); | |
| }) | |
| .on('drag', function(d, i) { | |
| self.dragged(this, d, i); | |
| }) | |
| .on('dragend', function() { | |
| self.dragended(this); | |
| }); | |
| return drag; | |
| }, | |
| /** | |
| * @param {D3CircleEventObject} item | |
| */ | |
| dragstarted: function(item) { | |
| d3.select(item).classed(this.getActiveClassName(), true); | |
| }, | |
| /** | |
| * @param {D3CircleEventObject} item | |
| * @param {Object} d reference to the backend circle item | |
| * @param {Integer} i circle index | |
| */ | |
| dragged: function(item, d, i) { | |
| var marker = d3.select(item); | |
| // Update the marker properties | |
| marker | |
| .attr('cx', d.x = d3.event.x) | |
| .attr('cy', d.y = d3.event.y); | |
| // Update the line properties | |
| this.lines | |
| .filter(function(lineData, lineIndex) { | |
| return lineIndex === d.lineIndex; | |
| }) | |
| .attr('x1', function(lineData) { | |
| return d.marker === 'marker-start' ? lineData.x1 = d.x : lineData.x1; | |
| }) | |
| .attr('y1', function(lineData) { | |
| return d.marker === 'marker-start' ? lineData.y1 = d.y : lineData.y1; | |
| }) | |
| .attr('x2', function(lineData) { | |
| return d.marker === 'marker-end' ? lineData.x2 = d.x : lineData.x2; | |
| }) | |
| .attr('y2', function(lineData) { | |
| return d.marker === 'marker-end' ? lineData.y2 = d.y : lineData.y2; | |
| }); | |
| }, | |
| /** | |
| * @param {D3CircleEventObject} item | |
| */ | |
| dragended: function(item) { | |
| d3.select(item).classed(this.getActiveClassName(), false); | |
| } | |
| }); | |
| </script> | |
| </dom-module> |