|
; |
|
d3.labeling = function() { |
|
|
|
var labeling = {}, className, labels, callbacks = [], callbackpos = -1, |
|
updateLabels = false, _break = false, legend = []; |
|
|
|
labeling.select = function(_className) { |
|
className = _className; |
|
labels = getLabels(); |
|
return labeling; |
|
} |
|
|
|
var getLabels = function() { |
|
|
|
if (typeof className === "string") { |
|
return svg.selectAll(className); |
|
} |
|
else { |
|
return className.call(this); |
|
} |
|
} |
|
|
|
labeling.remove = function() { |
|
callbacks.push(labeling_remove); |
|
updateLabels = true; |
|
return labeling; |
|
} |
|
|
|
labeling.scale = function(_scaleFactor) { |
|
|
|
var scaleFactor = _scaleFactor || .75; |
|
|
|
// currying: https://medium.com/@kbrainwave/currying-in-javascript-ce6da2d324fe |
|
var fn = function(label) { |
|
return labeling_scale(label, scaleFactor); |
|
} |
|
|
|
callbacks.push(fn); |
|
|
|
return labeling; |
|
} |
|
|
|
labeling.legend = function() { |
|
callbacks.push(labeling_legend); |
|
updateLabels = true; |
|
return labeling; |
|
} |
|
|
|
var labeling_remove = function(label) { |
|
label.remove(); |
|
} |
|
|
|
var labeling_scale = function(label,factor) { |
|
|
|
var x = +label.attr("x"), y = +label.attr("y"), |
|
scaleFactor = factor < 1 ? 1 - factor : - (factor - 1), |
|
transform = "translate(" + (x * scaleFactor) + "," + (y * scaleFactor) + ") scale(" + factor + ")"; |
|
|
|
label.attr("transform", transform); |
|
} |
|
|
|
var labeling_legend = function(label) { |
|
|
|
legend.push(label.text()); |
|
|
|
label.text(legend.length); |
|
|
|
} |
|
|
|
var next = function(label) { |
|
|
|
var box = getBox(label); |
|
|
|
var pos = label.attr("data-pos") || 0; |
|
|
|
pos++; |
|
|
|
if (pos === 8) { |
|
|
|
var calls = label.attr("data-calls") || -1; |
|
|
|
calls++; |
|
|
|
label.attr("data-calls", calls); |
|
|
|
if (calls < callbacks.length) { |
|
var fn = callbacks[calls]; |
|
fn.call(this, label); |
|
} |
|
|
|
pos = 0; |
|
box = getBox(label); |
|
|
|
// prevent infinite loop |
|
if (!callbacks.length) { |
|
_break = true; |
|
} |
|
|
|
} |
|
|
|
label.attr("data-pos", pos); |
|
|
|
var x = +label.attr("x"), y = +label.attr("y"); |
|
|
|
switch(pos) { |
|
case 0: |
|
case 1: |
|
y += box.height/2; |
|
break; |
|
case 2: |
|
case 3: |
|
x -= box.width/2; |
|
break; |
|
case 4: |
|
case 5: |
|
y -= box.height/2; |
|
break; |
|
case 6: |
|
case 7: |
|
x += box.width/2; |
|
break; |
|
} |
|
|
|
label.attr("x", x).attr("y", y); |
|
|
|
} |
|
|
|
var overlaps = function(a, b) { |
|
|
|
return ( |
|
(a.left <= b.left && b.left <= a.right) |
|
|| |
|
(a.left <= b.right && b.right <= a.right) |
|
) |
|
&& |
|
( |
|
(a.top <= b.top && b.top <= a.bottom) |
|
|| |
|
(a.top <= b.bottom && b.bottom <= a.bottom) |
|
); |
|
} |
|
|
|
var getBox = function(d) { |
|
return d[0][0].getBoundingClientRect(); |
|
} |
|
|
|
labeling.align = function() { |
|
|
|
var overlappeds; |
|
|
|
do { |
|
overlappeds = 0; |
|
|
|
labels.each(function() { |
|
var current = this; |
|
var box_text = getBox(d3.select(current)); |
|
|
|
var _overlappeds = labels[0].filter(function(d) { |
|
if (d === current) return false; |
|
return overlaps(box_text, getBox(d3.select(d))); |
|
}); |
|
|
|
overlappeds += _overlappeds.length; |
|
|
|
_overlappeds.forEach(function(el) { |
|
next(d3.select(el)); |
|
}); |
|
|
|
}); |
|
|
|
if (updateLabels) { |
|
labels = getLabels(className); |
|
} |
|
|
|
} while (overlappeds > 0 && !_break); |
|
|
|
return labeling; |
|
} |
|
|
|
labeling.getLegend = function() { |
|
|
|
return legend.map(function(d, i) { |
|
return { key: i + 1, name: d } |
|
}); |
|
} |
|
|
|
return labeling; |
|
|
|
} |