block by emeeks 03396c05b39b8198685f3e46942c87e3

Divided Line II

Full Screen

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.

index.html

<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>