block by fil 6d0abd3e94aff9ff40eb85e33a11f31b

LAP-JV

Full Screen

LAP-JV

Linear Assignment Problem — algorithm by R. Jonker and A. Volgenant

Ported to javascript by Philippe Rivière, from the C++ implementation found at https://github.com/yongyanghz/LAPJV-algorithm-c

See Fil/lap-jv for details.

See also LAP-JV Worker.

Using d3-annotation() by @susielu.

index.html

<!DOCTYPE html>
<head>
  <meta charset="utf-8">
  <script src="https://d3js.org/d3.v4.min.js"></script>
  <script src="https://raw.githack.com/Fil/lap-jv/master/lap.js"></script>
<script src="https://raw.githack.com/susielu/d3-annotation/master/d3-annotation.js"></script> 
  <!-- <link rel="stylesheet" href="https://cdn.rawgit.com/susielu/d3-annotation/master/d3-annotation-styles.css">  -->
<link rel="stylesheet" href="d3-annotation.css">  
  <style>
    body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
  </style>
</head>

<body>
  <script>
    // Feel free to change or delete any of the code you see in this editor!
    var svg = d3.select("body").append("svg")
      .attr("width", 960)
      .attr("height", 500)

    const m = 7, n = m * m, w = Math.ceil(440/m);
    
    const data = d3.range(n).map(k => [m * Math.random(), m * Math.random()]);
    
    data.map(d => d.color = d3.rgb(Math.random()*255, Math.random()*255, Math.random()*255));
    
    svg.selectAll('line') 
    .data(data)
    .enter()
    .append('line')

    svg.selectAll('circle')
    .data(data)
    .enter()
    .append('circle')
    .attr('r', 13)
    .attr('cx', d => w * d[0])
    .attr('cy', d => w * d[1])
    .attr('fill', d => d.color)
    .attr('fill-opacity', 0.5);

    const costs = data.map(d => d3.range(n).map( k => {
      const i = k % m, j = (k-i)/m;
      const dx = d[0] - i - 0.5, dy = d[1] - j - 0.5;
      return dx * dx + dy * dy;
    }));

    draw(lap(n, costs));

function draw(res) {
    res.col.map((c, k) => {
      const i = k % m, j = (k-i)/m;
      data[c].i = i;
      data[c].j = j;
      data[c].cost = costs[c][k];
    });
 

  svg.selectAll('line')
    .attr('x1', d => w * d[0])
    .attr('y1', d => w * d[1])
    .attr('x2', d => w * d[0])
    .attr('y2', d => w * d[1])
    .attr('stroke', d => d.color)
    .attr('opacity', 0.8)
    .transition()
    .duration(1500)
    .attr('x2', d => w/2 + w * d.i)
    .attr('y2', d => w/2 + w * d.j)
    ;

    setTimeout(function() {
      svg.selectAll('circle')
       .transition()
       .duration(500)
       .attr('cx', d => w/2 + w * d.i)
       .attr('cy', d => w/2 + w * d.j);

    }, 1500);
  
  const max = d3.scan(data.map(d => -d.cost)),
        annotation = d3.annotation()
        .type(d3.annotationCalloutCircle)
        .annotations(
          [data[max]]
          .map(d => {
           return {
            data: d,
            dx: 25,
            dy: 15,
            note: {
               title: "Most expensive attribution",
               label: "cost: "+ d3.format('$0.2f')(Math.sqrt(d.cost)),
            },
            subject: {
              radius: 17,
              radiusPadding: 2,
            },
          }
        }))
        .accessors({ x: d => w/2 + w * d.i, y: d =>  w/2 + w * d.j })

   setTimeout(() => {
    svg.append("g")
        .attr("class", "annotation-centroids")
        .call(annotation)    
   }, 1800)
  }

  
  </script>
</body>

d3-annotation.css

:root {
    --accent-color: #0c6e64;
}

.annotation-note-bg {
  fill: none;
}
.annotation path {
  stroke: var(--accent-color);
  fill: none;
}

.annotation text,
.annotation .annotation-connector .connector-dot,
.annotation path.connector-arrow{
  fill: var(--accent-color);
  font-family: sans-serif;
}

.annotation-note-title {
  font-weight: bold;
}

.annotation.badge path.subject-pointer, .annotation.badge path.subject {
  fill: var(--accent-color);
  stroke-width: 3px;
  stroke-linecap: round;
} 

.annotation.badge path.subject-ring {
  fill: white;
  stroke-width: 3px;
}

.annotation.badge .badge-text {
  fill: white;
  font-size: .7em;
}

/* Handling edit mode styles */
.editable .annotation-subject, .editable .annotation-note {
  cursor: move;
}

circle.handle {
  stroke-dasharray: 5;
  stroke: var(--accent-color);
  fill: rgba(255, 255, 255, .2);
  cursor: move;

  stroke-opacity: .4;
}