Skip to content

Instantly share code, notes, and snippets.

@dgfitch
Last active April 3, 2019 17:26
Show Gist options
  • Save dgfitch/9d0b7f2dab80ab4ee1580aa5b50d5a6d to your computer and use it in GitHub Desktop.
Save dgfitch/9d0b7f2dab80ab4ee1580aa5b50d5a6d to your computer and use it in GitHub Desktop.
Draw your feels

Preliminary experimenting with d3, "draw your feelings"

<!DOCTYPE html>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<style>
html,
body {
height: 100%;
margin: 0;
overflow: hidden;
}
svg {
position: absolute;
}
</style>
<body>
<div id="visarea"></div>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
var drawlinePlot = function(draw=true,curve1=null,curve2=null,curve3=null,curve4=null){
$("#visarea").empty();
var margin = {top: 50, right: 40, bottom: 60, left: 75},
width = Math.min(window.innerWidth*.9,1000),
height = width*.6;
var x = d3.scaleLinear()
.domain([0, 1])
.range([0, width-margin.left-margin.right])
var y = d3.scaleLinear()
.domain([0, 1])
.range([height-margin.top-margin.bottom, 0])
var xticklabs = ["Start","End"]
var yticklabs = ["Low","High"]
var xAxis = d3.axisBottom(x)
.ticks(1)
.tickFormat(function(d,i){ return xticklabs[i] });
var yAxis = d3.axisLeft(y)
.ticks(1)
.tickFormat(function(d,i){ return yticklabs[i] });
var svg = d3.select("#visarea").append("svg")
.attr("width",width)
.attr("height",height)
.append("g")
.attr("class", "easel")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.append("rect")
.attr("width",width)
.attr("height",height)
.attr("fill","white");
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (height - margin.bottom - margin.top) + ")")
.call(xAxis)
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(0,0)")
.call(yAxis)
d3.selectAll(".tick")
.attr("font-size",18);
svg.append("text")
.attr("class", "xlabel")
.attr("text-anchor", "middle")
.attr("font-size",24)
.attr("x", (width-margin.left-margin.right)/2)
.attr("y", height-margin.top-margin.bottom+30)
.text("Time")
svg.append("text")
.attr("class", "ylabel")
.attr("text-anchor", "middle")
.attr("font-size",24)
.attr("x", -(height-margin.top-margin.left)/2)
.attr("y", -55)
.attr("transform", "rotate(-90)")
.text("Intensity");
if(draw){
var line = d3.line()
.curve(d3.curveBasis);
var xmin = 0;
svg.call(d3.drag()
.container(function() { return this; })
.subject(function() { var p = [d3.event.x, d3.event.y]; return [p, p]; })
.on("start", dragstarted));
function dragstarted() {
var valpos = d3.event.x>0 & d3.event.x<(width-margin.left-margin.right) & d3.event.y>0 & d3.event.y<(height-margin.bottom-margin.top);
if(valpos & draw){
var d = d3.event.subject,
active = svg.append("path").datum(d)
.attr("fill","none")
.attr("stroke","#0066ff")
.attr("stroke-width","5px")
.attr("stroke-linejoin","round")
.attr("stroke-linecap","round"),
x0 = d3.event.x,
y0 = d3.event.y;
curvals.push({"x":x0,"y":y0});
d3.event.on("drag", function() {
var x1 = d3.event.x,
y1 = d3.event.y,
dx = x1 - x0,
dy = y1 - y0;
var valpos = x1>xmin & x1<(width-margin.left-margin.right) & y1>0 & y1<(height-margin.bottom-margin.top);
if (valpos){
curvals.push({"x":x1,"y":y1});
xmin = x1;
if (dx * dx + dy * dy > 10) d.push([x0 = x1, y0 = y1]);
else d[d.length - 1] = [x1, y1];
active.attr("d", line);
}
});
d3.event.on("end", function(){
if (curvals.length>2){
draw = false;
// TODO: Here is where we prompt the user to say "DONE"
curvals = normDrawing(curvals,height-margin.top-margin.bottom);
drawlinePlot(false,curvals);
} else {
curvals = [];
drawlinePlot();
}
});
}
}
} else {
var line = d3.line()
.x(function(d) {return x(d["x"]); })
.y(function(d) {return y(d["y"]); })
.curve(d3.curveBasis);
if (curve1 != null){
svg.append("path").datum(curve1)
.attr("fill","none")
.attr("stroke","#0066aa")
.attr("stroke-width","7px")
.attr("stroke-linejoin","round")
.attr("stroke-linecap","round")
.attr('d',line);
}
if (curve2 != null){
var curve2c = [];
for (var i=0; i<100; i ++){
curve2c.push({"x":i/99,"y":curve2[i]});
}
svg.append("path").datum(curve2c)
.attr("fill","none")
.attr("stroke","#0000CD")
.attr("stroke-width","3px")
.attr("stroke-linejoin","round")
.attr("stroke-linecap","round")
.attr('d',line);
}
if (curve3 != null){
var curve3c = [];
for (var i=0; i<100; i ++){
curve3c.push({"x":i/99,"y":curve3[i]});
}
svg.append("path").datum(curve3c)
.attr("fill","none")
.attr("stroke","#DDA0DD")
.attr("stroke-width","3px")
.attr("stroke-linejoin","round")
.attr("stroke-linecap","round")
.attr('d',line);
}
if (curve4 != null){
var curve4c = [];
for (var i=0; i<100; i ++){
curve4c.push({"x":i/99,"y":curve4[i]});
}
svg.append("path").datum(curve4c)
.attr("fill","none")
.attr("stroke","#006400")
.attr("stroke-width","3px")
.attr("stroke-linejoin","round")
.attr("stroke-linecap","round")
.attr('d',line);
}
}
svg.on("click", function() {
if (!draw) {
draw = true;
curvals = [];
drawlinePlot();
}
});
}
var normDrawing = function(drawn,ymax){
cvxMax = d3.max(drawn, function(d) {return d.x});
cvxMin = d3.min(drawn, function(d) {return d.x});
cvyMax = d3.max(drawn, function(d) {return d.y});
cvyMin = d3.min(drawn, function(d) {return d.y});
for (var i = 0; i < drawn.length; i ++){
drawn[i]["x"] = (drawn[i]["x"]-cvxMin)/(cvxMax-cvxMin);
drawn[i]["y"] = 1-(drawn[i]["y"]/ymax);
}
var idrawn = [];
for (var i = 0; i < (drawn.length-1); i ++){
var fx = d3.interpolateNumber(drawn[i]["x"],drawn[i+1]["x"])
var fy = d3.interpolateNumber(drawn[i]["y"],drawn[i+1]["y"])
for (var j=0; j<100; j ++){
idrawn.push({"x":fx(j/100),"y":fy(j/100)});
}
}
var fdrawn = [];
for (var i=0; i<100; i ++){
var xdiff = [];
for (var j=0; j<idrawn.length; j ++){
xdiff.push(Math.abs(idrawn[j]["x"]-i/99));
}
var xdmin = Math.min(...xdiff);
fdrawn.push({"x":i/99,"y":idrawn[xdiff.indexOf(xdmin)]["y"]});
}
return(fdrawn);
}
curvals = [];
drawlinePlot();
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment