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