Skip to content

Instantly share code, notes, and snippets.

@emeeks
Last active June 4, 2016 00:31
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 emeeks/14c4e5a2ea7cabc7e6f1e33cd61dc6b1 to your computer and use it in GitHub Desktop.
Save emeeks/14c4e5a2ea7cabc7e6f1e33cd61dc6b1 to your computer and use it in GitHub Desktop.
Divided Line

Here's an initial stab at building a Divided Line generator. The basic idea is to create a generator that takes a set of parameters and returns an array of coordinates corresponding to the segments of that line that exist within the parameters sent. In this example, I sample the previous point along with the first one so that the corresponding line can be drawn from the earlier position to the current one. Notice with the cardinal interpolation that the line doesn't interpolate properly at the junctions between the lines (the original interpolation is drawn as the black background line). This is more pronounced with basis interpolation.

Most of the code is for randomly generating points and bounding boxes...

<html>
<head>
<title>Divided Lines</title>
<meta charset="utf-8" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.16/d3.min.js"></script>
</head>
<style>
svg {
height: 500px;
width: 500px;
border: 1px solid gray;
}
</style>
<body>
<div id="viz">
<svg class="main">
</svg>
</div>
</body>
<footer>
<script>
function dividedLine(parameters, points) {
var currentParameters = parameters(points[0])
var currentPointsArray = []
dividedLinesData = [{dividedResponse: currentParameters, points: currentPointsArray}]
points.forEach(function (point, i) {
var newParameters = parameters(point)
if (newParameters === currentParameters) {
currentPointsArray.push(point)
}
else {
var lastPoint = currentPointsArray[currentPointsArray.length - 1];
currentPointsArray = [lastPoint, point]
dividedLinesData.push({dividedResponse: newParameters, points: currentPointsArray})
currentParameters = newParameters
}
})
return dividedLinesData.filter(function (d) {return d.points.length > 1})
}
function randomLineGenerator(width, height, points) {
var pointDataSet = []
var curY = 0.5
for (var x = 0; x< points; x++) {
curY += Math.random() * 0.3 - 0.15;
curY = Math.max(curY, 0.05)
curY = Math.min(curY, 0.95)
pointDataSet.push({ x: x / points * width, y: curY * height })
}
return pointDataSet
}
function randomBoundingBoxes(width, height, boxes) {
var column = height / boxes;
var boundingBoxes = []
for (var x = 0; x< boxes; x++) {
var x1 = 0
var y1 = column * x
var x2 = width
var y2 = y1 + column
boundingBoxes.push([[x1,y1],[x2,y2]])
}
return boundingBoxes
}
var lineData = randomLineGenerator(500,500,100);
var boundingBoxes = randomBoundingBoxes(500,500,4);
function parametersFromBoundingBoxes(point) {
var bbResponse = 1;
boundingBoxes.forEach(function (bb, i) {
if (point.x >= bb[0][0] && point.x <= bb[1][0] && point.y >= bb[0][1] && point.y <= bb[1][1]) {
bbResponse = i + 2
return
}
})
return bbResponse
}
var line = d3.svg.line()
.x(function (d) {return d.x})
.y(function (d) {return d.y})
.interpolate("cardinal")
d3.select("svg")
.append("path")
.attr("d", line(lineData))
.style("fill", "none")
.style("stroke", "black")
.style("stroke-width", 1)
d3.select("svg")
.selectAll("rect")
.data(boundingBoxes)
.enter()
.append("rect")
.attr("x", function (d) {return d[0][0]})
.attr("y", function (d) {return d[0][1]})
.attr("width", function (d) {return d[1][0] - d[0][0]})
.attr("height", function (d) {return d[1][1] - d[0][1]})
.style("fill", "yellow")
.style("stroke", "gray")
.style("fill-opacity", 0)
.style("stroke-opacity", 0)
var dLineData = dividedLine(parametersFromBoundingBoxes, lineData);
var color = d3.scale.category20()
d3.select("svg")
.selectAll("path.segment")
.data(dLineData)
.enter()
.append("path")
.attr("d", function (d) {return line(d.points)})
.style("fill", "none")
.style("stroke", function (d) {return d.dividedResponse ? color(d.dividedResponse) : "none"})
.style("stroke-width", 8)
.style("stroke-opacity", 0.75)
</script>
</footer>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment