1
- import { geoCentroid as GeoCentroid , geoPath } from "d3" ;
1
+ import { geoCentroid as GeoCentroid , geoPath , greatest , polygonArea , polygonContains } from "d3" ;
2
2
import { memoize1 } from "../memoize.js" ;
3
3
import { identity , valueof } from "../options.js" ;
4
4
import { initializer } from "./basic.js" ;
5
+ import polylabel from "polylabel" ;
5
6
6
7
export function centroid ( { geometry = identity , ...options } = { } ) {
7
8
const getG = memoize1 ( ( data ) => valueof ( data , geometry ) ) ;
@@ -28,6 +29,55 @@ export function centroid({geometry = identity, ...options} = {}) {
28
29
) ;
29
30
}
30
31
32
+ export function poi ( { geometry = identity , ...options } = { } ) {
33
+ const getG = memoize1 ( ( data ) => valueof ( data , geometry ) ) ;
34
+ return initializer (
35
+ { ...options , x : null , y : null , geometry : { transform : getG } } ,
36
+ ( data , facets , channels , scales , dimensions , { projection} ) => {
37
+ const G = getG ( data ) ;
38
+ const n = G . length ;
39
+ const X = new Float64Array ( n ) ;
40
+ const Y = new Float64Array ( n ) ;
41
+ let polygons , holes , ring ;
42
+ const alpha = 2 ;
43
+ const context = {
44
+ arc ( ) { } ,
45
+ moveTo ( x , y ) {
46
+ ring = [ [ x , - alpha * y ] ] ;
47
+ } ,
48
+ lineTo ( x , y ) {
49
+ ring . push ( [ x , - alpha * y ] ) ;
50
+ } ,
51
+ closePath ( ) {
52
+ ring . push ( ring [ 0 ] ) ;
53
+ if ( polygonArea ( ring ) > 0 ) polygons . push ( [ ring ] ) ;
54
+ else holes . push ( ring ) ;
55
+ }
56
+ } ;
57
+ const path = geoPath ( projection , context ) ;
58
+ for ( let i = 0 ; i < n ; ++ i ) {
59
+ polygons = [ ] ;
60
+ holes = [ ] ;
61
+ path ( G [ i ] ) ;
62
+ for ( const h of holes ) polygons . find ( ( [ ring ] ) => polygonContains ( ring , h [ 0 ] ) ) ?. push ( h ) ;
63
+ const a = greatest (
64
+ polygons . map ( ( d ) => polylabel ( d ) ) ,
65
+ ( d ) => d . distance
66
+ ) ;
67
+ [ X [ i ] , Y [ i ] ] = a ? [ a [ 0 ] , - a [ 1 ] / alpha ] : path . centroid ( G [ i ] ) ;
68
+ }
69
+ return {
70
+ data,
71
+ facets,
72
+ channels : {
73
+ x : { value : X , scale : projection == null ? "x" : null , source : null } ,
74
+ y : { value : Y , scale : projection == null ? "y" : null , source : null }
75
+ }
76
+ } ;
77
+ }
78
+ ) ;
79
+ }
80
+
31
81
export function geoCentroid ( { geometry = identity , ...options } = { } ) {
32
82
const getG = memoize1 ( ( data ) => valueof ( data , geometry ) ) ;
33
83
const getC = memoize1 ( ( data ) => valueof ( getG ( data ) , GeoCentroid ) ) ;
0 commit comments