1- import { extent , namespaces } from "d3" ;
1+ import { extent , namespaces , polygonCentroid } from "d3" ;
2+ import { valueObject } from "../channel.js" ;
23import { create } from "../context.js" ;
34import { composeRender } from "../mark.js" ;
45import { hasXY , identity , indexOf } from "../options.js" ;
56import { applyChannelStyles , applyDirectStyles , applyIndirectStyles , getPatternId } from "../style.js" ;
67import { template } from "../template.js" ;
8+ import { initializer } from "../transforms/basic.js" ;
79import { maybeIdentityX , maybeIdentityY } from "../transforms/identity.js" ;
810import { maybeIntervalX , maybeIntervalY } from "../transforms/interval.js" ;
911import { maybeStackX , maybeStackY } from "../transforms/stack.js" ;
@@ -14,8 +16,10 @@ const waffleDefaults = {
1416} ;
1517
1618export class WaffleX extends BarX {
17- constructor ( data , { unit = 1 , gap = 1 , round, render, multiple, ...options } = { } ) {
18- super ( data , { ...options , render : composeRender ( render , waffleRender ( "x" ) ) } , waffleDefaults ) ;
19+ constructor ( data , { unit = 1 , gap = 1 , round, render, multiple, tip, ...options } = { } ) {
20+ options = initializer ( { ...options , render : composeRender ( render , waffleRender ( "x" ) ) } , waffleInitializer ( "x" ) ) ;
21+ if ( tip ) options = initializer ( { ...options , tip} , waffleTipInitializer ( "x" ) ) ;
22+ super ( data , options , waffleDefaults ) ;
1923 this . unit = Math . max ( 0 , unit ) ;
2024 this . gap = + gap ;
2125 this . round = maybeRound ( round ) ;
@@ -24,19 +28,22 @@ export class WaffleX extends BarX {
2428}
2529
2630export class WaffleY extends BarY {
27- constructor ( data , { unit = 1 , gap = 1 , round, render, multiple, ...options } = { } ) {
28- super ( data , { ...options , render : composeRender ( render , waffleRender ( "y" ) ) } , waffleDefaults ) ;
31+ constructor ( data , { unit = 1 , gap = 1 , round, render, multiple, tip, ...options } = { } ) {
32+ options = initializer ( { ...options , render : composeRender ( render , waffleRender ( "y" ) ) } , waffleInitializer ( "y" ) ) ;
33+ if ( tip ) options = initializer ( { ...options , tip} , waffleTipInitializer ( "y" ) ) ;
34+ super ( data , options , waffleDefaults ) ;
2935 this . unit = Math . max ( 0 , unit ) ;
3036 this . gap = + gap ;
3137 this . round = maybeRound ( round ) ;
3238 this . multiple = maybeMultiple ( multiple ) ;
3339 }
3440}
3541
36- function waffleRender ( y ) {
37- return function ( index , scales , values , dimensions , context ) {
38- const { unit, gap, rx, ry, round} = this ;
39- const { document} = context ;
42+ function waffleInitializer ( y ) {
43+ return function ( data , facets , channels , scales , dimensions ) {
44+ const { round, unit} = this ;
45+
46+ const values = valueObject ( channels , scales ) ;
4047 const Y1 = values . channels [ `${ y } 1` ] . value ;
4148 const Y2 = values . channels [ `${ y } 2` ] . value ;
4249
@@ -56,9 +63,65 @@ function waffleRender(y) {
5663
5764 // TODO insets?
5865 const transform = y === "y" ? ( [ x , y ] ) => [ x * cx , - y * cy ] : ( [ x , y ] ) => [ y * cy , x * cx ] ;
66+ const P = Array . from ( Y1 , ( _ , i ) => wafflePoints ( round ( Y1 [ i ] / unit ) , round ( Y2 [ i ] / unit ) , multiple ) . map ( transform ) ) ;
67+
5968 const tx = ( barwidth - multiple * cx ) / 2 ;
60- const x0 = typeof barx === "function" ? ( i ) => barx ( i ) + tx : barx + tx ;
61- const y0 = scales [ y ] ( 0 ) ;
69+ this . x0 = typeof barx === "function" ? ( i ) => barx ( i ) + tx : barx + tx ;
70+ this . y0 = scales [ y ] ( 0 ) ;
71+ this . cx = cx ;
72+ this . cy = cy ;
73+ this . barwidth = barwidth ;
74+ this . barx = barx ;
75+ this . multiple = multiple ;
76+
77+ return { channels : { polygon : { value : P , source : null } } } ;
78+ } ;
79+ }
80+
81+ function waffleTipInitializer ( y ) {
82+ return function ( data , facets , channels ) {
83+ const { x0, y0, barwidth} = this ;
84+ const P = channels . polygon . value ;
85+ const n = P . length ;
86+ const tx = typeof x0 === "function" ? ( i ) => x0 ( i ) - barwidth / 2 : ( ) => x0 ;
87+ const ty = typeof y0 === "function" ? y0 : ( ) => y0 ;
88+
89+ const X = new Float64Array ( n ) ;
90+ const Y = new Float64Array ( n ) ;
91+
92+ const [ ix , iy ] = y === "y" ? [ 0 , 1 ] : [ 1 , 0 ] ;
93+ for ( let i = 0 ; i < n ; ++ i ) {
94+ const c = polygonCentroid ( P [ i ] ) ;
95+ X [ i ] = c [ ix ] + tx ( i ) ;
96+ Y [ i ] = c [ iy ] + ty ( i ) ;
97+ }
98+
99+ // restore the tip value for y
100+ const source = channels [ `${ y } 2` ] . hint ?. length
101+ ? {
102+ ...channels [ `${ y } 1` ] ,
103+ value : Array . from ( channels [ `${ y } 1` ] . value , ( d , i ) => channels [ `${ y } 2` ] . value [ i ] - d ) ,
104+ hint : { single : true }
105+ }
106+ : null ;
107+
108+ const x = y === "y" ? "x" : "y" ;
109+ return {
110+ channels : {
111+ [ `${ x } 1` ] : { value : X , scale : null , source : null } ,
112+ [ `${ x } 2` ] : { value : X , scale : null , source : null } ,
113+ [ `${ y } 1` ] : { value : Y , scale : null , source} ,
114+ [ `${ y } 2` ] : { value : Y , scale : null , source}
115+ }
116+ } ;
117+ } ;
118+ }
119+
120+ function waffleRender ( y ) {
121+ return function ( index , scales , values , dimensions , context ) {
122+ const { gap, cx, cy, rx, ry, x0, y0} = this ;
123+ const { document} = context ;
124+ const polygon = values . channels . polygon . value ;
62125
63126 // Create a base pattern with shared attributes for cloning.
64127 const patternId = getPatternId ( ) ;
@@ -95,13 +158,7 @@ function waffleRender(y) {
95158 . enter ( )
96159 . append ( "path" )
97160 . attr ( "transform" , y === "y" ? template `translate(${ x0 } ,${ y0 } )` : template `translate(${ y0 } ,${ x0 } )` )
98- . attr (
99- "d" ,
100- ( i ) =>
101- `M${ wafflePoints ( round ( Y1 [ i ] / unit ) , round ( Y2 [ i ] / unit ) , multiple )
102- . map ( transform )
103- . join ( "L" ) } Z`
104- )
161+ . attr ( "d" , ( i ) => `M${ polygon [ i ] . join ( "L" ) } Z` )
105162 . attr ( "fill" , ( i ) => `url(#${ patternId } -${ i } )` )
106163 . attr ( "stroke" , this . stroke == null ? null : ( i ) => `url(#${ patternId } -${ i } )` )
107164 )
@@ -198,12 +255,12 @@ function spread(domain) {
198255 return max - min ;
199256}
200257
201- export function waffleX ( data , options = { } ) {
258+ export function waffleX ( data , { tip , ... options } = { } ) {
202259 if ( ! hasXY ( options ) ) options = { ...options , y : indexOf , x2 : identity } ;
203- return new WaffleX ( data , maybeStackX ( maybeIntervalX ( maybeIdentityX ( options ) ) ) ) ;
260+ return new WaffleX ( data , { tip , ... maybeStackX ( maybeIntervalX ( maybeIdentityX ( options ) ) ) } ) ;
204261}
205262
206- export function waffleY ( data , options = { } ) {
263+ export function waffleY ( data , { tip , ... options } = { } ) {
207264 if ( ! hasXY ( options ) ) options = { ...options , x : indexOf , y2 : identity } ;
208- return new WaffleY ( data , maybeStackY ( maybeIntervalY ( maybeIdentityY ( options ) ) ) ) ;
265+ return new WaffleY ( data , { tip , ... maybeStackY ( maybeIntervalY ( maybeIdentityY ( options ) ) ) } ) ;
209266}
0 commit comments