Skip to content

Instantly share code, notes, and snippets.

@1wheel
Last active August 22, 2016 02:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 1wheel/e2e482660bc8436a0c85 to your computer and use it in GitHub Desktop.
Save 1wheel/e2e482660bc8436a0c85 to your computer and use it in GitHub Desktop.
mid-point-curves
<!DOCTYPE html>
<meta charset="utf-8">
<style>
path{
fill: none;
stroke: black;
}
.point{
fill: lightgrey;
stroke: black;
cursor: pointer;
}
.straight{
stroke: black;
opacity: .1
}
.midpoint{
fill: green;
opacity: .1;
}
.projected{
fill: steelblue;
opacity: 1;
}
.diagonal{
opacity: .1
}
</style>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="jetpack.js"></script>
<body></body>
<script>
d3.selection.prototype.appendData = function(name, data){
return this.selectAll(name)
.data(data).enter()
.append(name)
}
function ƒ(str){ return function(d){ return str ? d[str] : d } }
var drag = d3.behavior.drag()
.on('drag', function(d){
d[0] = Math.round(Math.max(0, Math.min(width, d3.event.x)))
d[1] = Math.round(Math.max(0, Math.min(height, d3.event.y)))
render()
})
.origin(function(d){ return {x: d[0], y: d[1]} })
var width = 960,
height = 500
var svg = d3.select('body').append('svg')
.attr({width: width, height: height})
var circleData = [[100, 200], [600, 300], [260, 360]]
var connectionData = [
{a: circleData[0], b: circleData[1]},
{a: circleData[1], b: circleData[0]},
{a: circleData[1], b: circleData[2]},
// {a: circleData[0], b: circleData[1]},
]
var straight = svg.appendData('path.straight', connectionData)
var diagonal = svg.appendData('path.diagonal', connectionData)
var bezier = svg.appendData('path.bezier', connectionData)
var midpoints = svg.appendData('circle.midpoint', connectionData)
.attr('r', 5)
var projected = svg.appendData('circle.projected', connectionData)
.attr('r', 5)
var circles = svg.appendData('circle.point', circleData)
.call(drag)
.attr('r', 10)
render()
function render(){
circles.translate(ƒ())
connectionData.forEach(function(d){
d.m = [(d.a[0] + d.b[0])/2, (d.a[1] + d.b[1])/2]
var θ = Math.PI - Math.atan2(d.a[0] - d.b[0], d.a[1] - d.b[1])
var r = 20
d.p = [d.m[0] - r*Math.cos(θ), d.m[1] - r*Math.sin(θ)]
d.z = [d.m[0] - 50*Math.cos(θ), d.m[1] - 50*Math.sin(θ)]
})
straight
.attr('d', function(d){
return ['M', d.a, 'L', d.b].join(' ')
})
diagonal
.attr('d', function(d){
return ['M', d.a, 'L', d.p, 'L', d.b].join(' ')
})
bezier.attr('d', function(d){
return ['M', d.a, 'Q', d.z, d.b].join(' ')
})
midpoints.translate(ƒ('m'))
projected.translate(ƒ('p'))
}
</script>
(function() {
function jetpack(d3) {
d3.selection.prototype.translate = function(xy) {
return this.attr('transform', function(d,i) {
return 'translate('+[typeof xy == 'function' ? xy(d,i) : xy]+')';
});
};
d3.transition.prototype.translate = function(xy) {
return this.attr('transform', function(d,i) {
return 'translate('+[typeof xy == 'function' ? xy(d,i) : xy]+')';
});
};
d3.selection.prototype.tspans = function(lines, lh) {
return this.selectAll('tspan')
.data(lines)
.enter()
.append('tspan')
.text(function(d) { return d; })
.attr('x', 0)
.attr('dy', lh || 15);
};
d3.selection.prototype.append =
d3.selection.enter.prototype.append = function(name) {
var n = d3_parse_attributes(name), s;
//console.log(name, n);
name = n.attr ? n.tag : name;
name = d3_selection_creator(name);
s = this.select(function() {
return this.appendChild(name.apply(this, arguments));
});
return n.attr ? s.attr(n.attr) : s;
};
d3.selection.prototype.insert =
d3.selection.enter.prototype.insert = function(name, before) {
var n = d3_parse_attributes(name), s;
name = n.attr ? n.tag : name;
name = d3_selection_creator(name);
before = d3_selection_selector(before);
s = this.select(function() {
return this.insertBefore(name.apply(this, arguments), before.apply(this, arguments) || null);
});
return n.attr ? s.attr(n.attr) : s;
};
var d3_parse_attributes_regex = /([\.#])/g;
function d3_parse_attributes(name) {
if (typeof name === "string") {
var attr = {},
parts = name.split(d3_parse_attributes_regex), p;
name = parts.shift();
while ((p = parts.shift())) {
if (p == '.') attr['class'] = attr['class'] ? attr['class'] + ' ' + parts.shift() : parts.shift();
else if (p == '#') attr.id = parts.shift();
}
return attr.id || attr['class'] ? { tag: name, attr: attr } : name;
}
return name;
}
function d3_selection_creator(name) {
return typeof name === "function" ? name : (name = d3.ns.qualify(name)).local ? function() {
return this.ownerDocument.createElementNS(name.space, name.local);
} : function() {
return this.ownerDocument.createElementNS(this.namespaceURI, name);
};
}
function d3_selection_selector(selector) {
return typeof selector === "function" ? selector : function() {
return this.querySelector(selector);
};
}
d3.wordwrap = function(line, maxCharactersPerLine) {
var w = line.split(' '),
lines = [],
words = [],
maxChars = maxCharactersPerLine || 40,
l = 0;
w.forEach(function(d) {
if (l+d.length > maxChars) {
lines.push(words.join(' '));
words.length = 0;
l = 0;
}
l += d.length;
words.push(d);
});
if (words.length) {
lines.push(words.join(' '));
}
return lines;
};
d3.ascendingKey = function(key) {
return typeof key == 'function' ? function (a, b) {
return key(a) < key(b) ? -1 : key(a) > key(b) ? 1 : key(a) >= key(b) ? 0 : NaN;
} : function (a, b) {
return a[key] < b[key] ? -1 : a[key] > b[key] ? 1 : a[key] >= b[key] ? 0 : NaN;
};
};
d3.descendingKey = function(key) {
return typeof key == 'function' ? function (a, b) {
return key(b) < key(a) ? -1 : key(b) > key(a) ? 1 : key(b) >= key(a) ? 0 : NaN;
} : function (a, b) {
return b[key] < a[key] ? -1 : b[key] > a[key] ? 1 : b[key] >= a[key] ? 0 : NaN;
};
};
}
if (typeof d3 === 'object' && d3.version) jetpack(d3);
else if (typeof define === 'function' && define.amd) {
define(['d3'], jetpack);
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment