Skip to content

Instantly share code, notes, and snippets.

@dimitardanailov
Last active January 5, 2017 18:20
Show Gist options
  • Select an option

  • Save dimitardanailov/556ff8797ba3f8a38fb8b9f79752ddff to your computer and use it in GitHub Desktop.

Select an option

Save dimitardanailov/556ff8797ba3f8a38fb8b9f79752ddff to your computer and use it in GitHub Desktop.
D3js and Polymer Web Components (Moving the line via endpoints)
license: gpl-3.0
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment