Skip to content

Instantly share code, notes, and snippets.

@jebeck
Last active August 29, 2015 14:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jebeck/d15be2c0ace80aef3503 to your computer and use it in GitHub Desktop.
Save jebeck/d15be2c0ace80aef3503 to your computer and use it in GitHub Desktop.
playing with SVG line markers in D3

SVG Line Markers

This is a quick exploration of SVG circle line markers (with a transparent line) as an alternative to drawing many circles.

With constantly updating data, this seems to render quite a bit smoother than circles, with the FPS only dropping below ~40 at about 600 items.

Disclaimer: Not (yet) a scientific study ;)

<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='utf-8'>
<title>
Line Markers in D3
</title>
<script src='http://d3js.org/d3.v3.min.js' charset='utf-8'></script>
<style type='text/css'>
svg {
display: block;
margin: 0 auto;
}
.axis path, .axis line {
fill: none;
stroke: #594E4D;
shape-rendering: crispEdges;
}
.axis text {
fill: #594E4D;
font-family: sans-serif;
font-size: 14px;
font-weight: bold;
}
#lineGraph {
stroke: rgba(0,0,0,0);
stroke-width: 2;
fill: none;
marker-start: url(#circle);
marker-mid: url(#circle);
marker-end: url(#circle);
}
.circleMarker {
stroke: none;
opacity: 0.5;
fill: #BF6989;
}
.transient {
fill: #D9C7C7;
stroke: #97A676;
stroke-width: 5px;
}
</style>
</head>
<body>
<script type='text/javascript'>
var margin = {top: 20, right: 15, bottom: 20, left: 40};
var width = 555 - margin.left - margin.right;
var height = 440 - margin.top - margin.bottom;
var random = d3.random.normal(5, 2);
var data = [];
for (var i = 0; i < Math.floor(Math.random() * 101); i++) {
data.push(random());
}
function markers() {
var svg = d3.select('body')
.append('svg')
.attr({
'width': width + margin.left + margin.right,
'height': height + margin.top + margin.bottom
})
.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
d3.select('svg').insert('defs', 'g')
.append('marker')
.attr({
id: 'circle',
markerWidth: 8,
markerHeight: 8,
refX: 5,
refY: 5
})
.append('circle')
.attr({
cx: 5,
cy: 5,
r: 2.5,
'class': 'circleMarker'
});
svg.append('clipPath')
.attr('id', 'activeGraphArea')
.append('rect')
.attr({
width: width,
height: height,
x: 0,
y: 0
});
svg.append('rect')
.attr({
width: width,
height: height,
x: 0,
y: 0,
fill: '#F8F8F8'
});
var xScale = d3.scale.linear().domain([0, data.length]).range([0, width]);
var xAxis = d3.svg.axis().scale(xScale).orient('bottom');
svg.append('g')
.attr({
'class': 'x axis',
'transform': 'translate(0,' + height + ')'
})
.call(xAxis);
var yScale = d3.scale.linear().domain([0, d3.max(data)]).range([height, 0]);
var yAxis = d3.svg.axis().scale(yScale).orient('left');
svg.append('g')
.attr({
'class': 'y axis'
})
.call(yAxis);
var line = d3.svg.line()
.x(function(d, i) { return xScale(i); })
.y(function(d) { return yScale(d); })
.interpolate('linear');
svg.append('path')
.attr({
d: line(data),
id: 'lineGraph',
'clip-path': 'url(#activeGraphArea)'
});
return function() {
xScale.domain([0, data.length]);
yScale.domain([0, d3.max(data)]);
xAxis.scale(xScale);
yAxis.scale(yScale);
svg.select('.x.axis').transition().call(xAxis);
svg.select('.y.axis').transition().call(yAxis);
var latest = data[data.length -1];
svg.append('circle')
.attr({
cx: xScale(data.length - 1),
cy: yScale(latest),
r: 15,
'class': 'transient'
})
.transition()
.duration(1000)
.attr('r', 0)
.remove();
svg.select('#lineGraph').transition().attr('d', line(data))
.attr('clip-path', 'url(#activeGraphArea)');
};
}
var addData = function() {
data.push(random());
update();
};
setInterval(addData, 25);
update = markers();
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment