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.
| license: mit | |
| border: no |
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.
| :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; | |
| } |
| <!DOCTYPE html> | |
| <head> | |
| <meta charset="utf-8"> | |
| <script src="https://d3js.org/d3.v4.min.js"></script> | |
| <script src="https://cdn.rawgit.com/Fil/lap-jv/master/lap.js"></script> | |
| <script src="https://cdn.rawgit.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> |