Skip to content

Instantly share code, notes, and snippets.

@emeeks
Last active June 6, 2016 16:35
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save emeeks/03396c05b39b8198685f3e46942c87e3 to your computer and use it in GitHub Desktop.
Save emeeks/03396c05b39b8198685f3e46942c87e3 to your computer and use it in GitHub Desktop.
Divided Line II

An improved divided line generator. This one uses a simple search function to find the point closest to the parameterized space that determines where lines are being divided. In this example there are four parameters: Before a certain point gets a thick grey line, above a certain threshold gets a red line, below a certain threshold gets a green line and past a certain point gets a dashed line.

<html>
<head>
<title>Divided Lines II</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 = [{key: [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];
var pointA = lastPoint;
var pointB = point;
for (var x = 0; x<10; x++) {
var findPoints = simpleSearchFunction(pointA, pointB, currentParameters, parameters)
pointA = findPoints[0]
pointB = findPoints[1]
}
currentPointsArray.push(pointB)
currentPointsArray = [pointB, point]
dividedLinesData.push({key: [newParameters], points: currentPointsArray})
currentParameters = newParameters
}
})
return dividedLinesData.filter(function (d) {return d.points.length > 1})
}
function simpleSearchFunction(pointA, pointB, current, parameters) {
var pointCX = (pointA.x + pointB.x) / 2
var pointCY = (pointA.y + pointB.y) / 2
if (parameters({x: pointCX, y: pointCY}) === current) {
return [{x: pointCX, y: pointCY}, pointB]
}
return [pointA, {x: pointCX, y: pointCY}]
}
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 parameters(point) {
if (point.x < 100) {
return "before"
}
if (point.x > 400) {
return "after"
}
if (point.y < 150) {
return "above"
}
if (point.y > 350) {
return "below"
}
return "normal"
}
var styleMap = {
before: {"stroke-width": 6, "stroke-opacity": 0.5},
after: {"stroke-dasharray": "5 5"},
above: {stroke: "red"},
below: {stroke: "green"},
normal: {}
}
var lineData = randomLineGenerator(500,500,100);
var line = d3.svg.line()
.x(function (d) {return d.x})
.y(function (d) {return d.y})
.interpolate("basis")
var dLineData = dividedLine(parameters, 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)})
.each(function (d){
var baseStyle = {fill: "none", stroke: "black", "stroke-width": 2}
d.key.forEach(function (p) {
Object.assign(baseStyle, styleMap[p])
})
d3.select(this).style(baseStyle)
})
</script>
</footer>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment