Skip to content

Instantly share code, notes, and snippets.

@sgpinkus
Last active March 11, 2017 06:12
Show Gist options
  • Save sgpinkus/fe019e73011a40f2978740b907e95b8f to your computer and use it in GitHub Desktop.
Save sgpinkus/fe019e73011a40f2978740b907e95b8f to your computer and use it in GitHub Desktop.
utility-function-editor-mock
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Spline Curve Editor</title>
<style>
* { border: 0; padding: 0; margin: 0; }
html, body { height: 100%; }
body {
font: 13px sans-serif;
position: relative;
}
article { display:flex; flex-flow: row nowrap; }
article { margin:auto auto; }
form {
position: absolute;
bottom: 10px;
left: 10px;
}
rect {
fill: none;
pointer-events: all;
}
circle,
.line {
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
}
circle {
fill: #fff;
fill-opacity: .2;
cursor: move;
}
.selected {
fill: #ff7f0e;
stroke: #ff7f0e;
}
svg {
border: solid 1px #000;
}
.level-canvas rect {
fill: steelblue;
}
.level-canvas text {
fill: white;
font: 10px sans-serif;
text-anchor: end;
}
</style>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var width = 840;
var height = 400;
var margin = 50;
var sum = 0;
var points = [
[10,height-margin],
[width*(0.25),(height-margin)/2],
[width*(0.50),margin],
[width*(0.75),(height-margin)/2],
[width-10,height-margin]
];
points = points.map((p, i) => { return {i:i, x:p[0], y:p[1]}; });
var dragged = null;
var selected = null;
var line;
var svg;
function init() {
d3.select(window)
.on("mousemove", mousemove)
.on("mouseup", mouseup)
d3.select("#interpolate")
.on("change", change)
.selectAll("option")
.data([
"cardinal",
"cardinal-open",
"cardinal-closed",
"linear",
"step-before",
"step-after",
"basis",
"basis-open",
"basis-closed",
"monotone"
])
.enter().append("option")
.attr("value", function(d) { return d; })
.text(function(d) { return d; });
line = d3.svg.line();
d3.select(".level-canvas")
.attr("width", 100)
.attr("height", height)
.attr("tabindex", 2)
.append("g")
svg = d3.select(".main-canvas")
.attr("width", width)
.attr("height", height)
.attr("tabindex", 1);
svg.append("rect")
.attr("width", width)
.attr("height", height)
.on("mousedown", mousedown);
svg.append("path")
.datum(points.map((n) => {return [n.x,n.y];}))
.attr("class", "line")
.call(redraw);
line.interpolate("cardinal");
redraw();
}
/**
* Redraw and also init the canvas
*/
function redraw() {
bounds()
sum = width*height - integrate_polyline(points.map((n) => {return [n.x,n.y];}));
console.log(sum, width*height)
svg.select("path").datum(points.map((n) => {return [n.x,n.y];})).attr("d", line);
var circle = svg.selectAll("circle").data(points);
circle.enter().append("circle")
.attr("r", 1e-6)
.on("mousedown", function(d) { selected = dragged = d; redraw(); })
.transition()
.duration(750)
.ease("elastic")
.attr("r", 6.5)
circle
.classed("selected", function(d) { return d === selected; })
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
circle.exit().remove();
var bar = d3.select(".level-canvas g").selectAll("rect").data([sum/(width*height)])
bar.enter()
.append("rect")
bar.attr("width", "100%")
.attr("height", function(d) { return d*height;})
.attr("transform", function(d) { return "translate(0," + ( height - d*height ) + ")"; });
if (d3.event) {
d3.event.preventDefault();
d3.event.stopPropagation();
}
}
/**
* Ensure points are within bounds.
* In x: min < s1 < peak < s2 < max.
* In y: min and max are pinned to base, peak pinned to top.
*/
function bounds() {
points = points.map((p,i) => {
p.x = Math.min(Math.max(p.x, (i+1)*margin), width-(points.length-i)*margin)
p.y = Math.min(Math.max(p.y, margin), height-margin)
return p;
})
points[0].y = height-margin
points[1].y = Math.max(points[1].y, margin*2)
points[2].y = margin
points[3].y = Math.max(points[3].y, margin*2)
points[4].y = height-margin
if (!dragged) return;
for(i = 0; i < points.length; i++) {
gap = i - dragged.i
if(gap > 0) {
points[i].x = Math.max(points[i].x, dragged.x+gap*margin)
}
else if(gap < 0) {
points[i].x = Math.min(points[i].x, dragged.x+gap*margin)
}
}
}
function change() {
line.interpolate(this.value);
redraw();
}
function mousedown() {
redraw();
}
function mousemove() {
if (!dragged) return;
var m = d3.mouse(svg.node());
var d = dragged
dragged.x = Math.max(0, Math.min(width, m[0]));
dragged.y = Math.max(0, Math.min(height, m[1]));
redraw();
}
function mouseup() {
dragged = null;
selected = null;
redraw();
}
function integrate_polyline(l) {
sum = 0;
step = 1;
for(var i = 1; i < l.length; i++) {
xa = l[i-1][0], xb = l[i][0], ya = l[i-1][1], yb = l[i][1];
if(xb <= xa)
throw new Error("List must have strictly increasing x values")
b = xb-xa
h = ya
sum += b*h + (b*(yb-ya)*0.5)
}
return sum
}
</script>
</head>
<body onload="init()">
<article>
<svg class="main-canvas"></svg>
<svg class="level-canvas"></svg>
<form>
<label for="interpolate">Interpolate:</label>
<select id="interpolate"></select><br>
</form>
</article>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment