smart-labels 0.0.6 → 0.0.8
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/README.md +5 -3
- package/dist/smartLabels.es.js +27 -11
- package/dist/smartLabels.js +27 -11
- package/dist/smartLabels.min.js +2 -2
- package/package.json +1 -1
- package/src/index.js +26 -10
package/README.md
CHANGED
|
@@ -33,9 +33,9 @@ Receives the data, accessors for the x and y coordinates as well as the label. E
|
|
|
33
33
|
y = (d) => d[1], // y coordinate accessor, expected to be in pixels
|
|
34
34
|
r = () => 3, // radius accessor, expected to be in pixels
|
|
35
35
|
label = (d, i) => i, // Accessor for the label
|
|
36
|
+
renderer = "svg", // canvas or svg
|
|
36
37
|
fill = "#333", // label fill color
|
|
37
38
|
stroke = "white", // label stroke color
|
|
38
|
-
threshold = 2000, // Areas over this size would get labels
|
|
39
39
|
width = null,
|
|
40
40
|
height = null,
|
|
41
41
|
target = null, // Where do you want it to draw
|
|
@@ -44,7 +44,9 @@ Receives the data, accessors for the x and y coordinates as well as the label. E
|
|
|
44
44
|
onHover = (i) => i, // callback when hovered, will pass the index of the selected element
|
|
45
45
|
hoverFont = "bolder 12px sans-serif",
|
|
46
46
|
labelsInCentroids = true,
|
|
47
|
-
|
|
47
|
+
threshold = 2000, // Areas over this size would get labels
|
|
48
|
+
alwaysShow = (d) => false, // If returns true for the node, it will always show the label
|
|
49
|
+
showLabel = (d, cell) => alwaysShow(d) || -d3.polygonArea(cell) > threshold, // If true, show the label
|
|
48
50
|
backgroundFill = "#fefefe01", // What to paint the bg rect of the labels. Needed for the onHover
|
|
49
51
|
strokeWidth = 5,
|
|
50
52
|
|
|
@@ -63,10 +65,10 @@ Receives the data, accessors for the x and y coordinates as well as the label. E
|
|
|
63
65
|
pointsFill = "#ccc",
|
|
64
66
|
pointsSelectedFill = "firebrick",
|
|
65
67
|
pointsStroke = "#ccc",
|
|
66
|
-
renderer = "svg",
|
|
67
68
|
debug = false,
|
|
68
69
|
selected = null,
|
|
69
70
|
padding = 3, // label padding in pixels
|
|
71
|
+
|
|
70
72
|
}
|
|
71
73
|
```
|
|
72
74
|
|
package/dist/smartLabels.es.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// smart-labels v0.0.
|
|
1
|
+
// smart-labels v0.0.6 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
|
|
@@ -26,15 +26,18 @@ function smartLabels(
|
|
|
26
26
|
label = (d, i) => i, // Accessor for the label
|
|
27
27
|
fill = "#333", // label fill color
|
|
28
28
|
stroke = "white", // label stroke color
|
|
29
|
-
threshold = 2000, // Areas over this size would get labels
|
|
30
29
|
width = null,
|
|
31
30
|
height = null,
|
|
32
31
|
target = null, // Where do you want it to draw
|
|
33
|
-
|
|
32
|
+
renderer = "svg", // canvas or svg
|
|
33
|
+
font = () => "18px sans-serif",
|
|
34
34
|
hover = true, // Show label of the hovered point
|
|
35
35
|
onHover = (i) => i, // callback when hovered, will pass the index of the selected element
|
|
36
|
-
hoverFont = "bolder 12px sans-serif",
|
|
36
|
+
hoverFont = () => "bolder 12px sans-serif",
|
|
37
37
|
labelsInCentroids = true,
|
|
38
|
+
threshold = 2000, // Areas over this size would get labels
|
|
39
|
+
alwaysShow = (d) => false, // If returns true for the node, it will always show the label
|
|
40
|
+
showLabel = (d, cell) => alwaysShow(d) || -d3.polygonArea(cell) > threshold, // If true, show the label
|
|
38
41
|
|
|
39
42
|
backgroundFill = "#fefefe01", // What to paint the bg rect of the labels. Needed for the onHover
|
|
40
43
|
strokeWidth = 5,
|
|
@@ -54,7 +57,6 @@ function smartLabels(
|
|
|
54
57
|
pointsFill = "#ccc",
|
|
55
58
|
pointsSelectedFill = "firebrick",
|
|
56
59
|
pointsStroke = "#ccc",
|
|
57
|
-
renderer = "svg",
|
|
58
60
|
debug = false,
|
|
59
61
|
selected = null,
|
|
60
62
|
padding = 3, // label padding in pixels
|
|
@@ -68,6 +70,9 @@ function smartLabels(
|
|
|
68
70
|
y(d, index) !== null
|
|
69
71
|
);
|
|
70
72
|
|
|
73
|
+
if (typeof font === "string") font = () => font;
|
|
74
|
+
if (typeof hoverFont === "string") hoverFont = () => hoverFont;
|
|
75
|
+
|
|
71
76
|
let xExtent = d3.extent(data, x),
|
|
72
77
|
yExtent = d3.extent(data, y);
|
|
73
78
|
width = width || xExtent[1] - xExtent[0];
|
|
@@ -87,8 +92,17 @@ function smartLabels(
|
|
|
87
92
|
}
|
|
88
93
|
|
|
89
94
|
if (target && !checkIfTargetMatchesRenderer(target, renderer)) {
|
|
90
|
-
if (debug)
|
|
91
|
-
|
|
95
|
+
if (debug)
|
|
96
|
+
console.log(
|
|
97
|
+
"❌ smartLabels Target doesn't match the renderer",
|
|
98
|
+
target,
|
|
99
|
+
renderer
|
|
100
|
+
);
|
|
101
|
+
throw new Error(
|
|
102
|
+
"Smartlabels Target doesn't match the renderer",
|
|
103
|
+
target,
|
|
104
|
+
renderer
|
|
105
|
+
);
|
|
92
106
|
}
|
|
93
107
|
|
|
94
108
|
// Try to reuse the target
|
|
@@ -120,7 +134,7 @@ function smartLabels(
|
|
|
120
134
|
// Replace null cells with the nearest one
|
|
121
135
|
cells = cells
|
|
122
136
|
.map(([d, cell], index) => [d, getNearestCell(d, cell, index)])
|
|
123
|
-
.map(([d, cell]) => ({ d, cell, show:
|
|
137
|
+
.map(([d, cell]) => ({ d, cell, show: showLabel(d, cell) }));
|
|
124
138
|
|
|
125
139
|
// cells can be null when we have duplicated coords
|
|
126
140
|
// https://github.com/d3/d3-delaunay/issues/106
|
|
@@ -239,7 +253,7 @@ function smartLabels(
|
|
|
239
253
|
.selectAll("text")
|
|
240
254
|
.data((d) => d)
|
|
241
255
|
.join("text")
|
|
242
|
-
.style("font", font)
|
|
256
|
+
.style("font", ({d}, i) => font(d, i))
|
|
243
257
|
.each(function ({ d, cell }, index) {
|
|
244
258
|
if (!cell) return;
|
|
245
259
|
const [cx, cy] = d3.polygonCentroid(cell);
|
|
@@ -285,7 +299,9 @@ function smartLabels(
|
|
|
285
299
|
.attr("display", ({ show }, i) =>
|
|
286
300
|
i === selected || show ? null : "none"
|
|
287
301
|
)
|
|
288
|
-
.style("font", (
|
|
302
|
+
.style("font", ({d}, i) =>
|
|
303
|
+
i === selected ? hoverFont(d, i) : font(d, i)
|
|
304
|
+
)
|
|
289
305
|
.classed("selected", (_, i) => i === selected)
|
|
290
306
|
.filter((_, i) => i === selected)
|
|
291
307
|
.raise();
|
|
@@ -411,7 +427,7 @@ function smartLabels(
|
|
|
411
427
|
: angle === 2
|
|
412
428
|
? "middle"
|
|
413
429
|
: "bottom";
|
|
414
|
-
context.font = index === selected ? hoverFont : font;
|
|
430
|
+
context.font = index === selected ? hoverFont(d, index) : font(d, index);
|
|
415
431
|
context.fillStyle = fill;
|
|
416
432
|
context.strokeStyle = stroke;
|
|
417
433
|
context.lineWidth = strokeWidth;
|
package/dist/smartLabels.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// smart-labels v0.0.
|
|
1
|
+
// smart-labels v0.0.6 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) :
|
|
@@ -49,15 +49,18 @@ function smartLabels(
|
|
|
49
49
|
label = (d, i) => i, // Accessor for the label
|
|
50
50
|
fill = "#333", // label fill color
|
|
51
51
|
stroke = "white", // label stroke color
|
|
52
|
-
threshold = 2000, // Areas over this size would get labels
|
|
53
52
|
width = null,
|
|
54
53
|
height = null,
|
|
55
54
|
target = null, // Where do you want it to draw
|
|
56
|
-
|
|
55
|
+
renderer = "svg", // canvas or svg
|
|
56
|
+
font = () => "18px sans-serif",
|
|
57
57
|
hover = true, // Show label of the hovered point
|
|
58
58
|
onHover = (i) => i, // callback when hovered, will pass the index of the selected element
|
|
59
|
-
hoverFont = "bolder 12px sans-serif",
|
|
59
|
+
hoverFont = () => "bolder 12px sans-serif",
|
|
60
60
|
labelsInCentroids = true,
|
|
61
|
+
threshold = 2000, // Areas over this size would get labels
|
|
62
|
+
alwaysShow = (d) => false, // If returns true for the node, it will always show the label
|
|
63
|
+
showLabel = (d, cell) => alwaysShow(d) || -d3__namespace.polygonArea(cell) > threshold, // If true, show the label
|
|
61
64
|
|
|
62
65
|
backgroundFill = "#fefefe01", // What to paint the bg rect of the labels. Needed for the onHover
|
|
63
66
|
strokeWidth = 5,
|
|
@@ -77,7 +80,6 @@ function smartLabels(
|
|
|
77
80
|
pointsFill = "#ccc",
|
|
78
81
|
pointsSelectedFill = "firebrick",
|
|
79
82
|
pointsStroke = "#ccc",
|
|
80
|
-
renderer = "svg",
|
|
81
83
|
debug = false,
|
|
82
84
|
selected = null,
|
|
83
85
|
padding = 3, // label padding in pixels
|
|
@@ -91,6 +93,9 @@ function smartLabels(
|
|
|
91
93
|
y(d, index) !== null
|
|
92
94
|
);
|
|
93
95
|
|
|
96
|
+
if (typeof font === "string") font = () => font;
|
|
97
|
+
if (typeof hoverFont === "string") hoverFont = () => hoverFont;
|
|
98
|
+
|
|
94
99
|
let xExtent = d3__namespace.extent(data, x),
|
|
95
100
|
yExtent = d3__namespace.extent(data, y);
|
|
96
101
|
width = width || xExtent[1] - xExtent[0];
|
|
@@ -110,8 +115,17 @@ function smartLabels(
|
|
|
110
115
|
}
|
|
111
116
|
|
|
112
117
|
if (target && !checkIfTargetMatchesRenderer(target, renderer)) {
|
|
113
|
-
if (debug)
|
|
114
|
-
|
|
118
|
+
if (debug)
|
|
119
|
+
console.log(
|
|
120
|
+
"❌ smartLabels Target doesn't match the renderer",
|
|
121
|
+
target,
|
|
122
|
+
renderer
|
|
123
|
+
);
|
|
124
|
+
throw new Error(
|
|
125
|
+
"Smartlabels Target doesn't match the renderer",
|
|
126
|
+
target,
|
|
127
|
+
renderer
|
|
128
|
+
);
|
|
115
129
|
}
|
|
116
130
|
|
|
117
131
|
// Try to reuse the target
|
|
@@ -143,7 +157,7 @@ function smartLabels(
|
|
|
143
157
|
// Replace null cells with the nearest one
|
|
144
158
|
cells = cells
|
|
145
159
|
.map(([d, cell], index) => [d, getNearestCell(d, cell, index)])
|
|
146
|
-
.map(([d, cell]) => ({ d, cell, show:
|
|
160
|
+
.map(([d, cell]) => ({ d, cell, show: showLabel(d, cell) }));
|
|
147
161
|
|
|
148
162
|
// cells can be null when we have duplicated coords
|
|
149
163
|
// https://github.com/d3/d3-delaunay/issues/106
|
|
@@ -262,7 +276,7 @@ function smartLabels(
|
|
|
262
276
|
.selectAll("text")
|
|
263
277
|
.data((d) => d)
|
|
264
278
|
.join("text")
|
|
265
|
-
.style("font", font)
|
|
279
|
+
.style("font", ({d}, i) => font(d, i))
|
|
266
280
|
.each(function ({ d, cell }, index) {
|
|
267
281
|
if (!cell) return;
|
|
268
282
|
const [cx, cy] = d3__namespace.polygonCentroid(cell);
|
|
@@ -308,7 +322,9 @@ function smartLabels(
|
|
|
308
322
|
.attr("display", ({ show }, i) =>
|
|
309
323
|
i === selected || show ? null : "none"
|
|
310
324
|
)
|
|
311
|
-
.style("font", (
|
|
325
|
+
.style("font", ({d}, i) =>
|
|
326
|
+
i === selected ? hoverFont(d, i) : font(d, i)
|
|
327
|
+
)
|
|
312
328
|
.classed("selected", (_, i) => i === selected)
|
|
313
329
|
.filter((_, i) => i === selected)
|
|
314
330
|
.raise();
|
|
@@ -434,7 +450,7 @@ function smartLabels(
|
|
|
434
450
|
: angle === 2
|
|
435
451
|
? "middle"
|
|
436
452
|
: "bottom";
|
|
437
|
-
context.font = index === selected ? hoverFont : font;
|
|
453
|
+
context.font = index === selected ? hoverFont(d, index) : font(d, index);
|
|
438
454
|
context.fillStyle = fill;
|
|
439
455
|
context.strokeStyle = stroke;
|
|
440
456
|
context.lineWidth = strokeWidth;
|
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",
|
|
1
|
+
// smart-labels v0.0.6 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=()=>"18px sans-serif",hover:g=!0,onHover:p=t=>t,hoverFont:y=()=>"bolder 12px 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}={}){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&&(u=()=>u),"string"==typeof y&&(y=()=>y);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
package/src/index.js
CHANGED
|
@@ -24,15 +24,18 @@ export default function smartLabels(
|
|
|
24
24
|
label = (d, i) => i, // Accessor for the label
|
|
25
25
|
fill = "#333", // label fill color
|
|
26
26
|
stroke = "white", // label stroke color
|
|
27
|
-
threshold = 2000, // Areas over this size would get labels
|
|
28
27
|
width = null,
|
|
29
28
|
height = null,
|
|
30
29
|
target = null, // Where do you want it to draw
|
|
31
|
-
|
|
30
|
+
renderer = "svg", // canvas or svg
|
|
31
|
+
font = () => "18px sans-serif",
|
|
32
32
|
hover = true, // Show label of the hovered point
|
|
33
33
|
onHover = (i) => i, // callback when hovered, will pass the index of the selected element
|
|
34
|
-
hoverFont = "bolder 12px sans-serif",
|
|
34
|
+
hoverFont = () => "bolder 12px sans-serif",
|
|
35
35
|
labelsInCentroids = true,
|
|
36
|
+
threshold = 2000, // Areas over this size would get labels
|
|
37
|
+
alwaysShow = (d) => false, // If returns true for the node, it will always show the label
|
|
38
|
+
showLabel = (d, cell) => alwaysShow(d) || -d3.polygonArea(cell) > threshold, // If true, show the label
|
|
36
39
|
|
|
37
40
|
backgroundFill = "#fefefe01", // What to paint the bg rect of the labels. Needed for the onHover
|
|
38
41
|
strokeWidth = 5,
|
|
@@ -52,7 +55,6 @@ export default function smartLabels(
|
|
|
52
55
|
pointsFill = "#ccc",
|
|
53
56
|
pointsSelectedFill = "firebrick",
|
|
54
57
|
pointsStroke = "#ccc",
|
|
55
|
-
renderer = "svg",
|
|
56
58
|
debug = false,
|
|
57
59
|
selected = null,
|
|
58
60
|
padding = 3, // label padding in pixels
|
|
@@ -66,6 +68,9 @@ export default function smartLabels(
|
|
|
66
68
|
y(d, index) !== null
|
|
67
69
|
);
|
|
68
70
|
|
|
71
|
+
if (typeof font === "string") font = () => font;
|
|
72
|
+
if (typeof hoverFont === "string") hoverFont = () => hoverFont;
|
|
73
|
+
|
|
69
74
|
let xExtent = d3.extent(data, x),
|
|
70
75
|
yExtent = d3.extent(data, y);
|
|
71
76
|
width = width || xExtent[1] - xExtent[0];
|
|
@@ -85,8 +90,17 @@ export default function smartLabels(
|
|
|
85
90
|
}
|
|
86
91
|
|
|
87
92
|
if (target && !checkIfTargetMatchesRenderer(target, renderer)) {
|
|
88
|
-
if (debug)
|
|
89
|
-
|
|
93
|
+
if (debug)
|
|
94
|
+
console.log(
|
|
95
|
+
"❌ smartLabels Target doesn't match the renderer",
|
|
96
|
+
target,
|
|
97
|
+
renderer
|
|
98
|
+
);
|
|
99
|
+
throw new Error(
|
|
100
|
+
"Smartlabels Target doesn't match the renderer",
|
|
101
|
+
target,
|
|
102
|
+
renderer
|
|
103
|
+
);
|
|
90
104
|
}
|
|
91
105
|
|
|
92
106
|
// Try to reuse the target
|
|
@@ -118,7 +132,7 @@ export default function smartLabels(
|
|
|
118
132
|
// Replace null cells with the nearest one
|
|
119
133
|
cells = cells
|
|
120
134
|
.map(([d, cell], index) => [d, getNearestCell(d, cell, index)])
|
|
121
|
-
.map(([d, cell]) => ({ d, cell, show:
|
|
135
|
+
.map(([d, cell]) => ({ d, cell, show: showLabel(d, cell) }));
|
|
122
136
|
|
|
123
137
|
// cells can be null when we have duplicated coords
|
|
124
138
|
// https://github.com/d3/d3-delaunay/issues/106
|
|
@@ -237,7 +251,7 @@ export default function smartLabels(
|
|
|
237
251
|
.selectAll("text")
|
|
238
252
|
.data((d) => d)
|
|
239
253
|
.join("text")
|
|
240
|
-
.style("font", font)
|
|
254
|
+
.style("font", ({d}, i) => font(d, i))
|
|
241
255
|
.each(function ({ d, cell }, index) {
|
|
242
256
|
if (!cell) return;
|
|
243
257
|
const [cx, cy] = d3.polygonCentroid(cell);
|
|
@@ -283,7 +297,9 @@ export default function smartLabels(
|
|
|
283
297
|
.attr("display", ({ show }, i) =>
|
|
284
298
|
i === selected || show ? null : "none"
|
|
285
299
|
)
|
|
286
|
-
.style("font", (
|
|
300
|
+
.style("font", ({d}, i) =>
|
|
301
|
+
i === selected ? hoverFont(d, i) : font(d, i)
|
|
302
|
+
)
|
|
287
303
|
.classed("selected", (_, i) => i === selected)
|
|
288
304
|
.filter((_, i) => i === selected)
|
|
289
305
|
.raise();
|
|
@@ -409,7 +425,7 @@ export default function smartLabels(
|
|
|
409
425
|
: angle === 2
|
|
410
426
|
? "middle"
|
|
411
427
|
: "bottom";
|
|
412
|
-
context.font = index === selected ? hoverFont : font;
|
|
428
|
+
context.font = index === selected ? hoverFont(d, index) : font(d, index);
|
|
413
429
|
context.fillStyle = fill;
|
|
414
430
|
context.strokeStyle = stroke;
|
|
415
431
|
context.lineWidth = strokeWidth;
|