d3-cluster
Version:
d3 clustering layout
153 lines (124 loc) • 4.07 kB
JavaScript
// https://github.com/stormpython/d3-cluster#readme Version 1.0.0-alpha.8. Copyright 2016 undefined.
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3-scale'), require('lodash')) :
typeof define === 'function' && define.amd ? define(['exports', 'd3-scale', 'lodash'], factory) :
(factory((global.d3 = global.d3 || {}),global.d3,global.lodash));
}(this, (function (exports,d3Scale,lodash) { 'use strict';
// import quadtree from 'd3-quadtree';
function cluster () {
var x = function (d) { return d[0] };
var y = function (d) { return d[1] };
var radius = function (d) { return d[2] };
var xScale = d3Scale.scaleLinear();
var yScale = d3Scale.scaleLinear();
var centroid = function (p0, p1) { return (p1 + p0) / 2 };
function X(d, i) {
return xScale(x.call(this, d, i));
}
function Y(d, i) {
return yScale(y.call(this, d, i));
}
function clusterize(data) {
var clusteredPoints = [];
var overlappingPoints = [];
var modifiedData = data
.sort(function (a, b) {
return radius.call(this, b) - radius.call(this, a);
})
.map(function (d, i) {
return {
x: X.call(this, d, i),
y: Y.call(this, d, i),
radius: radius.call(this, d, i),
point: lodash.cloneDeep(d) // copy of original data point
};
});
var targetPoints = lodash.cloneDeep(modifiedData); // copy of data
modifiedData.forEach(function (p) {
if (overlappingPoints.indexOf(p) === -1) {
p.overlap = [];
clusteredPoints.push(p);
targetPoints.forEach(function (t) {
if (!lodash.isEqual(t, p)) {
var distance = Math.sqrt(Math.pow(Math.abs(t.x - p.x), 2) +
Math.pow(Math.abs(t.y - p.y), 2));
if (distance < t.radius + p.radius) {
t.clustered = true;
p.overlap.push(t);
overlappingPoints.push(t);
}
}
});
targetPoints = targetPoints.filter(function (d) {
return p.overlap.every(function (e) {
return !lodash.isEqual(e, d);
});
});
}
});
return clusteredPoints;
// quadtree()
// .x(d => d.x)
// .y(d => d.y)
// .addAll(modifiedData)
// .visit((d, x0, y0, x1, y1) => {
// if (d.data) { clusteredData.push(d.data); }
//
// // if pixel width < tolerance value, cluster points
// if ((x1 - x0) < tolerance) {
// let points = flattenDeep(d);
// points = points.filter(e => e);
//
// clusteredData.push({
// x: centroid.call(null, x0, x1, points.map(e => e.x)),
// y: centroid.call(null, y0, y1, points.map(e => e.y)),
// points,
// });
//
// return true; // Stop here
// }
//
// return false;
// });
//
// return clusteredData;
}
function layout(data) {
return clusterize(data);
}
// Public API
layout.x = function (_) {
if (!arguments.length) { return x; }
x = lodash.isFunction(_) ? _ : x;
return layout;
};
layout.y = function (_) {
if (!arguments.length) { return y; }
y = lodash.isFunction(_) ? _ : y;
return layout;
};
layout.radius = function (_) {
if (!arguments.length) { return radius; }
radius = lodash.isFunction(_) ? _ : radius;
return layout;
};
layout.centroid = function (_) {
if (!arguments.length) { return centroid; }
centroid = lodash.isFunction(_) ? _ : centroid;
return layout;
};
layout.xScale = function (_) {
if (!arguments.length) { return xScale; }
xScale = lodash.isFunction(_) ? _ : xScale;
return layout;
};
layout.yScale = function (_) {
if (!arguments.length) { return yScale; }
yScale = lodash.isFunction(_) ? _ : yScale;
return layout;
};
return layout;
}
exports.cluster = cluster;
Object.defineProperty(exports, '__esModule', { value: true });
})));