smart-labels 0.0.13 → 0.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/{src/index.js → dist/smartLabels.cjs} +56 -23
- package/dist/smartLabels.es.js +11 -3
- package/dist/smartLabels.js +11 -3
- package/dist/smartLabels.min.js +2 -2
- package/package.json +37 -11
- package/rollup.config.js +0 -66
|
@@ -1,4 +1,27 @@
|
|
|
1
|
-
|
|
1
|
+
// smart-labels v0.0.15 Copyright (c) 2024 John Alexis Guerra Gómez
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var d3 = require('d3');
|
|
5
|
+
|
|
6
|
+
function _interopNamespaceDefault(e) {
|
|
7
|
+
var n = Object.create(null);
|
|
8
|
+
if (e) {
|
|
9
|
+
Object.keys(e).forEach(function (k) {
|
|
10
|
+
if (k !== 'default') {
|
|
11
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
12
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
get: function () { return e[k]; }
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
n.default = e;
|
|
20
|
+
return Object.freeze(n);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
var d3__namespace = /*#__PURE__*/_interopNamespaceDefault(d3);
|
|
24
|
+
|
|
2
25
|
// Based on https://observablehq.com/@d3/voronoi-labels by Mike Bostock
|
|
3
26
|
|
|
4
27
|
// ISC License
|
|
@@ -15,7 +38,7 @@ import * as d3 from "d3";
|
|
|
15
38
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
16
39
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
17
40
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
18
|
-
|
|
41
|
+
function smartLabels(
|
|
19
42
|
data,
|
|
20
43
|
{
|
|
21
44
|
x = (d) => d[0], // x coordinate accessor, expected to be in pixels
|
|
@@ -35,7 +58,7 @@ export default function smartLabels(
|
|
|
35
58
|
labelsInCentroids = true,
|
|
36
59
|
threshold = 2000, // Areas over this size would get labels
|
|
37
60
|
alwaysShow = (d) => false, // If returns true for the node, it will always show the label
|
|
38
|
-
showLabel = (d, cell) => alwaysShow(d) || -
|
|
61
|
+
showLabel = (d, cell) => alwaysShow(d) || -d3__namespace.polygonArea(cell) > threshold, // If true, show the label
|
|
39
62
|
|
|
40
63
|
backgroundFill = "#fefefe01", // What to paint the bg rect of the labels. Needed for the onHover
|
|
41
64
|
strokeWidth = 5,
|
|
@@ -73,11 +96,19 @@ export default function smartLabels(
|
|
|
73
96
|
y(d, index) !== null
|
|
74
97
|
);
|
|
75
98
|
|
|
76
|
-
|
|
77
|
-
|
|
99
|
+
// Keep the string in its own constant: `font = () => font` would return the
|
|
100
|
+
// arrow function itself (font is reassigned), so string fonts were ignored.
|
|
101
|
+
if (typeof font === "string") {
|
|
102
|
+
const fontString = font;
|
|
103
|
+
font = () => fontString;
|
|
104
|
+
}
|
|
105
|
+
if (typeof hoverFont === "string") {
|
|
106
|
+
const hoverFontString = hoverFont;
|
|
107
|
+
hoverFont = () => hoverFontString;
|
|
108
|
+
}
|
|
78
109
|
|
|
79
|
-
let xExtent =
|
|
80
|
-
yExtent =
|
|
110
|
+
let xExtent = d3__namespace.extent(data, x),
|
|
111
|
+
yExtent = d3__namespace.extent(data, y);
|
|
81
112
|
width = width || xExtent[1] - xExtent[0];
|
|
82
113
|
height = height || yExtent[1] - yExtent[0];
|
|
83
114
|
|
|
@@ -111,21 +142,21 @@ export default function smartLabels(
|
|
|
111
142
|
// Try to reuse the target
|
|
112
143
|
if (renderer.toLocaleLowerCase() === "canvas") {
|
|
113
144
|
if (target) {
|
|
114
|
-
target =
|
|
145
|
+
target = d3__namespace.select(target.node ? target.node() : target);
|
|
115
146
|
} else {
|
|
116
|
-
target =
|
|
147
|
+
target = d3__namespace.create("canvas").attr("width", width).attr("height", height);
|
|
117
148
|
}
|
|
118
149
|
useOcclusion = false;
|
|
119
150
|
} else {
|
|
120
151
|
if (target) {
|
|
121
|
-
target =
|
|
152
|
+
target = d3__namespace.select(target.node ? target.node() : target);
|
|
122
153
|
} else {
|
|
123
|
-
target =
|
|
154
|
+
target = d3__namespace.create("svg").attr("viewBox", [0, 0, width, height]);
|
|
124
155
|
}
|
|
125
|
-
target = target ||
|
|
156
|
+
target = target || d3__namespace.create("svg").attr("viewBox", [0, 0, width, height]);
|
|
126
157
|
}
|
|
127
158
|
|
|
128
|
-
const delaunay =
|
|
159
|
+
const delaunay = d3__namespace.Delaunay.from(data, x, y);
|
|
129
160
|
const voronoi = delaunay.voronoi([
|
|
130
161
|
xExtent[0] - 1,
|
|
131
162
|
yExtent[0] - 1,
|
|
@@ -213,7 +244,7 @@ export default function smartLabels(
|
|
|
213
244
|
.attr("display", ({ show }) => (show ? null : "none"))
|
|
214
245
|
.attr("d", ({ d, cell }, index) =>
|
|
215
246
|
cell
|
|
216
|
-
? `M${
|
|
247
|
+
? `M${d3__namespace.polygonCentroid(cell)}L${x(d, index)},${y(d, index)}`
|
|
217
248
|
: null
|
|
218
249
|
);
|
|
219
250
|
}
|
|
@@ -259,7 +290,7 @@ export default function smartLabels(
|
|
|
259
290
|
.style("font", ({d}, i) => font(d, i))
|
|
260
291
|
.each(function ({ d, cell }, index) {
|
|
261
292
|
if (!cell) return;
|
|
262
|
-
const [cx, cy] =
|
|
293
|
+
const [cx, cy] = d3__namespace.polygonCentroid(cell);
|
|
263
294
|
const angle =
|
|
264
295
|
(Math.round(
|
|
265
296
|
(Math.atan2(cy - y(d, index), cx - x(d, index)) / Math.PI) * 2
|
|
@@ -267,7 +298,7 @@ export default function smartLabels(
|
|
|
267
298
|
4) %
|
|
268
299
|
4;
|
|
269
300
|
|
|
270
|
-
|
|
301
|
+
d3__namespace.select(this).call(
|
|
271
302
|
angle === 0
|
|
272
303
|
? orient.right
|
|
273
304
|
: angle === 3
|
|
@@ -279,7 +310,7 @@ export default function smartLabels(
|
|
|
279
310
|
})
|
|
280
311
|
.attr("transform", ({ d, cell }, index) => {
|
|
281
312
|
if (labelsInCentroids) {
|
|
282
|
-
const [cx, cy] =
|
|
313
|
+
const [cx, cy] = d3__namespace.polygonCentroid(cell);
|
|
283
314
|
|
|
284
315
|
return `translate(${cx}, ${cy})`;
|
|
285
316
|
} else {
|
|
@@ -293,7 +324,7 @@ export default function smartLabels(
|
|
|
293
324
|
if (hover) {
|
|
294
325
|
mouseRect.on("mousemove", (event) => {
|
|
295
326
|
// Find the selected point
|
|
296
|
-
const i = delaunay.find(...
|
|
327
|
+
const i = delaunay.find(...d3__namespace.pointer(event));
|
|
297
328
|
if (i === selected) return;
|
|
298
329
|
selected = i;
|
|
299
330
|
|
|
@@ -361,7 +392,7 @@ export default function smartLabels(
|
|
|
361
392
|
if (showAnchors || labelsInCentroids) {
|
|
362
393
|
cells.forEach(({ d, cell, show }, index) => {
|
|
363
394
|
if (!show) return;
|
|
364
|
-
const [cx, cy] =
|
|
395
|
+
const [cx, cy] = d3__namespace.polygonCentroid(cell);
|
|
365
396
|
context.beginPath();
|
|
366
397
|
context.moveTo(cx, cy);
|
|
367
398
|
context.lineTo(x(d, index), y(d, index));
|
|
@@ -398,7 +429,7 @@ export default function smartLabels(
|
|
|
398
429
|
function renderCanvasLabels(context, selected) {
|
|
399
430
|
cells.forEach(({ d, cell, show }, index) => {
|
|
400
431
|
if (!show && index !== selected) return;
|
|
401
|
-
const [cx, cy] =
|
|
432
|
+
const [cx, cy] = d3__namespace.polygonCentroid(cell);
|
|
402
433
|
const angle =
|
|
403
434
|
(Math.round(
|
|
404
435
|
(Math.atan2(cy - y(d, index), cx - x(d, index)) / Math.PI) * 2
|
|
@@ -451,7 +482,7 @@ export default function smartLabels(
|
|
|
451
482
|
if (debug) console.log("setting onmousemove", target);
|
|
452
483
|
|
|
453
484
|
target.on("mousemove", (event) => {
|
|
454
|
-
const [mx, my] =
|
|
485
|
+
const [mx, my] = d3__namespace.pointer(event);
|
|
455
486
|
const i = delaunay.find(mx, my);
|
|
456
487
|
if (i === selected) return;
|
|
457
488
|
selected = i;
|
|
@@ -489,7 +520,7 @@ export default function smartLabels(
|
|
|
489
520
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
490
521
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
491
522
|
function occlusion(svg, against = "text") {
|
|
492
|
-
const nodes =
|
|
523
|
+
const nodes = d3__namespace
|
|
493
524
|
.sort(svg.selectAll(against), (node) => +node.getAttribute("data-priority"))
|
|
494
525
|
.reverse()
|
|
495
526
|
.map((node) => {
|
|
@@ -500,7 +531,7 @@ function occlusion(svg, against = "text") {
|
|
|
500
531
|
const visible = [];
|
|
501
532
|
for (const d of nodes) {
|
|
502
533
|
const occluded = visible.some((e) => intersectRect(d, e));
|
|
503
|
-
|
|
534
|
+
d3__namespace.select(d.node).classed("occluded", occluded);
|
|
504
535
|
if (!occluded) visible.push(d);
|
|
505
536
|
}
|
|
506
537
|
return visible;
|
|
@@ -515,3 +546,5 @@ function intersectRect(a, b) {
|
|
|
515
546
|
b.y + b.height < a.y
|
|
516
547
|
);
|
|
517
548
|
}
|
|
549
|
+
|
|
550
|
+
module.exports = smartLabels;
|
package/dist/smartLabels.es.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// smart-labels v0.0.
|
|
1
|
+
// smart-labels v0.0.15 Copyright (c) 2024 John Alexis Guerra Gómez
|
|
2
2
|
import * as d3 from 'd3';
|
|
3
3
|
|
|
4
4
|
// Based on https://observablehq.com/@d3/voronoi-labels by Mike Bostock
|
|
@@ -75,8 +75,16 @@ function smartLabels(
|
|
|
75
75
|
y(d, index) !== null
|
|
76
76
|
);
|
|
77
77
|
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
// Keep the string in its own constant: `font = () => font` would return the
|
|
79
|
+
// arrow function itself (font is reassigned), so string fonts were ignored.
|
|
80
|
+
if (typeof font === "string") {
|
|
81
|
+
const fontString = font;
|
|
82
|
+
font = () => fontString;
|
|
83
|
+
}
|
|
84
|
+
if (typeof hoverFont === "string") {
|
|
85
|
+
const hoverFontString = hoverFont;
|
|
86
|
+
hoverFont = () => hoverFontString;
|
|
87
|
+
}
|
|
80
88
|
|
|
81
89
|
let xExtent = d3.extent(data, x),
|
|
82
90
|
yExtent = d3.extent(data, y);
|
package/dist/smartLabels.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// smart-labels v0.0.
|
|
1
|
+
// smart-labels v0.0.15 Copyright (c) 2024 John Alexis Guerra Gómez
|
|
2
2
|
(function (global, factory) {
|
|
3
3
|
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('d3')) :
|
|
4
4
|
typeof define === 'function' && define.amd ? define(['d3'], factory) :
|
|
@@ -98,8 +98,16 @@ function smartLabels(
|
|
|
98
98
|
y(d, index) !== null
|
|
99
99
|
);
|
|
100
100
|
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
// Keep the string in its own constant: `font = () => font` would return the
|
|
102
|
+
// arrow function itself (font is reassigned), so string fonts were ignored.
|
|
103
|
+
if (typeof font === "string") {
|
|
104
|
+
const fontString = font;
|
|
105
|
+
font = () => fontString;
|
|
106
|
+
}
|
|
107
|
+
if (typeof hoverFont === "string") {
|
|
108
|
+
const hoverFontString = hoverFont;
|
|
109
|
+
hoverFont = () => hoverFontString;
|
|
110
|
+
}
|
|
103
111
|
|
|
104
112
|
let xExtent = d3__namespace.extent(data, x),
|
|
105
113
|
yExtent = d3__namespace.extent(data, y);
|
package/dist/smartLabels.min.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
// smart-labels v0.0.
|
|
2
|
-
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("d3")):"function"==typeof define&&define.amd?define(["d3"],e):(t="undefined"!=typeof globalThis?globalThis:t||self).smartLabels=e(t.d3)}(this,function(t){"use strict";function e(t){var e=Object.create(null);return t&&Object.keys(t).forEach(function(o){if("default"!==o){var n=Object.getOwnPropertyDescriptor(t,o);Object.defineProperty(e,o,n.get?n:{enumerable:!0,get:function(){return t[o]}})}}),e.default=t,Object.freeze(e)}var o=e(t);function n(t,e="text"){const n=o.sort(t.selectAll(e),t=>+t.getAttribute("data-priority")).reverse().map(t=>{const{x:e,y:o,width:n,height:r}=t.getBoundingClientRect();return{node:t,x:e,y:o,width:n,height:r}}),r=[];for(const t of n){const e=r.some(e=>{return n=e,!((o=t).x+o.width<n.x||n.x+n.width<o.x||o.y+o.height<n.y||n.y+n.height<o.y);var o,n});o.select(t.node).classed("occluded",e),e||r.push(t)}return r}return function(t,{x:e=t=>t[0],y:r=t=>t[1],r:l=()=>3,label:a=(t,e)=>e,fill:s="#333",stroke:i="white",width:c=null,height:d=null,target:h=null,renderer:f="svg",font:u=()=>"10pt sans-serif",hover:g=!0,onHover:p=t=>t,hoverFont:y=()=>"bolder 12pt sans-serif",labelsInCentroids:b=!0,threshold:m=2e3,alwaysShow:v=t=>!1,showLabel:w=(t,e)=>v(t)||-o.polygonArea(e)>m,backgroundFill:x="#fefefe01",strokeWidth:k=5,showVoronoi:L=!1,voronoiStroke:A="#ccc",showAnchors:j=!1,anchorsStroke:S="orange",anchorsFill:C="none",useOcclusion:P=!0,occludedStyle:M="opacity: 0.2",showPoints:O=!1,pointsFill:T="#ccc",pointsSelectedFill:$="firebrick",pointsStroke:E="#ccc",debug:F=!1,selected:I=null,padding:B=3}={}){if(!t||0===t?.length)return console.log("smartLabels: No data to render"),h;t=t.filter((t,o)=>void 0!==e(t,o)&&null!==e(t,o)&&void 0!==r(t,o)&&null!==r(t,o)),"string"==typeof u
|
|
1
|
+
// smart-labels v0.0.15 Copyright (c) 2024 John Alexis Guerra Gómez
|
|
2
|
+
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("d3")):"function"==typeof define&&define.amd?define(["d3"],e):(t="undefined"!=typeof globalThis?globalThis:t||self).smartLabels=e(t.d3)}(this,function(t){"use strict";function e(t){var e=Object.create(null);return t&&Object.keys(t).forEach(function(o){if("default"!==o){var n=Object.getOwnPropertyDescriptor(t,o);Object.defineProperty(e,o,n.get?n:{enumerable:!0,get:function(){return t[o]}})}}),e.default=t,Object.freeze(e)}var o=e(t);function n(t,e="text"){const n=o.sort(t.selectAll(e),t=>+t.getAttribute("data-priority")).reverse().map(t=>{const{x:e,y:o,width:n,height:r}=t.getBoundingClientRect();return{node:t,x:e,y:o,width:n,height:r}}),r=[];for(const t of n){const e=r.some(e=>{return n=e,!((o=t).x+o.width<n.x||n.x+n.width<o.x||o.y+o.height<n.y||n.y+n.height<o.y);var o,n});o.select(t.node).classed("occluded",e),e||r.push(t)}return r}return function(t,{x:e=t=>t[0],y:r=t=>t[1],r:l=()=>3,label:a=(t,e)=>e,fill:s="#333",stroke:i="white",width:c=null,height:d=null,target:h=null,renderer:f="svg",font:u=()=>"10pt sans-serif",hover:g=!0,onHover:p=t=>t,hoverFont:y=()=>"bolder 12pt sans-serif",labelsInCentroids:b=!0,threshold:m=2e3,alwaysShow:v=t=>!1,showLabel:w=(t,e)=>v(t)||-o.polygonArea(e)>m,backgroundFill:x="#fefefe01",strokeWidth:k=5,showVoronoi:L=!1,voronoiStroke:A="#ccc",showAnchors:j=!1,anchorsStroke:S="orange",anchorsFill:C="none",useOcclusion:P=!0,occludedStyle:M="opacity: 0.2",showPoints:O=!1,pointsFill:T="#ccc",pointsSelectedFill:$="firebrick",pointsStroke:E="#ccc",debug:F=!1,selected:I=null,padding:B=3}={}){if(!t||0===t?.length)return console.log("smartLabels: No data to render"),h;if(t=t.filter((t,o)=>void 0!==e(t,o)&&null!==e(t,o)&&void 0!==r(t,o)&&null!==r(t,o)),"string"==typeof u){const t=u;u=()=>t}if("string"==typeof y){const t=y;y=()=>t}let V=o.extent(t,e),D=o.extent(t,r);if(c=c||V[1]-V[0],d=d||D[1]-D[0],F&&console.log("✅ smartLabels renderer",f),h&&!function(t,e){return t&&t.node&&(t=t.node()),"canvas"===e.toLocaleLowerCase()?t instanceof HTMLCanvasElement:t instanceof SVGElement}(h,f))throw F&&console.log("❌ smartLabels Target doesn't match the renderer",h,f),new Error("Smartlabels Target doesn't match the renderer",h,f);"canvas"===f.toLocaleLowerCase()?(h=h?o.select(h.node?h.node():h):o.create("canvas").attr("width",c).attr("height",d),P=!1):h=(h=h?o.select(h.node?h.node():h):o.create("svg").attr("viewBox",[0,0,c,d]))||o.create("svg").attr("viewBox",[0,0,c,d]);const H=o.Delaunay.from(t,e,r),R=H.voronoi([V[0]-1,D[0]-1,V[1]+1,D[1]+1]);let W=t.map((t,e)=>[t,R.cellPolygon(e)]);function q(t,o,n){if(!o){const l=H.find(e(t,n),r(t,n));if(-1===l)return console.log("couldn't find cell",l,t,e(t,n),r(t,n)),null;o=W[l][1]}return o}function z(n){F&&console.log("renderCanvasAnchorsVoronoiPoints","showAnchors",j,"labelsInCentroids",b,"showVoronoi",L,"showPoints",O),(j||b)&&W.forEach(({d:t,cell:l,show:a},s)=>{if(!a)return;const[i,c]=o.polygonCentroid(l);n.beginPath(),n.moveTo(i,c),n.lineTo(e(t,s),r(t,s)),n.strokeStyle=S,n.stroke()}),L&&(n.beginPath(),R.render(n),n.strokeStyle=A,n.stroke()),O&&(n.beginPath(),n.save(),n.globalAlpha=.7,n.fillStyle="black",t.forEach((t,o)=>{n.beginPath(),n.arc(e(t,o),r(t,o),l(t,o),0,2*Math.PI)}),n.restore(),n.fillStyle=T,n.fill(),n.strokeStyle=E,n.stroke())}function G(t,n){W.forEach(({d:c,cell:d,show:h},f)=>{if(!h&&f!==n)return;const[g,p]=o.polygonCentroid(d),m=(Math.round(Math.atan2(p-r(c,f),g-e(c,f))/Math.PI*2)+4)%4;t.save();const v=l(c,f)+B,w=0===m?v:2===m?-v:v,x=1===m?v:3===m?-v:v;t.translate(b?g:e(c,f)+w,b?p:r(c,f)+x),t.textAlign=0===m?"left":1===m?"center":2===m?"right":"center",t.textBaseline=0===m?"middle":1===m?"top":2===m?"middle":"bottom",t.font=f===n?y(c,f):u(c,f),t.fillStyle=s,t.strokeStyle=i,t.lineWidth=k,t.strokeText(a(c,f),0,0),t.fillText(a(c,f),0,0),t.restore()})}return W=W.map(([t,e],o)=>[t,q(t,e,o)]).map(([t,e])=>({d:t,cell:e,show:w(t,e)})),"canvas"===f.toLocaleLowerCase()?function(){const t=h.node().getContext("2d");z(t),G(t,I),g&&(F&&console.log("setting onmousemove",h),h.on("mousemove",e=>{const[n,r]=o.pointer(e),l=H.find(n,r);l!==I&&(I=l,t.clearRect(0,0,c,d),z(t),p&&"function"==typeof p&&p(l),G(t,I))}))}():function(){let t=null;P&&h.selectAll("style.smartLabels").data([0]).join("style").attr("class","smartLabels").html(`\n svg g.labels > text.occluded:not(.selected) { ${M} }\n `);const f=h.selectAll("rect.smartLabels").data([0]).join("rect").attr("class","smartLabels").attr("width",c).attr("height",d).attr("fill",x).attr("stroke","none"),m={top:t=>t.attr("text-anchor","middle").attr("y",(t,e)=>-(l(t,e)+B)),right:t=>t.attr("text-anchor","start").attr("dy","0.35em").attr("x",(t,e)=>l(t,e)+B),bottom:t=>t.attr("text-anchor","middle").attr("dy","0.71em").attr("y",(t,e)=>l(t,e)+B),left:t=>t.attr("text-anchor","end").attr("dy","0.35em").attr("x",(t,e)=>-(l(t,e)+B))};let v;(j||b)&&(t=h.selectAll("g#anchors").data([W]).join("g").attr("pointer-events","none").attr("id","anchors").attr("stroke",S).attr("fill",C).selectAll("path.anchor").data(t=>t).join("path").attr("class","anchor").attr("display",({show:t})=>t?null:"none").attr("d",({d:t,cell:n},l)=>n?`M${o.polygonCentroid(n)}L${e(t,l)},${r(t,l)}`:null)),L&&h.selectAll("path#voronoi").data([1]).join("path").attr("id","voronoi").attr("stroke",A).attr("pointer-events","none").attr("d",R.render()),O&&(v=h.selectAll("circle#points").data([1]).join("path").attr("id","points").attr("pointer-events","none").attr("stroke",E).attr("fill",T).attr("d",H.renderPoints(null,2)));const w=h.selectAll("g.labels").data([W]).join("g").attr("class","labels").attr("fill",s).attr("stroke",i).attr("stroke-width",k).attr("paint-order","stroke").attr("pointer-events","none").selectAll("text").data(t=>t).join("text").style("font",({d:t},e)=>u(t,e)).each(function({d:t,cell:n},l){if(!n)return;const[a,s]=o.polygonCentroid(n),i=(Math.round(Math.atan2(s-r(t,l),a-e(t,l))/Math.PI*2)+4)%4;o.select(this).call(0===i?m.right:3===i?m.top:1===i?m.bottom:m.left)}).attr("transform",({d:t,cell:n},l)=>{if(b){const[t,e]=o.polygonCentroid(n);return`translate(${t}, ${e})`}return`translate(${e(t,l)}, ${r(t,l)})`}).attr("display",({show:t})=>t?null:"none").text(({d:t},e,o)=>a(t,e,o));let F=null;if(g&&f.on("mousemove",e=>{const n=H.find(...o.pointer(e));n!==F&&(F=n,w.attr("display",({show:t},e)=>e===F||t?null:"none").style("font",({d:t},e)=>e===F?y(t,e):u(t,e)).classed("selected",(t,e)=>e===F).filter((t,e)=>e===F).raise(),t&&t.attr("display",({show:t},e)=>t||e===F?null:"none"),O&&v.attr("fill",(t,e)=>$).classed("selected",(t,e)=>e===F),p&&"function"==typeof p&&p(n))}),P){const t=new MutationObserver(function(){document.contains(h.node())&&(h.call(n,"g.labels > text"),t.disconnect())});t.observe(document,{attributes:!1,childList:!0,characterData:!1,subtree:!0})}}(),Object.assign(h.node(),{delaunay:H,voronoi:R,cells:W})}});
|
package/package.json
CHANGED
|
@@ -1,13 +1,37 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "smart-labels",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.0.15",
|
|
4
|
+
"description": "Fast automatic label placement for D3 scatterplots using Voronoi cells and occlusion detection",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"d3",
|
|
7
|
+
"labels",
|
|
8
|
+
"label-placement",
|
|
9
|
+
"voronoi",
|
|
10
|
+
"delaunay",
|
|
11
|
+
"occlusion",
|
|
12
|
+
"scatterplot",
|
|
13
|
+
"annotation",
|
|
14
|
+
"visualization",
|
|
15
|
+
"dataviz"
|
|
16
|
+
],
|
|
5
17
|
"type": "module",
|
|
6
|
-
"main": "dist/smartLabels.
|
|
18
|
+
"main": "dist/smartLabels.cjs",
|
|
7
19
|
"module": "dist/smartLabels.es.js",
|
|
8
20
|
"browser": "dist/smartLabels.min.js",
|
|
9
21
|
"unpkg": "dist/smartLabels.min.js",
|
|
10
22
|
"jsdelivr": "dist/smartLabels.min.js",
|
|
23
|
+
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"import": "./dist/smartLabels.es.js",
|
|
26
|
+
"require": "./dist/smartLabels.cjs",
|
|
27
|
+
"default": "./dist/smartLabels.min.js"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"dist",
|
|
32
|
+
"LICENSE",
|
|
33
|
+
"README.md"
|
|
34
|
+
],
|
|
11
35
|
"scripts": {
|
|
12
36
|
"build": "rollup -c",
|
|
13
37
|
"dev": "rollup -c -w",
|
|
@@ -15,18 +39,16 @@
|
|
|
15
39
|
},
|
|
16
40
|
"devDependencies": {
|
|
17
41
|
"@eslint/js": "^9.14.0",
|
|
18
|
-
"@rollup/plugin-
|
|
19
|
-
"
|
|
20
|
-
"@rollup/plugin-terser": "^1.0.0",
|
|
42
|
+
"@rollup/plugin-terser": "^1.0.2",
|
|
43
|
+
"d3": "^7.9.2",
|
|
21
44
|
"eslint": "^9.14.0",
|
|
22
45
|
"eslint-config-prettier": "^9.1.0",
|
|
23
|
-
"eslint-plugin-html": "^8.1
|
|
46
|
+
"eslint-plugin-html": "^8.2.1",
|
|
24
47
|
"globals": "^15.12.0",
|
|
25
|
-
"prettier": "^3.
|
|
26
|
-
"rollup": "^4.
|
|
27
|
-
"rollup-plugin-commonjs": "^10.1.0"
|
|
48
|
+
"prettier": "^3.10.1",
|
|
49
|
+
"rollup": "^4.68.2"
|
|
28
50
|
},
|
|
29
|
-
"
|
|
51
|
+
"peerDependencies": {
|
|
30
52
|
"d3": "^7.9.0"
|
|
31
53
|
},
|
|
32
54
|
"author": {
|
|
@@ -34,6 +56,10 @@
|
|
|
34
56
|
"url": "https://johnguerra.co"
|
|
35
57
|
},
|
|
36
58
|
"license": "MIT",
|
|
59
|
+
"repository": {
|
|
60
|
+
"type": "git",
|
|
61
|
+
"url": "git+https://github.com/john-guerra/smart-labels.git"
|
|
62
|
+
},
|
|
37
63
|
"bugs": {
|
|
38
64
|
"url": "https://github.com/john-guerra/smart-labels/issues"
|
|
39
65
|
},
|
package/rollup.config.js
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from "fs";
|
|
2
|
-
import node from "@rollup/plugin-node-resolve";
|
|
3
|
-
import commonjs from "rollup-plugin-commonjs";
|
|
4
|
-
import terser from "@rollup/plugin-terser";
|
|
5
|
-
// import babel from "rollup-plugin-babel";
|
|
6
|
-
import json from "@rollup/plugin-json";
|
|
7
|
-
import meta from "./package.json" with { type: "json" };
|
|
8
|
-
|
|
9
|
-
// Extract copyrights from the LICENSE.
|
|
10
|
-
const copyrights = readFileSync("./LICENSE", "utf-8")
|
|
11
|
-
.split(/\n/g)
|
|
12
|
-
.filter((line) => /^copyright\s+/i.test(line))
|
|
13
|
-
.map((line) => line.replace(/^copyright\s+/i, ""));
|
|
14
|
-
|
|
15
|
-
const filename = "smartLabels";
|
|
16
|
-
|
|
17
|
-
// Observable Plot style
|
|
18
|
-
const config = {
|
|
19
|
-
input: "src/index.js",
|
|
20
|
-
external: ["d3"],
|
|
21
|
-
output: {
|
|
22
|
-
indent: false,
|
|
23
|
-
banner: `// ${meta.name} v${meta.version} Copyright ${copyrights.join(", ")}`,
|
|
24
|
-
extend: true,
|
|
25
|
-
globals: {
|
|
26
|
-
"d3": "d3",
|
|
27
|
-
},
|
|
28
|
-
name: "smartLabels",
|
|
29
|
-
},
|
|
30
|
-
plugins: [commonjs(), json(), node()],
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
export default [
|
|
34
|
-
{
|
|
35
|
-
...config,
|
|
36
|
-
output: {
|
|
37
|
-
...config.output,
|
|
38
|
-
format: "umd",
|
|
39
|
-
file: `dist/${filename}.js`,
|
|
40
|
-
},
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
...config,
|
|
44
|
-
output: {
|
|
45
|
-
...config.output,
|
|
46
|
-
format: "es",
|
|
47
|
-
file: `dist/${filename}.es.js`,
|
|
48
|
-
},
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
...config,
|
|
52
|
-
output: {
|
|
53
|
-
...config.output,
|
|
54
|
-
format: "umd",
|
|
55
|
-
file: `dist/${filename}.min.js`,
|
|
56
|
-
},
|
|
57
|
-
plugins: [
|
|
58
|
-
...config.plugins,
|
|
59
|
-
terser({
|
|
60
|
-
output: {
|
|
61
|
-
preamble: config.output.banner,
|
|
62
|
-
},
|
|
63
|
-
}),
|
|
64
|
-
],
|
|
65
|
-
},
|
|
66
|
-
];
|