From 3df73d0e1f74b66e688a64e477c78d5ed3225f0a Mon Sep 17 00:00:00 2001 From: Robert Monfera Date: Wed, 13 Jan 2021 20:38:59 +0100 Subject: [PATCH] feat(partition): Flame and icicle chart (#965) * feat: flame and icicle chart * chore: no longer shadow variables in treemap and solving other partitioning warnings Co-authored-by: Nick Partridge Co-authored-by: Marco Vettorello --- .eslintrc.js | 5 +- .playground/playground.tsx | 33 +---- api/charts.api.md | 6 +- ...me-chart-visually-looks-correct-1-snap.png | Bin 0 -> 63235 bytes ...le-chart-visually-looks-correct-1-snap.png | Bin 0 -> 63827 bytes .../layout/types/config_types.ts | 2 + .../layout/utils/group_by_rollup.ts | 35 +++-- .../partition_chart/layout/utils/sunburst.ts | 13 +- .../partition_chart/layout/utils/treemap.ts | 19 ++- .../layout/viewmodel/hierarchy_of_arrays.ts | 4 +- .../layout/viewmodel/viewmodel.ts | 139 +++++++++++++----- .../renderer/canvas/canvas_renderers.ts | 6 +- .../renderer/dom/highlighter.tsx | 33 ++--- .../partition_chart/state/selectors/tree.ts | 15 +- src/mocks/hierarchical/index.ts | 2 + src/mocks/hierarchical/observability_tree.ts | 23 +++ stories/icicle/01_unix_icicle.tsx | 43 ++++++ stories/icicle/02_unix_flame.tsx | 43 ++++++ stories/icicle/icicle.stories.tsx | 30 ++++ .../interactions/4_sunburst_slice_clicks.tsx | 6 +- stories/legend/10_sunburst.tsx | 9 +- stories/stylings/20_partition_background.tsx | 9 +- stories/sunburst/15_single_sunburst.tsx | 9 +- stories/sunburst/26_percentage.tsx | 9 +- stories/sunburst/27_heterogeneous_depth.tsx | 9 +- stories/sunburst/3_value_formatted_2.tsx | 4 +- stories/sunburst/9_sunburst_three_layers.tsx | 9 +- stories/treemap/2_one_layer_2.tsx | 4 +- stories/utils/hierarchical_input_utils.tsx | 84 +++++++++++ stories/utils/utils.ts | 125 +++++++++++++++- 30 files changed, 552 insertions(+), 176 deletions(-) create mode 100644 integration/tests/__image_snapshots__/all-test-ts-baseline-visual-tests-for-all-stories-flame-alpha-flame-chart-visually-looks-correct-1-snap.png create mode 100644 integration/tests/__image_snapshots__/all-test-ts-baseline-visual-tests-for-all-stories-flame-alpha-icicle-chart-visually-looks-correct-1-snap.png create mode 100644 src/mocks/hierarchical/observability_tree.ts create mode 100644 stories/icicle/01_unix_icicle.tsx create mode 100644 stories/icicle/02_unix_flame.tsx create mode 100644 stories/icicle/icicle.stories.tsx create mode 100644 stories/utils/hierarchical_input_utils.tsx diff --git a/.eslintrc.js b/.eslintrc.js index 1a61524f2d..5838f5f875 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -81,7 +81,8 @@ module.exports = { 'global-require': 1, 'import/no-dynamic-require': 1, 'no-shadow': 1, - 'no-param-reassign': 1, + 'no-param-reassign': [1, { props: false }], + '@typescript-eslint/comma-spacing': 0, 'react/no-array-index-key': 1, 'react/prefer-stateless-function': 1, 'react/require-default-props': 'off', @@ -342,7 +343,7 @@ module.exports = { 'prefer-destructuring': [ 'warn', { - array: true, + array: false, object: true, }, { diff --git a/.playground/playground.tsx b/.playground/playground.tsx index 13036f2204..3c9f2ee240 100644 --- a/.playground/playground.tsx +++ b/.playground/playground.tsx @@ -38,39 +38,10 @@ import React from 'react'; -import { Chart, Settings, Partition, PartitionLayout } from '../src'; +import { Example } from '../stories/icicle/01_unix_icicle'; export class Playground extends React.Component { render() { - return ( -
- - - d.val as number} - layers={[ - { - groupByRollup: (d: any) => d.cat1, - }, - { - groupByRollup: (d: any) => d.cat2, - }, - ]} - config={{ - partitionLayout: PartitionLayout.sunburst, - }} - /> - -
- ); + return ; } } diff --git a/api/charts.api.md b/api/charts.api.md index 5c1859c6e8..dea40bc007 100644 --- a/api/charts.api.md +++ b/api/charts.api.md @@ -1258,6 +1258,8 @@ export interface PartitionLayer { export const PartitionLayout: Readonly<{ sunburst: "sunburst"; treemap: "treemap"; + icicle: "icicle"; + flame: "flame"; }>; // @public (undocumented) @@ -1958,8 +1960,8 @@ export type YDomainRange = YDomainBase & DomainRange; // src/chart_types/heatmap/layout/types/config_types.ts:28:13 - (ae-forgotten-export) The symbol "SizeRatio" needs to be exported by the entry point index.d.ts // src/chart_types/heatmap/layout/types/config_types.ts:60:5 - (ae-forgotten-export) The symbol "TextAlign" needs to be exported by the entry point index.d.ts // src/chart_types/heatmap/layout/types/config_types.ts:61:5 - (ae-forgotten-export) The symbol "TextBaseline" needs to be exported by the entry point index.d.ts -// src/chart_types/partition_chart/layout/types/config_types.ts:126:5 - (ae-forgotten-export) The symbol "TimeMs" needs to be exported by the entry point index.d.ts -// src/chart_types/partition_chart/layout/types/config_types.ts:127:5 - (ae-forgotten-export) The symbol "AnimKeyframe" needs to be exported by the entry point index.d.ts +// src/chart_types/partition_chart/layout/types/config_types.ts:128:5 - (ae-forgotten-export) The symbol "TimeMs" needs to be exported by the entry point index.d.ts +// src/chart_types/partition_chart/layout/types/config_types.ts:129:5 - (ae-forgotten-export) The symbol "AnimKeyframe" needs to be exported by the entry point index.d.ts // src/chart_types/partition_chart/specs/index.ts:48:13 - (ae-forgotten-export) The symbol "NodeColorAccessor" needs to be exported by the entry point index.d.ts // src/commons/series_id.ts:39:3 - (ae-forgotten-export) The symbol "SeriesKey" needs to be exported by the entry point index.d.ts diff --git a/integration/tests/__image_snapshots__/all-test-ts-baseline-visual-tests-for-all-stories-flame-alpha-flame-chart-visually-looks-correct-1-snap.png b/integration/tests/__image_snapshots__/all-test-ts-baseline-visual-tests-for-all-stories-flame-alpha-flame-chart-visually-looks-correct-1-snap.png new file mode 100644 index 0000000000000000000000000000000000000000..b4a00fc2e44e104dbe45e4778eb4355726a792da GIT binary patch literal 63235 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 E3lh#U^#A|> literal 0 HcmV?d00001 diff --git a/integration/tests/__image_snapshots__/all-test-ts-baseline-visual-tests-for-all-stories-flame-alpha-icicle-chart-visually-looks-correct-1-snap.png b/integration/tests/__image_snapshots__/all-test-ts-baseline-visual-tests-for-all-stories-flame-alpha-icicle-chart-visually-looks-correct-1-snap.png new file mode 100644 index 0000000000000000000000000000000000000000..f23daebae8edb94d2f623a5f2299ca88bda9099d GIT binary patch literal 63827 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
mMpjE3+1Q26tTB;eeRyn}1 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
UO43*BQO9nk8 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 $tI+)=_cI%3T~ z#T!G{Bvp$qJ|A@(d7y=SZ@iv;OmQ)|_G)!{^6P_p*F;xGzo`L8D&`g}z1-sLDRf~( z?7@fHx_Pn!XuvbEr^%2n%Z0&m-0iy8ev|I{Ygy}UD$>Tl>6&coNAC_S6AnEU1IXuI~<_P)Y0TeOTMOHo6b>_h5^jp%y zl-8oh6q`RR%ScmdAIncIufPT%4D&w z%Fe}Qt!k(0+UnM-CG}!XG5ls~v+UU7Oce$w8;qBK)NM~@(!qqr({7FD&=hM`y!7Da z=1b%9>sl&X{^PP(ePLXYc(c=E+*>)g#k}>J2(z<{zl;&pi`1If`06)nNS#6ArFr=OzyzX=>}BG_+s~to^+-%Mf}F691*cW(82;ABuWZI$6nt~=jwxlol{*OsGz`+jnZj> zFS+>n5j508f5l%^jXz90S||g?^4s>|ro_#u@y*?Q`12l;(INsMOpTKe_PcHI*Xp~W zA6VmaO~9m-VfOrOmdtJ`Sd|-oW>x3OY3u1_2~_RC#6QPnq%@V!p;W-@XrU&^SLe_1 zDRp>ST7-*e`0{dQtC*zZQ${!K08@rk1^vLz;(-$kpo(=v$(Gu><`B8LiENRHdeb2Y z)=mKWg1v>CC4OqLWUz&BVu_0K0x2gl{%isfx62mv$|oT4-+ljROy3j1$abRIf|j-% zHOcTNY!@Hb3*dDwMz7t{5l_c$eMc@%%EpE&3L%F0!A74Shw%MHlFrYc_o!8yMOisv zVq!Y*43Ejn7O8mO*W1AA4yH!iHdR#Edp;Zp(rYzK<@N~$j(ty1-FbdNgh}L=x7Dd` zkLJQoE-ns|WZM)YZ-R1)fY-fYcXgkylL{}e#ukss%T`hwX{8-7GU92bPRY(DE>VFM zkdUAT$y2f;K&VMCpT#jIKX!BZp!@FM8COUFyTe@$Y0?a; z%gY10&$BkbR2(jI`3W)`BBxMLAZeyhXJ=>Ja0;lifq_EH$@*shl%>^NBkU6!-OXuH z!{CFnN_vma*&o3Wtg))co*c6pjoPD^25Y(2aJvIjLvhE)Vo+xzB^Hw^IAD&LmCp2z z?_Bg_tIa}x;hRvay;UMYLOVOVVY{aw?lM8*fq zg+G-`D9s)-GM*O~o}@>VPh(?@FG%>}Ej1slHOlS!z5u~$a9D`R)UH$Wbm@g+*98*> z^IsM3x3^eG;XKWWa(QnwZM3V0@>N~vhxc@*%+^=pY`w&z6ImUQfI<1@T@FowViQG) z=1r!&W`Y_>{rn+si@@YGPutN+HpLG?xI1xp z-Dd5nN62isa)W+J0VFt$`!sR|MP-fy|Qc71H6loQZI<%w?r*tBK zxN?o>L9LR42BaX_)NyY-iXxm~eReu=%=Tm>)y;8_69z2!pv%Ye!?}wBLyx)tfIx!T zQ9-I-F-{k*m1sx)P7bJHx6GjPkUf}c)(P^1{UE>A;~SeXv`%kPwYEn%6l*8yt`$w%(wEq~B1M_YB&3yoW ztVS6pEiY#i^4li^l7Gu~`HPj{;G};A$m!r`X4c`cKPm#+EjWIX%D81DUhVlVYo)gQ z0XlzLEE4G+qe7?a^$h*t>Oa3ZK_p?AXnVY&GZb}A_ozKhDF6rfLqC18h`Vslr;hXQ zqRm$NAV-ZgXES)xs_+4;)*B`ksf+(h%92zST+TTDQ8q0$Ue4*sLu9luUf08|I?0w& zI%bZ-SCJCIxB=JGq6|Z#w{`fD@#4`KX)4wSYgD)HgKco`;P^dSBTQeHY43;>?AD)MiyNd+UQu z>?NJAJgu3NEyrWM?R)X?vbbyv!G$jV)D5lww(e?sNl>R6KdywKrvG*^=At25$>5^! zZL<~DDSuKDVt`I#yT1xqRI*J+y9}(_Q~M8NF-i6;m(fSEhhMpP6%z&4&_GAB#=8ez zUN{j$3hYog?f6=f*qmIG<>jA4d1!E86B1WgC^M|r-O_i{uzvyiz%hHI@W zdVl2+R8)De1Qy$yefcoJn_FFtyno6s$&-_V2O`34G)IcC{o23( zivEZz#j)$;E2YthD6a5UQy@<hB5tZJ9-o{rkBYW1RwX-zm2T7wqeQxX)D za5!0vPlT%(;iaj7mUlzFwzbAL%cqXq?BWGeB%AYbg zlzy#){kOjj1#i|JUJ#juT<6(z)_HTnBU?$Rsqs|tEhU!>&IynFmTf$KSbgx}XLZg^7j-E@D? zJcImra0Q8z(I9sb3C)0XOfFxwxuzdgjJH?u{zYj^EX~$1yRQ0C#MRC@v8yZA#!(S^ zeLYunlDWxKdMM$nOF`QMuX$L;&~_ICKgq`aj%KabMC*2VRcK3_*S8DSa;v^)fz2yD zrzEI$j|)UFxx?Fixw;V!yG9=r`H%XNChE-Qi!q!@ljt3d)G6p#{Wz;!7x0F2$9m8J7vX14#Xh} zk$d?ctI8F;`Njhmkx0CZBYUni)KDw^_KuuLfFxI7Kg~4$kK(>MEXuy?cCb)E5Cf$| zB&1t9lu|-kT9EFNZWRHMl5P+w5r<|d3F$_pC5Dt7y7O$_$LBfqo^!tMI@h@le{m7R zJD6oeYisAb?`IV8}9tZ5-1NiO>fXmKFQY;PZoC;p`bSUE5noa2A<#O z#6}%<>DB9!Us^8K_{2P+A-z25Zg24V*J&8~S?rLST*Jrkw7QIYj5(Z+uW9ZDCqCN5 zy)72dpLlz(Q?0g^5^?cLOVQDaPVkVB$y9{M0fqxL|dR(9Y?5s6Voe_6IHo8ke8Xa+w0qO<2nuJW+ z5@KTCg-8)v-)_|YT$wGH$h`U1cgzSbD}-zcopJtwnX>-2s-2{ajNZcLkh_2`qpWPh zON&Cq^!M%uTQcDDGgNL$M()8A2iU@Wx7z?jj*UsrNlg0|o}J#iOzMJO$Jc}z_ktbF zz3$$lk9(Hw)ylDr;eRt&vU1g2h1sZ1j)CXY)RG=;^k;dO-5iZ2_qUNm0p!5dw3uw-_o7PD`UA^s4@Z=<2Kv`RBjMJk6%*$w486-lw2Y z1$dWgoqXp>*fkyWFHQ@!E|ud&Yt4&uqd`(aH(_1n7+6vk#)Q=a|5AWdm*((ZRm3yQ zv_;RXm~&qy^?I0V1=&E#^f#|899(-jV;0;LbTIy0Hi4&Ol_1r0?CYhDI4))zas*J( zX^)P|IX%(|U~y8YvLdzHgvWET2op0VSaDDCS{M}pz%h6!XS(k#4Y|Dd@Z3$NaJs&i7kzl=q zm1liI5yzP$m-y>JC>1qirAy>Gr>M*nw!%c(>#_}#ndpEC>=Lj^r3xiBg{{VAK?#cqC{yOLo@88FsKO41&`9YDww zhP2Yt(+h6m{-4p^{>772?sG*6R)6?Hv=4b^EVDJi>nj*&1A`4`!qB0t(e zIWV;OQnqui-^sy&f)Co120iIs%1@tGw+oIb&yQ!R!G)bF@Cmrl%mHU?XNSb=X^FglWtfEUpH-yyhu9xbg>d*1qfUuZJm zLJ`>5*rcSSyD$5VBN!GFXPvb#=#`xs=EM0@yLj`Ea4j}N8{DmOi&jiU`h%v6ujLw zt`~QI5w{B_6Bb{c(2wab@*K+}@TTzI-&z<9R)% z&@>PzCRAwkg#X@&JCLU}7Qz#0Y~jt#2krS6+uJu`Q34?Wo0(%#GY35QmAK+XNlD4#NT-!w{<&32a)4}KRIYb;lSfur z{PP1lM;oMFwkH_AofAAvl`N_93uh-1qX(g`}8p%?a>qu+bKY6sO!tgM^0;RQM$c!-Ev-`pKJihnormuL13;vngW z3|s%7a?jD3dM+wRHG|+R|=-&5h1gfU82rgt$mxVsVv3P7r9dYI=v33Ct{Xc+SE%8+T#&w*igKXNanh7BI0 zChnPZ0fyubPxE#u(u?8Oe#w~{3$8+!HasvpK!AxFEm;YJs#!Z(pE z2KS&t096ZA3qodX37qN-7OJS~Hz8r6x>VqBPac)iINA~UGhM3cgPJxKTlilF_R^G` zn_N?kUhlh2>PI_*=9PpSr;ZtyyhgdvOa?1eq9GXTz5-qtX9fC5M{%r$o5H#xG541) zO=~@{_B?E50huS+QX_TuW-FDA!UOsLfMSs z6jpZ`UrVIktBWyZP@t{Je@Etj$ux$Eut;MO-_$}s%8*lIOWy2GlL zjZkdAC9%R3{f7=$zX`pYk_5oV7SGho-fYx%WOr5~^-`pi&ydBV6a+jARP!LeN%Cip zi6Lo8whytUj{qu5NdYZUtkGJnCu>PflGn^0mIh*o@wr`t+{{cv&bSs%Lp@G)>w%n} ztmP9-%d0a1)U(34L-#1NBGecQF!^kh*VCo^88y+v5mM)2HZ@%R#VklHqs4+jRchye zp$7d)G3#Lp!te1|07NplK%-5&sTh96op<8am%gn}`VU3z9pfx!*4SFUCRF$lT<7~0 z)^FVL!N_3io1pSnh080K?|eP9;>HW+lX$uu_}dfLmy@zOXV=?2x{f@1Wm!EiWu?UM zxCm)KH+nUB;iO%oVw00nnE6-NXngn3_P|%2sNWbf_LahpUQ?~4f${;-qlC_9vbgg! zD(=_C4AcZtX`H^dJUgk?BRC$GX_Rq1atzbB(q=12mEg_aDd-p|k!{pow7fKC9~SO) z)Db_$|8n!;MY6NRpOlYxs@~i>H?eoM?fF}gE(_FEvd|}rBITAB1Q`OvX_)!S#yRRv z5b9C>A=1=L)MxE79te4VkFe}WU~Hpm%p@RN+a;S-HoK(mJ2+<$NR-jkdg9moE=1Dv zYggJ^&UPb?ZUTR*`x(MrN|7AuG|Qd|MumIgk0}qE(y7w*JBvOLH#6^&))@3PJOJ@diRb|o&+c& zgYj{K-QuNYxZFLU9)5S~=rN%4Io>5&D~g?(;|n4L?%D!Wh~M{N45~+ldqX+XN z#VlD_S%`DkRr7Rn$=!Hw7$Q9vMWmr05}Qudf4(rY)t(evweL=v2kvyOc-yjQ6eK(n z9s8tO^TPAkP^oH`7bfQT!f`SH_~v@NZnvp?HT>}-6txb$2rHw_4NoK=!4GTNrr_i= zF94mr3kuS2AN03h_~{3zVLeE9rONxh>Ov*T<(7IrdAWknA-4 z8U2}>h)4pVH#NCuQhVc9(V|o)v&XLOsIPmIirU}PJ`vsFnGafRo_uc5`5P7ba;N8F$UzXVvO@=^TW>XCv>3{PJis}~P3bltz*c@vTG{oN^*UR7*7 zJUpx$8*;p**8Ch99<^`I3)}Ec(<6qR&gEO9Df+)^wfiQk*i6saYLXT(ZhZF(r_~-w zw2U7pG??H9wX4eU;o_4deFnyVnlKv*c6y+y*4Fm=@&Dsg6fs--nPdk!6xihHNdpiOu=KL-Z@eu*PK4Bd$A3 zt@9kS1zX*jB@QEO8?#r|6H_19mnrEtwSFl`n7T$wC*3ppWd!NpbQj;Fp8gX21|1m4y<#8JCx> z+(-!sTGHE82MY`{Et9Dv>l+&;){1A z%w;|F9XNI#xE--7E3mGTkTeaTnPHK!%^*$&_-JRBNK~;k1QI1CcA_wolQJfA7_BKu zSy>87%Cq<(ezPd&s3wAm&;((x&^whEer=}%v0W%ptTo)u;Ja~)8BAW;twyWds!t3w z(cRtoE{(dJv2&xwd6vm72DMF@B007!tUf$n@>VPPS1>H>%X{yl7K-Eamoj0~CMiy#N>*1zwva&(FF^GX0< zk%j)OhOr|*R>L?OC%bg3Q4I?;f!Iq$cA=ZdmO1G3(w-0qE_!LbSIIU!2)+yarjfZY z6I0^bw_@*aGF%4GH&I$v_M155U!0&c+>Ndt>WF&<0@io#SizrYYlr4fO(#oU0L7Af zTZs6C&N>7)4e2EvAw>-kq`&cT6(T^b$I_%~8~Iaio>{U7>`PbDkCT>T-Ec&|TK zaR}SZ&COG52L}pT`28*$Fz3*8*~v*%D|01_X4V0w9%wI|Z=2u$AU&u59nwRQyZttT zY70lhM`e02#}zrnBiwl@dn=Nn5Uc1uJ&<4-Em}%&OD=A{#s48ojd zR}fF*I1PG-U&|zN1+1=K+{DA{%~tj6N3P30!8&uMoNYdQ{@f&5j z_wYP=YI)hL!fGFIq00tx$7JwFG!U6HYO|2;*uH-nBM?|x&I7ATk9qhOuvU>u0Yydj z3%yyF9%3{eu-<0>tXYwPJdUsPTZKT{r6H#pJ|i?AkX@}RplKq=Wlx78BtkOmA}Loh zDoK!Af6OhQE2AUhx!;`|EX$8HPom&wiSs;D*;aWvNtCVCv#udy|vPQ=G2KpK9(d2T2%8b$^!WY%zQE-x7&w zAfrK9!VA7;-LszW3i)w^*CUR8dgJ`|Fm%%@dO}cj@H;^3V6=E@z+za`Pv8(sKQkCJ z*PEaCAZbU!h`$psDWpS(4Sd+0tLt{R7yj-M5v^((OzyHvDOWl6I`z9-0hv-u<{5Jp zrWTa7^Y}-L;iLWSH1MZ!X$*aK3RGcig2EIFTh)w?cA%b@72pT_?rO=mY9s708Tu4! zdGK8^bwtl(0Cf}d3)Py>l&;vqPkHtfnj&CIXlrYW@(388T&g!#q9JtF^6^*u%Qv@H zda8YB11c$H8$0NLcs(aM;pTDg)~&R+LYK8|EplU(IxONXavz?8%q~GZaL=<@Re%<_ zrG*Z1<(7Qv*BIaZZ#YbKBWIsCBp`HY{yf*T9dc)jCMl^Qc6H4dOr$60K4-QqVoZlV z?b(GWMCne1&Bz=Y5StapH3ltg^vBmFxsi6g5sAWisX+P2**5IjPgcVi`7CPtZH*#6 z2h@7~uCm^}@Kwf{z)I}{Ej=memb>%6b;K?wRql37oMTvU?cE{pJOGK`3OaaAwR~@ zAmF?tQiP)I39wUDtvj3Qkanv4HxuG0I8Ct{-R8aJ z9%=VomCZ2bV)ae$20c#+kJj59>}7U>>z-b*Vq-yddMI%0F12HtjNLro#LbeB$uPFN zb8f0FY_0f z=2Hv58e6$>HM;iG6OK4U=?%h$%=n#`Yuf(_o(busi}!y=GzGW*FNvldw$Y1*b0jN2 zJ~`aiIB=Q(H5pcnfFTX&3UMF8=GGQTu|XY6JXWdQ>>Z}zZ^4Xh|Ary@=H*Eq=++%J zgG;Z*C4|0_>XUdO{5 z2&nm@Ky-n2BTXq<2s)RypdwuI3peS>VE~|}*E?q`CMMtxqMDUX{5BOf=eZ}Y=W&f1 z+j(PT`gb>oNotk_vFCmw$&rWr8<-Js+}oQp-~B?cKp7ZQGVaD#H5Si>DQEX+RP|Zd zLHyI74SI4>4HP7YBzKim4O!?el}Z+wj=rg^C}I7mV-0z0mHocYA00HefmZAiDc8kBS-;Fo?9p@Ck&Vhz*(K|FMr7vw(EG2O^j8t zE|1~pgW(_o`t>~fA+wxA4>CI=8i=_Hqn1W|RFnjo$R}~MEHWqm%M7s`H0wa; z(rO=0tepE+**fm(b!eJpDkd($rZ;_ndg%?BI7T!Gpg2Ak3M9jv1yloe({q<_=P!U@ z)3x#rY(^<&)x(p)$KUar{Z&Vnt{A#9$R0?f{8fHTMJ_DjR1^p(l!@sIuvJy@CAZUS z_g!IDq$eIQec&#@^3N^%SqG(@!|{78N0xWFt2MQhAAq=e6v&|@wK9eRv$gSGfnrb@ zsS!))`IJ1Hgn%HHiQt^M-tk?REkxYAz(`Fk~V>TvBb>x;y67L6iWIy$X+nhYZ{` zrGq@AWXP6GuXw@)0S8|o?h&_fiB6+?^JucImUD)F**UuMxM`$EDa)yD2 z-}vdz=Y{v@@wRW!=_N)M_srY8q`&;CC87mXw{rs}_d&@g8b&o7LT_icrg$+c%M`{Q z35kiTo2!5fJ^H>p_l7e5c~%qq74d^FwiAluCv-URe*!^3kz7-sOmCZw zz$}YaqXk!ZtSQZAza@Mdi&nEg02m!j&CBW6taI5>_?Mbw6FxcHIt^npIXS5UD=!L~ zX;agAu(5ta=-IJOrg^mQ;2#`J4G&OWh&+6lTVGnUKZcn>sO^mE(YV1?s~(VW=j1V z4*-Jt?rwrtz<~D5Y;7N|&FTUu|MB@j1mnEqmf16?w$7!qtl^%*lGZ=du-vwnW;2t$ z>c%>Qe-(eZPDrTB-#^;HG`y7Ot!*vMj#={v5EzOg(W!n%@A8i zXa;l;Cc#thgMy}Z*OUz6ItGV_K}`KtC+^LU3AzBM6tc_;ECPL z?uXe#Ccwp!N^{Ge?(R@s(c_S6Jo1^rwQyPlK0bFGx7&HdNk7x>MlL1%x5H?H7L=;B zpTn!P>rzLvgmG|oahZrUqzkHuCvjNp*XxPGz%2=^xoBa=({-|VsFPTgyvT`K5$WN#;=mT`c|aX0=4>RmbceL zEA&;jWxm~y8J(;TtZ7CzHa(ZjIJ24qC)yA(MT{RPD>^68nQVM+7~!$Z?icr%*+V_5 z$!1qO3uO*HZyO(%w`M1LgepsMwWFUxMkFoTM_HzK2(nGL^8I z_4Aw6+6h&<#v1)Lux%H{4f(*RFD-1{`XQ}79yxEYv2Dm1oy@~(8km8LdY$V@sXRI9 z?JPFuekb?jqi1FLiM#>6C7MXAP?cCI?cLN#FEoayZ5xaZH}T3&j#Ki0v^iaXf8=a> z>O-58k_Zvs0PDs4Ys-F@vdU*sjgYJVR=PTW;Vj(QueKhiNVc?q4DU$J4_nPEBHn?n zJN(I$C%}{e?+-18LbXZ~hBXuh{qi literal 0 HcmV?d00001 diff --git a/src/chart_types/partition_chart/layout/types/config_types.ts b/src/chart_types/partition_chart/layout/types/config_types.ts index 1307bbb76d..8bcec0dabd 100644 --- a/src/chart_types/partition_chart/layout/types/config_types.ts +++ b/src/chart_types/partition_chart/layout/types/config_types.ts @@ -27,6 +27,8 @@ import { Font, FontFamily, PartialFont } from './types'; export const PartitionLayout = Object.freeze({ sunburst: 'sunburst' as const, treemap: 'treemap' as const, + icicle: 'icicle' as const, + flame: 'flame' as const, }); /** @public */ diff --git a/src/chart_types/partition_chart/layout/utils/group_by_rollup.ts b/src/chart_types/partition_chart/layout/utils/group_by_rollup.ts index 76cbb0de28..f39943ac4c 100644 --- a/src/chart_types/partition_chart/layout/utils/group_by_rollup.ts +++ b/src/chart_types/partition_chart/layout/utils/group_by_rollup.ts @@ -57,7 +57,9 @@ interface MapNode extends NodeDescriptor { export type PrimitiveValue = string | number | null; // there could be more but sufficient for now type Key = PrimitiveValue; -type Sorter = (a: number, b: number) => number; + +export type Sorter = (a: number, b: number) => number; + type NodeSorter = (a: ArrayEntry, b: ArrayEntry) => number; export const entryKey = ([key]: ArrayEntry) => key; @@ -99,7 +101,7 @@ export function groupByRollup( const statistics: Statistics = { globalAggregate: NaN, }; - const reductionMap = factTable.reduce((p: HierarchyOfMaps, n, index) => { + const reductionMap: HierarchyOfMaps = factTable.reduce((p: HierarchyOfMaps, n, index) => { const keyCount = keyAccessors.length; let pointer: HierarchyOfMaps = p; keyAccessors.forEach((keyAccessor, i) => { @@ -132,22 +134,22 @@ export function groupByRollup( function getRootArrayNode(): ArrayNode { const children: HierarchyOfArrays = []; - const bootstrap = { + const bootstrap: Omit = { [AGGREGATE_KEY]: NaN, [DEPTH_KEY]: NaN, [CHILDREN_KEY]: children, [INPUT_KEY]: [] as number[], [PATH_KEY]: [] as number[], + [SORT_INDEX_KEY]: 0, + [STATISTICS_KEY]: { globalAggregate: 0 }, }; - Object.assign(bootstrap, { [PARENT_KEY]: bootstrap }); - const result: ArrayNode = bootstrap as ArrayNode; - return result; + return { ...bootstrap, [PARENT_KEY]: bootstrap } as ArrayNode; // TS doesn't yet handle bootstrapping but the `Omit` above retains guarantee for all props except `[PARENT_KEY` } /** @internal */ -export function mapsToArrays(root: HierarchyOfMaps, sorter: NodeSorter): HierarchyOfArrays { - const groupByMap = (node: HierarchyOfMaps, parent: ArrayNode) => - Array.from( +export function mapsToArrays(root: HierarchyOfMaps, sorter: NodeSorter | null): HierarchyOfArrays { + const groupByMap = (node: HierarchyOfMaps, parent: ArrayNode) => { + const items = Array.from( node, ([key, value]: [Key, MapNode]): ArrayEntry => { const valueElement = value[CHILDREN_KEY]; @@ -168,12 +170,15 @@ export function mapsToArrays(root: HierarchyOfMaps, sorter: NodeSorter): Hierarc ); return [key, newValue]; }, - ) - .sort(sorter) - .map((n: ArrayEntry, i) => { - entryValue(n).sortIndex = i; - return n; - }); // with the current algo, decreasing order is important + ); + if (sorter !== null) { + items.sort(sorter); + } + return items.map((n: ArrayEntry, i) => { + entryValue(n).sortIndex = i; + return n; + }); + }; // with the current algo, decreasing order is important const tree = groupByMap(root, getRootArrayNode()); const buildPaths = ([, mapNode]: ArrayEntry, currentPath: number[]) => { const newPath = [...currentPath, mapNode[SORT_INDEX_KEY]]; diff --git a/src/chart_types/partition_chart/layout/utils/sunburst.ts b/src/chart_types/partition_chart/layout/utils/sunburst.ts index fc4415410c..911f8c4e0c 100644 --- a/src/chart_types/partition_chart/layout/utils/sunburst.ts +++ b/src/chart_types/partition_chart/layout/utils/sunburst.ts @@ -22,11 +22,12 @@ import { ArrayEntry, childrenAccessor, HierarchyOfArrays } from './group_by_roll /** @internal */ export function sunburst( - nodes: HierarchyOfArrays, + outerNodes: HierarchyOfArrays, areaAccessor: (e: ArrayEntry) => number, - { x0, y0 }: Origin, + { x0: outerX0, y0: outerY0 }: Origin, clockwiseSectors: boolean, specialFirstInnermostSector: boolean, + heightStep: number = 1, ): Array { const result: Array = []; const laySubtree = (nodes: HierarchyOfArrays, { x0, y0 }: Origin, depth: number) => { @@ -36,14 +37,14 @@ export function sunburst( const index = clockwiseSectors ? i : nodeCount - i - 1; const node = nodes[depth === 1 && specialFirstInnermostSector ? (index + 1) % nodeCount : index]; const area = areaAccessor(node); - result.push({ node, x0: currentOffsetX, y0, x1: currentOffsetX + area, y1: y0 + 1 }); + result.push({ node, x0: currentOffsetX, y0, x1: currentOffsetX + area, y1: y0 + heightStep }); const children = childrenAccessor(node); - if (children && children.length) { - laySubtree(children, { x0: currentOffsetX, y0: y0 + 1 }, depth + 1); + if (children.length > 0) { + laySubtree(children, { x0: currentOffsetX, y0: y0 + heightStep }, depth + 1); } currentOffsetX += area; } }; - laySubtree(nodes, { x0, y0 }, 0); + laySubtree(outerNodes, { x0: outerX0, y0: outerY0 }, 0); return result; } diff --git a/src/chart_types/partition_chart/layout/utils/treemap.ts b/src/chart_types/partition_chart/layout/utils/treemap.ts index 2b5dbb2969..7bfc456c3b 100644 --- a/src/chart_types/partition_chart/layout/utils/treemap.ts +++ b/src/chart_types/partition_chart/layout/utils/treemap.ts @@ -101,20 +101,25 @@ export function treemap( areaAccessor: (e: ArrayEntry) => number, topPaddingAccessor: (e: ArrayEntry) => number, paddingAccessor: (e: ArrayEntry) => number, - { x0, y0, width, height }: { x0: number; y0: number; width: number; height: number }, + { + x0: outerX0, + y0: outerY0, + width: outerWidth, + height: outerHeight, + }: { x0: number; y0: number; width: number; height: number }, ): Array { if (nodes.length === 0) return []; // some bias toward horizontal rectangles with a golden ratio of width to height - const vertical = width / GOLDEN_RATIO <= height; - const independentSize = vertical ? width : height; + const vertical = outerWidth / GOLDEN_RATIO <= outerHeight; + const independentSize = vertical ? outerWidth : outerHeight; const vectorElements = bestVector(nodes, independentSize, areaAccessor); - const vector = vectorNodeCoordinates(vectorElements, x0, y0, vertical); + const vector = vectorNodeCoordinates(vectorElements, outerX0, outerY0, vertical); const { dependentSize } = vectorElements; return vector .concat( ...vector.map(({ node, x0, y0, x1, y1 }) => { const childrenNodes = entryValue(node)[CHILDREN_KEY]; - if (!childrenNodes || !childrenNodes.length) { + if (childrenNodes.length === 0) { return []; } const fullWidth = x1 - x0; @@ -148,8 +153,8 @@ export function treemap( topPaddingAccessor, paddingAccessor, vertical - ? { x0, y0: y0 + dependentSize, width, height: height - dependentSize } - : { x0: x0 + dependentSize, y0, width: width - dependentSize, height }, + ? { x0: outerX0, y0: outerY0 + dependentSize, width: outerWidth, height: outerHeight - dependentSize } + : { x0: outerX0 + dependentSize, y0: outerY0, width: outerWidth - dependentSize, height: outerHeight }, ), ); } diff --git a/src/chart_types/partition_chart/layout/viewmodel/hierarchy_of_arrays.ts b/src/chart_types/partition_chart/layout/viewmodel/hierarchy_of_arrays.ts index 919dbaa61b..5514e931c0 100644 --- a/src/chart_types/partition_chart/layout/viewmodel/hierarchy_of_arrays.ts +++ b/src/chart_types/partition_chart/layout/viewmodel/hierarchy_of_arrays.ts @@ -28,12 +28,14 @@ import { groupByRollup, mapEntryValue, mapsToArrays, + Sorter, } from '../utils/group_by_rollup'; export function getHierarchyOfArrays( rawFacts: Relation, valueAccessor: ValueAccessor, groupByRollupAccessors: IndexedAccessorFn[], + sorter: Sorter | null = childOrders.descending, ): HierarchyOfArrays { const aggregator = aggregators.sum; @@ -52,6 +54,6 @@ export function getHierarchyOfArrays( // size as data value vs size as number of pixels in the rectangle return mapsToArrays( groupByRollup(groupByRollupAccessors, valueAccessor, aggregator, facts), - aggregateComparator(mapEntryValue, childOrders.descending), + sorter && aggregateComparator(mapEntryValue, sorter), ); } diff --git a/src/chart_types/partition_chart/layout/viewmodel/viewmodel.ts b/src/chart_types/partition_chart/layout/viewmodel/viewmodel.ts index d4a33c8f82..714f67c804 100644 --- a/src/chart_types/partition_chart/layout/viewmodel/viewmodel.ts +++ b/src/chart_types/partition_chart/layout/viewmodel/viewmodel.ts @@ -103,7 +103,7 @@ export function makeQuadViewModel( const opacityMultiplier = 1; // could alter in the future, eg. in response to interactions const layer = layers[node.depth - 1]; const fillColorSpec = layer && layer.shape && layer.shape.fillColor; - const fill = fillColorSpec || 'rgba(128,0,0,0.5)'; + const fill = fillColorSpec ?? 'rgba(128,0,0,0.5)'; const shapeFillColor = typeof fill === 'function' ? fill(node, node.sortIndex, node.parent.children) : fill; const { r, g, b, opacity } = stringToRGB(shapeFillColor); const fillColor = argsToRGBString(r, g, b, opacity * opacityMultiplier); @@ -149,9 +149,9 @@ export interface RectangleConstruction { y1: Pixels; } -function rectangleConstruction(treeHeight: number, topGroove: number) { - return function (node: ShapeTreeNode): RectangleConstruction { - return node.depth < treeHeight +function rectangleConstruction(treeHeight: number, topGroove: number | null) { + return function rectangleConstructionClosure(node: ShapeTreeNode): RectangleConstruction { + return node.depth < treeHeight && topGroove !== null ? { x0: node.x0, y0: node.y0px, @@ -167,6 +167,66 @@ function rectangleConstruction(treeHeight: number, topGroove: number) { }; } +const rawChildNodes = ( + partitionLayout: PartitionLayout, + tree: HierarchyOfArrays, + topGroove: number, + width: number, + height: number, + clockwiseSectors: boolean, + specialFirstInnermostSector: boolean, + maxDepth: number, +): Array => { + const totalValue = tree.reduce((p: number, n: ArrayEntry): number => p + mapEntryValue(n), 0); + switch (partitionLayout) { + case PartitionLayout.sunburst: + const sunburstValueToAreaScale = TAU / totalValue; + const sunburstAreaAccessor = (e: ArrayEntry) => sunburstValueToAreaScale * mapEntryValue(e); + return sunburst(tree, sunburstAreaAccessor, { x0: 0, y0: -1 }, clockwiseSectors, specialFirstInnermostSector); + + case PartitionLayout.treemap: + const treemapInnerArea = isTreemap(partitionLayout) ? width * height : 1; // assuming 1 x 1 unit square + const treemapValueToAreaScale = treemapInnerArea / totalValue; + const treemapAreaAccessor = (e: ArrayEntry) => treemapValueToAreaScale * mapEntryValue(e); + return treemap(tree, treemapAreaAccessor, topGrooveAccessor(topGroove), grooveAccessor, { + x0: -width / 2, + y0: -height / 2, + width, + height, + }); + + case PartitionLayout.icicle: + case PartitionLayout.flame: + const icicleLayout = isIcicle(partitionLayout); + const multiplier = icicleLayout ? -1 : 1; + const icicleValueToAreaScale = width / totalValue; + const icicleAreaAccessor = (e: ArrayEntry) => icicleValueToAreaScale * mapEntryValue(e); + const icicleRowHeight = height / maxDepth; + const result = sunburst( + tree, + icicleAreaAccessor, + { x0: -width / 2, y0: (multiplier * height) / 2 - icicleRowHeight }, + true, + false, + icicleRowHeight, + ); + return icicleLayout + ? result + : result.map(({ y0, y1, ...rest }) => ({ y0: height - y1, y1: height - y0, ...rest })); + + default: + // Let's ensure TS complains if we add a new PartitionLayout type in the future without creating a `case` for it + // Hopefully, a future TS version will do away with the need for this boilerplate `default`. Now TS even needs a `default` even if all possible cases are covered. + // Even in runtime it does something sensible (returns the empty set); explicit throwing is avoided as it can deopt the function + return ((layout: never) => layout ?? [])(partitionLayout); + } +}; + +export const isTreemap = (partitionLayout: PartitionLayout) => partitionLayout === PartitionLayout.treemap; +export const isSunburst = (partitionLayout: PartitionLayout) => partitionLayout === PartitionLayout.sunburst; +const isIcicle = (partitionLayout: PartitionLayout) => partitionLayout === PartitionLayout.icicle; +const isFlame = (partitionLayout: PartitionLayout) => partitionLayout === PartitionLayout.flame; + /** @internal */ export function shapeViewModel( textMeasure: TextMeasure, @@ -207,25 +267,25 @@ export function shapeViewModel( return nullShapeViewModel(config, diskCenter); } - const totalValue = tree.reduce((p: number, n: ArrayEntry): number => p + mapEntryValue(n), 0); - - const sunburstValueToAreaScale = TAU / totalValue; - const sunburstAreaAccessor = (e: ArrayEntry) => sunburstValueToAreaScale * mapEntryValue(e); - const treemapLayout = partitionLayout === PartitionLayout.treemap; - const treemapInnerArea = treemapLayout ? width * height : 1; // assuming 1 x 1 unit square - const treemapValueToAreaScale = treemapInnerArea / totalValue; - const treemapAreaAccessor = (e: ArrayEntry) => treemapValueToAreaScale * mapEntryValue(e); - - const rawChildNodes: Array = treemapLayout - ? treemap(tree, treemapAreaAccessor, topGrooveAccessor(topGroove), grooveAccessor, { - x0: -width / 2, - y0: -height / 2, - width, - height, - }) - : sunburst(tree, sunburstAreaAccessor, { x0: 0, y0: -1 }, clockwiseSectors, specialFirstInnermostSector); + const treemapLayout = isTreemap(partitionLayout); + const sunburstLayout = isSunburst(partitionLayout); + const icicleLayout = isIcicle(partitionLayout); + const flameLayout = isFlame(partitionLayout); + const longestPath = ([, { children, path }]: ArrayEntry): number => + children.length > 0 ? children.reduce((p, n) => Math.max(p, longestPath(n)), 0) : path.length; + const maxDepth = longestPath(tree[0]) - 2; // don't include the root node + const childNodes = rawChildNodes( + partitionLayout, + tree, + topGroove, + width, + height, + clockwiseSectors, + specialFirstInnermostSector, + maxDepth, + ); - const shownChildNodes = rawChildNodes.filter((n: Part) => { + const shownChildNodes = childNodes.filter((n: Part) => { const layerIndex = entryValue(n.node).depth - 1; const layer = layers[layerIndex]; return !layer || !layer.showAccessor || layer.showAccessor(entryKey(n.node)); @@ -237,7 +297,7 @@ export function shapeViewModel( const innerRadius: Radius = outerRadius - (1 - emptySizeRatio) * outerRadius; const treeHeight = shownChildNodes.reduce((p: number, n: Part) => Math.max(p, entryValue(n.node).depth), 0); // 1: pie, 2: two-ring donut etc. const ringThickness = (outerRadius - innerRadius) / treeHeight; - const partToShapeFn = partToShapeTreeNode(treemapLayout, innerRadius, ringThickness); + const partToShapeFn = partToShapeTreeNode(!sunburstLayout, innerRadius, ringThickness); const quadViewModel = makeQuadViewModel( shownChildNodes.slice(1).map(partToShapeFn), layers, @@ -248,32 +308,31 @@ export function shapeViewModel( // fill text const roomCondition = (n: ShapeTreeNode) => { const diff = n.x1 - n.x0; - return treemapLayout - ? n.x1 - n.x0 > minFontSize && n.y1px - n.y0px > minFontSize - : (diff < 0 ? TAU + diff : diff) * ringSectorMiddleRadius(n) > Math.max(minFontSize, linkLabel.maximumSection); + return sunburstLayout + ? (diff < 0 ? TAU + diff : diff) * ringSectorMiddleRadius(n) > Math.max(minFontSize, linkLabel.maximumSection) + : n.x1 - n.x0 > minFontSize && n.y1px - n.y0px > minFontSize; }; const nodesWithRoom = quadViewModel.filter(roomCondition); - const outsideFillNodes = fillOutside && !treemapLayout ? nodesWithRoom : []; + const outsideFillNodes = fillOutside && sunburstLayout ? nodesWithRoom : []; - const textFillOrigins = nodesWithRoom.map(treemapLayout ? rectangleFillOrigins : sectorFillOrigins(fillOutside)); + const textFillOrigins = nodesWithRoom.map(sunburstLayout ? sectorFillOrigins(fillOutside) : rectangleFillOrigins); const valueFormatter = valueGetter === percentValueGetter ? specifiedPercentFormatter : specifiedValueFormatter; - const getRowSets = treemapLayout + const getRowSets = sunburstLayout ? fillTextLayout( - rectangleConstruction(treeHeight, topGroove), - getRectangleRowGeometry, - () => 0, - containerBackgroundColor, - ) - : fillTextLayout( ringSectorConstruction(config, innerRadius, ringThickness), getSectorRowGeometry, inSectorRotation(config.horizontalTextEnforcer, config.horizontalTextAngleThreshold), containerBackgroundColor, + ) + : fillTextLayout( + rectangleConstruction(treeHeight, treemapLayout ? topGroove : null), + getRectangleRowGeometry, + () => 0, + containerBackgroundColor, ); - const rowSets: RowSet[] = getRowSets( textMeasure, rawTextGetter, @@ -283,7 +342,7 @@ export function shapeViewModel( config, layers, textFillOrigins, - treemapLayout, + !sunburstLayout, !treemapLayout, ); @@ -294,13 +353,13 @@ export function shapeViewModel( const currentY = [-height, -height, -height, -height]; const nodesWithoutRoom = - fillOutside || treemapLayout + fillOutside || treemapLayout || icicleLayout || flameLayout ? [] // outsideFillNodes and linkLabels are in inherent conflict due to very likely overlaps : quadViewModel.filter((n: ShapeTreeNode) => { const id = nodeId(n); const foundInFillText = rowSets.find((r: RowSet) => r.id === id); // successful text render if found, and has some row(s) - return !(foundInFillText && foundInFillText.rows.length !== 0); + return !(foundInFillText && foundInFillText.rows.length > 0); }); const maxLinkedLabelTextLength = config.linkLabel.maxTextLength; const linkLabelViewModels = linkTextLayout( @@ -321,7 +380,7 @@ export function shapeViewModel( const pickQuads: PickFunction = (x, y) => quadViewModel.filter( - treemapLayout + treemapLayout || icicleLayout || flameLayout ? ({ x0, y0, x1, y1 }) => x0 <= x && x <= x1 && y0 <= y && y <= y1 : ({ x0, y0px, x1, y1px }) => { const angleX = (Math.atan2(y, x) + TAU / 4 + TAU) % TAU; diff --git a/src/chart_types/partition_chart/renderer/canvas/canvas_renderers.ts b/src/chart_types/partition_chart/renderer/canvas/canvas_renderers.ts index 6834206f51..119f4a59b7 100644 --- a/src/chart_types/partition_chart/renderer/canvas/canvas_renderers.ts +++ b/src/chart_types/partition_chart/renderer/canvas/canvas_renderers.ts @@ -19,7 +19,6 @@ import { clearCanvas, renderLayers, withContext } from '../../../../renderers/canvas'; import { Color } from '../../../../utils/commons'; -import { PartitionLayout } from '../../layout/types/config_types'; import { Pixels } from '../../layout/types/geometry_types'; import { LinkLabelVM, @@ -33,6 +32,7 @@ import { addOpacity } from '../../layout/utils/calcs'; import { TAU } from '../../layout/utils/constants'; import { cssFontShorthand } from '../../layout/utils/measure'; import { LinkLabelsViewModelSpec } from '../../layout/viewmodel/link_text_layout'; +import { isSunburst } from '../../layout/viewmodel/viewmodel'; // the burnout avoidance in the center of the pie const LINE_WIDTH_MULT = 10; // border can be a maximum 1/LINE_WIDTH_MULT - th of the sector angle, otherwise the border would dominate @@ -266,9 +266,7 @@ export function renderPartitionCanvas2d( // bottom layer: sectors (pie slices, ring sectors etc.) (ctx: CanvasRenderingContext2D) => - config.partitionLayout === PartitionLayout.treemap - ? renderRectangles(ctx, quadViewModel) - : renderSectors(ctx, quadViewModel), + isSunburst(config.partitionLayout) ? renderSectors(ctx, quadViewModel) : renderRectangles(ctx, quadViewModel), // all the fill-based, potentially multirow text, whether inside or outside the sector (ctx: CanvasRenderingContext2D) => renderRowSets(ctx, rowSets, linkLineColor), diff --git a/src/chart_types/partition_chart/renderer/dom/highlighter.tsx b/src/chart_types/partition_chart/renderer/dom/highlighter.tsx index c94f4a273c..729f5e2845 100644 --- a/src/chart_types/partition_chart/renderer/dom/highlighter.tsx +++ b/src/chart_types/partition_chart/renderer/dom/highlighter.tsx @@ -20,10 +20,12 @@ import React from 'react'; import { Dimensions } from '../../../../utils/dimensions'; +import { configMetadata } from '../../layout/config/config'; import { PartitionLayout } from '../../layout/types/config_types'; import { PointObject } from '../../layout/types/geometry_types'; import { QuadViewModel } from '../../layout/types/viewmodel_types'; import { TAU } from '../../layout/utils/constants'; +import { isSunburst, isTreemap } from '../../layout/viewmodel/viewmodel'; /** @internal */ export interface HighlighterProps { @@ -97,26 +99,12 @@ function renderSector(geometry: QuadViewModel, key: string, style: SVGStyle) { return ; } -function renderGeometries(geometries: QuadViewModel[], partitionLayout: PartitionLayout, style: SVGStyle) { - let maxDepth = -1; +function renderGeometries(geoms: QuadViewModel[], partitionLayout: PartitionLayout, style: SVGStyle) { + const maxDepth = geoms.reduce((acc, geom) => Math.max(acc, geom.depth), 0); // we should render only the deepest geometries of the tree to avoid overlaying highlighted geometries - if (partitionLayout === PartitionLayout.treemap) { - maxDepth = geometries.reduce((acc, geom) => Math.max(acc, geom.depth), 0); - } - return geometries - .filter((geometry) => { - if (maxDepth !== -1) { - return geometry.depth >= maxDepth; - } - return true; - }) - .map((geometry, index) => { - if (partitionLayout === PartitionLayout.sunburst) { - return renderSector(geometry, `${index}`, style); - } - - return renderRectangles(geometry, `${index}`, style); - }); + const highlightedGeoms = isTreemap(partitionLayout) ? geoms.filter((g) => g.depth >= maxDepth) : geoms; + const renderGeom = isSunburst(partitionLayout) ? renderSector : renderRectangles; + return highlightedGeoms.map((geometry, index) => renderGeom(geometry, `${index}`, style)); } /** @internal */ @@ -143,7 +131,7 @@ export class HighlighterComponent extends React.Component { - {partitionLayout === PartitionLayout.sunburst && ( + {isSunburst(partitionLayout) ? ( { mask={`url(#${maskId})`} className="echHighlighter__mask" /> - )} - {partitionLayout === PartitionLayout.treemap && ( + ) : ( )} @@ -201,5 +188,5 @@ export const DEFAULT_PROPS: HighlighterProps = { }, outerRadius: 10, renderAsOverlay: false, - partitionLayout: PartitionLayout.sunburst, + partitionLayout: configMetadata.partitionLayout.dflt, }; diff --git a/src/chart_types/partition_chart/state/selectors/tree.ts b/src/chart_types/partition_chart/state/selectors/tree.ts index e8c0f76d02..8d744be838 100644 --- a/src/chart_types/partition_chart/state/selectors/tree.ts +++ b/src/chart_types/partition_chart/state/selectors/tree.ts @@ -20,11 +20,13 @@ import createCachedSelector from 're-reselect'; import { ChartTypes } from '../../..'; -import { SpecTypes } from '../../../../specs/constants'; +import { SpecTypes } from '../../../../specs'; import { GlobalChartState } from '../../../../state/chart_state'; import { getSpecsFromStore } from '../../../../state/utils'; -import { HierarchyOfArrays } from '../../layout/utils/group_by_rollup'; +import { configMetadata } from '../../layout/config/config'; +import { childOrders, HierarchyOfArrays } from '../../layout/utils/group_by_rollup'; import { getHierarchyOfArrays } from '../../layout/viewmodel/hierarchy_of_arrays'; +import { isSunburst, isTreemap } from '../../layout/viewmodel/viewmodel'; import { PartitionSpec } from '../../specs'; const getSpecs = (state: GlobalChartState) => state.specs; @@ -38,6 +40,13 @@ export const getTree = createCachedSelector( return []; } const { data, valueAccessor, layers } = pieSpecs[0]; - return getHierarchyOfArrays(data, valueAccessor, [() => null, ...layers.map(({ groupByRollup }) => groupByRollup)]); + const layout = pieSpecs[0].config.partitionLayout ?? configMetadata.partitionLayout.dflt; + const sorter = isTreemap(layout) || isSunburst(layout) ? childOrders.descending : null; + return getHierarchyOfArrays( + data, + valueAccessor, + [() => null, ...layers.map(({ groupByRollup }) => groupByRollup)], + sorter, + ); }, )((state) => state.chartId); diff --git a/src/mocks/hierarchical/index.ts b/src/mocks/hierarchical/index.ts index dbd0d18fe7..ae729fd636 100644 --- a/src/mocks/hierarchical/index.ts +++ b/src/mocks/hierarchical/index.ts @@ -19,6 +19,7 @@ import { manyPieMock } from './many_pie'; import { miniSunburstMock } from './mini_sunburst'; +import { observabilityTreeMock } from './observability_tree'; import { pieMock } from './pie'; import { sunburstMock } from './sunburst'; @@ -27,4 +28,5 @@ export const mocks = { sunburst: sunburstMock, miniSunburst: miniSunburstMock, manyPie: manyPieMock, + observabilityTree: observabilityTreeMock, }; diff --git a/src/mocks/hierarchical/observability_tree.ts b/src/mocks/hierarchical/observability_tree.ts new file mode 100644 index 0000000000..6498c78329 --- /dev/null +++ b/src/mocks/hierarchical/observability_tree.ts @@ -0,0 +1,23 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// source of data: Martin Spier's https://github.com/spiermar/d3-flame-graph + +// prettier-ignore +export const observabilityTreeMock = {c:[{n:'genunix`syscall_mstate',v:89},{c:[{c:[{c:[{c:[{c:[{c:[{c:[{c:[{n:'unix`page_lookup_create',v:1}],n:'unix`page_lookup',v:1}],n:'ufs`ufs_getpage',v:1}],n:'genunix`fop_getpage',v:1},{c:[{c:[{c:[{c:[{c:[{n:'genunix`pvn_plist_init',v:1},{n:'unix`lgrp_mem_choose',v:1},{c:[{c:[{c:[{n:'unix`mutex_enter',v:1}],n:'unix`page_get_mnode_freelist',v:1}],n:'unix`page_get_freelist',v:1}],n:'unix`page_create_va',v:1},{c:[{n:'unix`page_lookup_create',v:1}],n:'unix`page_lookup',v:1}],n:'genunix`swap_getapage',v:4}],n:'genunix`swap_getpage',v:4}],n:'genunix`fop_getpage',v:4},{c:[{c:[{n:'unix`hwblkclr',v:3}],n:'unix`pfnzero',v:3}],n:'unix`pagezero',v:3}],n:'genunix`anon_zero',v:7}],n:'genunix`segvn_faultpage',v:7},{n:'ufs`ufs_getpage',v:1},{c:[{c:[{c:[{c:[{c:[{c:[{c:[{c:[{n:'unix`hment_compare',v:1}],n:'genunix`avl_find',v:1}],n:'genunix`avl_add',v:1}],n:'unix`hment_insert',v:2}],n:'unix`hment_assign',v:2}],n:'unix`hati_pte_map',v:2}],n:'unix`hati_load_common',v:2}],n:'unix`hat_memload',v:2}],n:'unix`hat_memload_region',v:2}],n:'genunix`segvn_fault',v:11}],n:'genunix`as_fault',v:12},{n:'genunix`segvn_fault',v:1}],n:'unix`pagefault',v:13}],n:'unix`trap',v:13}],n:'unix`0xfffffffffb8001d6',v:13},{n:'unix`0xfffffffffb800c7c',v:42},{n:'unix`0xfffffffffb800c81',v:2},{c:[{n:'genunix`gethrtime_unscaled',v:4},{c:[{c:[{n:'unix`tsc_gethrtimeunscaled',v:11},{n:'unix`tsc_read',v:186}],n:'genunix`gethrtime_unscaled',v:203},{n:'unix`tsc_gethrtimeunscaled',v:13}],n:'genunix`syscall_mstate',v:355},{n:'unix`atomic_add_64',v:110}],n:'unix`0xfffffffffb800c86',v:472},{c:[{n:'genunix`audit_getstate',v:27},{n:'genunix`clear_stale_fd',v:10},{n:'genunix`disp_lock_exit',v:27},{c:[{n:'FSS`fss_preempt',v:1},{n:'genunix`audit_getstate',v:15},{n:'genunix`clear_stale_fd',v:44},{c:[{n:'unix`clear_int_flag',v:39},{n:'unix`do_splx',v:1993},{c:[{c:[{c:[{n:'unix`do_splx',v:1}],n:'genunix`disp_lock_exit_nopreempt',v:1}],n:'unix`preempt',v:1}],n:'unix`kpreempt',v:1}],n:'genunix`disp_lock_exit',v:2096},{n:'genunix`sigcheck',v:1},{c:[{n:'unix`clear_int_flag',v:180},{n:'unix`splr',v:400}],n:'genunix`thread_lock',v:670},{n:'unix`do_splx',v:31},{n:'unix`i_ddi_splhigh',v:23},{n:'unix`lock_clear_splx',v:28},{n:'unix`lock_try',v:778},{n:'unix`lwp_getdatamodel',v:6},{c:[{c:[{c:[{c:[{c:[{n:'unix`tsc_gethrtimeunscaled',v:1}],n:'genunix`mstate_thread_onproc_time',v:1}],n:'unix`caps_charge_adjust',v:1}],n:'unix`cpucaps_charge',v:3},{c:[{n:'unix`cmt_balance',v:1},{c:[{n:'unix`bitset_in_set',v:1}],n:'unix`cpu_wakeup_mwait',v:1}],n:'unix`setbackdq',v:5}],n:'FSS`fss_preempt',v:8},{n:'unix`do_splx',v:1},{c:[{n:'genunix`disp_lock_exit_high',v:1},{c:[{n:'unix`membar_enter',v:1}],n:'unix`disp',v:1},{n:'unix`do_splx',v:1},{c:[{c:[{n:'genunix`schedctl_save',v:1}],n:'genunix`savectx',v:2}],n:'unix`resume',v:2}],n:'unix`swtch',v:5}],n:'unix`preempt',v:14},{n:'unix`prunstop',v:36},{n:'unix`splr',v:92},{n:'unix`splx',v:6}],n:'genunix`post_syscall',v:4245},{n:'genunix`thread_lock',v:33},{n:'unix`lwp_getdatamodel',v:3},{n:'unix`prunstop',v:2}],n:'unix`0xfffffffffb800c91',v:4361},{c:[{n:'genunix`gethrtime_unscaled',v:7},{c:[{c:[{n:'unix`tsc_gethrtimeunscaled',v:17},{n:'unix`tsc_read',v:160}],n:'genunix`gethrtime_unscaled',v:182},{n:'unix`tsc_gethrtimeunscaled',v:12}],n:'genunix`syscall_mstate',v:412},{n:'unix`atomic_add_64',v:95}],n:'unix`0xfffffffffb800ca0',v:517},{n:'unix`_sys_rtt',v:6},{c:[{c:[{c:[{c:[{c:[{c:[{n:'genunix`cpu_decay',v:1}],n:'genunix`cpu_grow',v:1}],n:'genunix`cpu_update_pct',v:1}],n:'genunix`new_mstate',v:1}],n:'unix`trap',v:1}],n:'unix`sys_rtt_common',v:1}],n:'unix`_sys_rtt_ints_disabled',v:1},{c:[{c:[{c:[{c:[{c:[{c:[{c:[{n:'doorfs`door_close',v:1}],n:'namefs`nm_close',v:1}],n:'genunix`fop_close',v:1}],n:'genunix`closef',v:1}],n:'genunix`close_exec',v:1}],n:'genunix`exec_common',v:1}],n:'genunix`exece',v:1}],n:'unix`_sys_sysenter_post_swapgs',v:1},{c:[{n:'genunix`gethrtime_unscaled',v:11},{c:[{c:[{c:[{c:[{c:[{c:[{c:[{c:[{c:[{c:[{n:'unix`mtype_func',v:1},{n:'unix`mutex_enter',v:1}],n:'unix`page_get_mnode_freelist',v:2}],n:'unix`page_get_freelist',v:2}],n:'unix`page_create_va',v:3}],n:'genunix`pvn_read_kluster',v:3}],n:'ufs`ufs_getpage_ra',v:3}],n:'ufs`ufs_getpage',v:3}],n:'genunix`fop_getpage',v:3}],n:'genunix`segvn_faulta',v:3}],n:'genunix`as_faulta',v:3}],n:'genunix`memcntl',v:3},{c:[{c:[{c:[{c:[{c:[{c:[{c:[{c:[{n:'unix`htable_lookup',v:1}],n:'unix`htable_walk',v:1}],n:'unix`hat_unload_callback',v:1}],n:'genunix`segvn_unmap',v:1}],n:'genunix`as_unmap',v:1}],n:'unix`mmapobj_map_elf',v:1}],n:'unix`mmapobj_map_interpret',v:1}],n:'unix`mmapobj',v:1}],n:'genunix`mmapobjsys',v:1},{c:[{n:'genunix`copen',v:7},{c:[{n:'genunix`audit_getstate',v:62},{c:[{n:'genunix`audit_falloc',v:8},{c:[{c:[{c:[{c:[{c:[{n:'unix`swtch',v:1}],n:'unix`preempt',v:1}],n:'unix`kpreempt',v:1}],n:'unix`sys_rtt_common',v:1}],n:'unix`_sys_rtt_ints_disabled',v:1}],n:'genunix`audit_getstate',v:66},{n:'genunix`audit_unfalloc',v:32},{n:'genunix`crfree',v:9},{n:'genunix`crhold',v:5},{n:'genunix`cv_broadcast',v:16},{c:[{c:[{n:'genunix`kmem_cache_alloc',v:11},{c:[{n:'genunix`kmem_cache_alloc',v:66},{n:'unix`mutex_enter',v:122},{n:'unix`mutex_exit',v:46}],n:'genunix`kmem_zalloc',v:280},{n:'unix`bzero',v:8}],n:'genunix`audit_falloc',v:313},{n:'genunix`crhold',v:11},{n:'genunix`kmem_cache_alloc',v:49},{n:'genunix`kmem_zalloc',v:13},{c:[{n:'genunix`fd_find',v:13},{n:'genunix`fd_reserve',v:9},{c:[{n:'genunix`fd_find',v:161},{n:'genunix`fd_reserve',v:15}],n:'genunix`ufalloc_file',v:294},{n:'unix`mutex_enter',v:197},{n:'unix`mutex_exit',v:29}],n:'genunix`ufalloc',v:551},{n:'genunix`ufalloc_file',v:20},{n:'unix`atomic_add_32',v:134},{n:'unix`mutex_enter',v:99},{n:'unix`mutex_exit',v:58}],n:'genunix`falloc',v:1363},{n:'genunix`fd_reserve',v:8},{n:'genunix`kmem_cache_alloc',v:9},{n:'genunix`kmem_cache_free',v:5},{n:'genunix`lookupnameat',v:69},{n:'genunix`set_errno',v:24},{c:[{n:'genunix`audit_getstate',v:31},{n:'genunix`cv_broadcast',v:25},{n:'genunix`fd_reserve',v:35}],n:'genunix`setf',v:187},{n:'genunix`ufalloc',v:10},{c:[{c:[{n:'genunix`kmem_cache_free',v:5},{c:[{n:'genunix`kmem_cache_free',v:73},{n:'unix`mutex_enter',v:111},{n:'unix`mutex_exit',v:55}],n:'genunix`kmem_free',v:288}],n:'genunix`audit_unfalloc',v:340},{n:'genunix`crfree',v:13},{n:'genunix`kmem_cache_free',v:51},{n:'genunix`kmem_free',v:11},{n:'unix`atomic_add_32_nv',v:100},{n:'unix`mutex_enter',v:97},{n:'unix`mutex_exit',v:56}],n:'genunix`unfalloc',v:729},{c:[{c:[{c:[{c:[{n:'genunix`audit_getstate',v:16},{n:'genunix`fop_lookup',v:55},{c:[{n:'genunix`audit_getstate',v:21},{n:'genunix`crgetmapped',v:55},{n:'genunix`fop_inactive',v:39},{c:[{n:'genunix`crgetmapped',v:57},{n:'genunix`dnlc_lookup',v:26},{n:'genunix`fop_lookup',v:85},{n:'genunix`kmem_alloc',v:73},{n:'genunix`traverse',v:30},{n:'genunix`vfs_matchops',v:28},{c:[{c:[{n:'genunix`kmem_cache_alloc',v:241},{n:'unix`mutex_enter',v:366},{n:'unix`mutex_exit',v:149}],n:'genunix`kmem_alloc',v:934},{n:'genunix`kmem_cache_alloc',v:32}],n:'genunix`vn_setpath',v:1969},{c:[{n:'genunix`crgetmapped',v:36},{c:[{n:'genunix`crgetmapped',v:58},{n:'genunix`dnlc_lookup',v:70},{n:'genunix`vn_rele',v:14},{n:'ufs`ufs_iaccess',v:91},{c:[{n:'genunix`crgetuid',v:30},{c:[{n:'genunix`memcmp',v:38},{c:[{n:'genunix`memcmp',v:277}],n:'unix`bcmp',v:295}],n:'genunix`dnlc_lookup',v:1843},{n:'genunix`secpolicy_vnode_access2',v:72},{n:'genunix`vn_rele',v:39},{c:[{n:'genunix`crgetuid',v:22},{n:'genunix`secpolicy_vnode_access2',v:217}],n:'ufs`ufs_iaccess',v:648},{n:'unix`bcmp',v:42},{n:'unix`mutex_enter',v:980},{n:'unix`mutex_exit',v:350},{n:'unix`rw_enter',v:525},{n:'unix`rw_exit',v:439}],n:'ufs`ufs_lookup',v:5399}],n:'genunix`fop_lookup',v:6470},{n:'genunix`kmem_cache_alloc',v:39},{c:[{n:'genunix`rwst_exit',v:18},{n:'genunix`rwst_tryenter',v:32},{n:'genunix`vn_mountedvfs',v:11},{n:'genunix`vn_vfslocks_getlock',v:62},{n:'genunix`vn_vfslocks_rele',v:50},{c:[{n:'genunix`kmem_alloc',v:32},{n:'genunix`rwst_enter_common',v:32},{n:'genunix`rwst_init',v:28},{c:[{n:'genunix`rwst_enter_common',v:264},{n:'unix`mutex_enter',v:337},{n:'unix`mutex_exit',v:105}],n:'genunix`rwst_tryenter',v:734},{c:[{n:'genunix`cv_init',v:53},{c:[{c:[{n:'genunix`kmem_cpu_reload',v:2}],n:'genunix`kmem_cache_alloc',v:168},{n:'unix`mutex_enter',v:379},{n:'unix`mutex_exit',v:155}],n:'genunix`kmem_alloc',v:795},{n:'genunix`kmem_cache_alloc',v:29},{c:[{n:'genunix`cv_init',v:65},{n:'unix`mutex_init',v:53}],n:'genunix`rwst_init',v:236},{n:'unix`mutex_init',v:46}],n:'genunix`vn_vfslocks_getlock',v:1357},{n:'unix`mutex_enter',v:727},{n:'unix`mutex_exit',v:371}],n:'genunix`vn_vfsrlock',v:3342},{c:[{n:'genunix`cv_broadcast',v:25},{n:'genunix`kmem_free',v:35},{n:'genunix`rwst_destroy',v:32},{c:[{n:'genunix`cv_broadcast',v:40}],n:'genunix`rwst_exit',v:167},{n:'genunix`vn_vfslocks_getlock',v:120},{c:[{n:'genunix`cv_destroy',v:77},{n:'genunix`kmem_cache_free',v:22},{c:[{n:'genunix`kmem_cache_free',v:154},{n:'unix`mutex_enter',v:316},{n:'unix`mutex_exit',v:148}],n:'genunix`kmem_free',v:693},{c:[{n:'genunix`cv_destroy',v:42},{n:'unix`mutex_destroy',v:176}],n:'genunix`rwst_destroy',v:296},{n:'unix`mutex_destroy',v:31}],n:'genunix`vn_vfslocks_rele',v:1420},{n:'unix`mutex_enter',v:1202},{n:'unix`mutex_exit',v:512}],n:'genunix`vn_vfsunlock',v:3578}],n:'genunix`traverse',v:7243},{n:'genunix`vfs_getops',v:21},{c:[{n:'genunix`vfs_getops',v:157},{n:'unix`membar_consumer',v:123}],n:'genunix`vfs_matchops',v:336},{n:'genunix`vn_alloc',v:20},{n:'genunix`vn_exists',v:17},{n:'genunix`vn_mountedvfs',v:30},{n:'genunix`vn_setops',v:41},{n:'genunix`vn_vfsrlock',v:13},{n:'genunix`vn_vfsunlock',v:40},{n:'lofs`lfind',v:26},{n:'lofs`lsave',v:27},{n:'lofs`makelfsnode',v:28},{c:[{n:'genunix`kmem_cache_alloc',v:234},{n:'genunix`kmem_cpu_reload',v:1},{c:[{n:'genunix`kmem_cache_alloc',v:179},{n:'genunix`vn_recycle',v:33},{c:[{c:[{n:'genunix`vsd_free',v:155}],n:'genunix`vn_recycle',v:319},{n:'genunix`vsd_free',v:14}],n:'genunix`vn_reinit',v:424},{n:'unix`mutex_enter',v:318},{n:'unix`mutex_exit',v:142}],n:'genunix`vn_alloc',v:1189},{n:'genunix`vn_exists',v:50},{n:'genunix`vn_reinit',v:48},{n:'genunix`vn_setops',v:160},{n:'lofs`lfind',v:278},{n:'lofs`lsave',v:162},{n:'lofs`makelfsnode',v:82},{n:'lofs`table_lock_enter',v:220},{n:'unix`atomic_cas_64',v:318},{n:'unix`membar_consumer',v:237},{n:'unix`mutex_enter',v:640},{n:'unix`mutex_exit',v:138}],n:'lofs`makelonode',v:4212},{n:'lofs`table_lock_enter',v:43},{n:'ufs`ufs_lookup',v:46},{n:'unix`atomic_add_32',v:325},{n:'unix`mutex_exit',v:26}],n:'lofs`lo_lookup',v:19887},{n:'lofs`makelonode',v:39},{n:'unix`bcopy',v:896},{n:'unix`mutex_enter',v:947},{n:'unix`mutex_exit',v:337},{c:[{c:[{c:[{n:'unix`dispatch_hilevel',v:1}],n:'unix`do_interrupt',v:1}],n:'unix`_interrupt',v:1}],n:'unix`strlen',v:2659},{n:'zfs`specvp_check',v:10},{n:'zfs`zfs_fastaccesschk_execute',v:4},{c:[{n:'genunix`crgetuid',v:6},{c:[{n:'genunix`memcmp',v:3},{c:[{n:'genunix`memcmp',v:38}],n:'unix`bcmp',v:45}],n:'genunix`dnlc_lookup',v:263},{n:'unix`bcmp',v:11},{n:'unix`mutex_enter',v:309},{n:'unix`mutex_exit',v:135},{n:'zfs`specvp_check',v:20},{c:[{n:'genunix`crgetuid',v:2}],n:'zfs`zfs_fastaccesschk_execute',v:50}],n:'zfs`zfs_lookup',v:946}],n:'genunix`fop_lookup',v:29216},{n:'genunix`fsop_root',v:62},{n:'genunix`pn_fixslash',v:44},{n:'genunix`pn_getcomponent',v:454},{c:[{c:[{n:'lofs`lo_root',v:80},{n:'unix`mutex_enter',v:95},{n:'unix`mutex_exit',v:59}],n:'genunix`fsop_root',v:297},{n:'genunix`rwst_exit',v:12},{n:'genunix`rwst_tryenter',v:37},{n:'genunix`vn_mountedvfs',v:20},{n:'genunix`vn_rele',v:19},{n:'genunix`vn_vfslocks_getlock',v:47},{n:'genunix`vn_vfslocks_rele',v:34},{c:[{n:'genunix`kmem_alloc',v:11},{n:'genunix`rwst_enter_common',v:28},{n:'genunix`rwst_init',v:13},{c:[{n:'genunix`rwst_enter_common',v:314},{n:'unix`mutex_enter',v:238},{n:'unix`mutex_exit',v:49}],n:'genunix`rwst_tryenter',v:628},{c:[{n:'genunix`cv_init',v:56},{c:[{n:'genunix`kmem_cache_alloc',v:126},{n:'unix`mutex_enter',v:252},{n:'unix`mutex_exit',v:95}],n:'genunix`kmem_alloc',v:533},{n:'genunix`kmem_cache_alloc',v:17},{c:[{n:'genunix`cv_init',v:49},{n:'unix`mutex_init',v:38}],n:'genunix`rwst_init',v:173},{n:'unix`mutex_init',v:31}],n:'genunix`vn_vfslocks_getlock',v:973},{n:'unix`mutex_enter',v:455},{n:'unix`mutex_exit',v:250}],n:'genunix`vn_vfsrlock',v:2414},{c:[{n:'genunix`cv_broadcast',v:14},{n:'genunix`kmem_free',v:17},{n:'genunix`rwst_destroy',v:20},{c:[{n:'genunix`cv_broadcast',v:19}],n:'genunix`rwst_exit',v:110},{n:'genunix`vn_vfslocks_getlock',v:79},{c:[{n:'genunix`cv_destroy',v:81},{n:'genunix`kmem_cache_free',v:18},{c:[{n:'genunix`kmem_cache_free',v:116},{n:'unix`mutex_enter',v:195},{n:'unix`mutex_exit',v:90}],n:'genunix`kmem_free',v:457},{c:[{n:'genunix`cv_destroy',v:31},{n:'unix`mutex_destroy',v:53}],n:'genunix`rwst_destroy',v:146},{n:'unix`mutex_destroy',v:17}],n:'genunix`vn_vfslocks_rele',v:903},{n:'unix`mutex_enter',v:823},{n:'unix`mutex_exit',v:356}],n:'genunix`vn_vfsunlock',v:2372},{n:'lofs`lo_root',v:31},{n:'unix`mutex_enter',v:95},{n:'unix`mutex_exit',v:56}],n:'genunix`traverse',v:5557},{n:'genunix`vn_mountedvfs',v:43},{c:[{n:'genunix`crgetmapped',v:31},{c:[{n:'genunix`crgetmapped',v:41},{n:'lofs`freelonode',v:35},{c:[{n:'genunix`kmem_cache_free',v:29},{n:'genunix`vn_free',v:26},{n:'genunix`vn_invalid',v:20},{n:'genunix`vn_rele',v:25},{c:[{c:[{n:'genunix`kmem_cpu_reload',v:1}],n:'genunix`kmem_cache_free',v:184},{n:'genunix`kmem_free',v:115},{c:[{c:[{n:'genunix`kmem_cpu_reload',v:4}],n:'genunix`kmem_cache_free',v:215},{n:'genunix`kmem_cpu_reload',v:5},{c:[{n:'genunix`kmem_cache_free',v:209},{n:'unix`mutex_enter',v:299},{n:'unix`mutex_exit',v:160}],n:'genunix`kmem_free',v:785},{n:'genunix`vsd_free',v:48},{n:'unix`mutex_enter',v:314},{n:'unix`mutex_exit',v:171}],n:'genunix`vn_free',v:1663},{n:'genunix`vn_invalid',v:47},{n:'genunix`vn_rele',v:64},{n:'genunix`vsd_free',v:17},{n:'lofs`table_lock_enter',v:189},{n:'unix`membar_consumer',v:106},{n:'unix`mutex_enter',v:905},{n:'unix`mutex_exit',v:358},{n:'unix`strlen',v:1238}],n:'lofs`freelonode',v:5313},{n:'lofs`table_lock_enter',v:44},{n:'unix`atomic_add_32',v:292},{n:'unix`mutex_enter',v:279},{n:'unix`mutex_exit',v:212}],n:'lofs`lo_inactive',v:6307}],n:'genunix`fop_inactive',v:6689},{n:'lofs`lo_inactive',v:21}],n:'genunix`vn_rele',v:6943},{n:'genunix`vn_setpath',v:58},{n:'genunix`vn_vfsrlock',v:12},{n:'genunix`vn_vfsunlock',v:20},{n:'lofs`lo_lookup',v:65},{n:'unix`mutex_enter',v:575},{n:'unix`mutex_exit',v:379},{n:'unix`strlen',v:107},{n:'zfs`zfs_lookup',v:22}],n:'genunix`lookuppnvp',v:44242},{n:'genunix`pn_fixslash',v:14},{n:'genunix`pn_getcomponent',v:41},{n:'genunix`traverse',v:17},{n:'genunix`vn_mountedvfs',v:56},{n:'genunix`vn_rele',v:73},{c:[{n:'unix`mutex_delay_default',v:1},{n:'unix`tsc_read',v:1}],n:'unix`mutex_vector_enter',v:2}],n:'genunix`lookuppnatcred',v:44681},{n:'genunix`lookuppnvp',v:10},{c:[{n:'unix`copyinstr',v:25},{n:'unix`copystr',v:598}],n:'genunix`pn_get_buf',v:687},{n:'unix`copyinstr',v:18},{n:'unix`mutex_enter',v:320},{n:'unix`mutex_exit',v:163}],n:'genunix`lookupnameatcred',v:45978},{n:'genunix`lookuppnatcred',v:12},{n:'genunix`pn_get_buf',v:13}],n:'genunix`lookupnameat',v:46075},{n:'genunix`lookupnameatcred',v:22}],n:'genunix`vn_openat',v:46342},{n:'unix`mutex_enter',v:303},{n:'unix`mutex_exit',v:38}],n:'genunix`copen',v:49444},{n:'genunix`falloc',v:36},{n:'genunix`set_errno',v:9},{n:'genunix`setf',v:16},{n:'genunix`unfalloc',v:39},{n:'genunix`vn_openat',v:14}],n:'genunix`openat',v:49647}],n:'genunix`open',v:49669},{n:'genunix`openat',v:17},{c:[{c:[{c:[{n:'genunix`dotoprocs',v:1}],n:'genunix`doprio',v:1}],n:'genunix`priocntl_common',v:1}],n:'genunix`priocntlsys',v:1},{c:[{c:[{c:[{c:[{c:[{c:[{c:[{c:[{n:'genunix`dnlc_lookup',v:1}],n:'ufs`ufs_lookup',v:1}],n:'genunix`fop_lookup',v:1}],n:'lofs`lo_lookup',v:1}],n:'genunix`fop_lookup',v:1}],n:'genunix`lookuppnvp',v:1}],n:'genunix`lookuppnatcred',v:1}],n:'genunix`lookuppn',v:1}],n:'genunix`resolvepath',v:1},{c:[{c:[{c:[{c:[{c:[{c:[{c:[{n:'genunix`kmem_cache_free',v:1}],n:'genunix`kmem_free',v:1}],n:'genunix`removectx',v:1}],n:'genunix`schedctl_lwp_cleanup',v:1}],n:'genunix`exitlwps',v:1},{c:[{c:[{c:[{c:[{c:[{c:[{c:[{n:'unix`hment_compare',v:2}],n:'genunix`avl_find',v:2}],n:'unix`hment_remove',v:2},{n:'unix`page_numtopp_nolock',v:1}],n:'unix`hat_pte_unmap',v:3}],n:'unix`hat_unload_callback',v:3}],n:'genunix`segvn_unmap',v:3}],n:'genunix`as_free',v:3}],n:'genunix`relvm',v:3},{c:[{c:[{c:[{c:[{n:'genunix`vmem_free',v:1}],n:'genunix`segkp_release_internal',v:1}],n:'genunix`segkp_release',v:1}],n:'genunix`schedctl_freepage',v:1}],n:'genunix`schedctl_proc_cleanup',v:1}],n:'genunix`proc_exit',v:5}],n:'genunix`exit',v:5}],n:'genunix`rexit',v:5},{c:[{c:[{n:'unix`tsc_gethrtimeunscaled',v:43},{n:'unix`tsc_read',v:367}],n:'genunix`gethrtime_unscaled',v:420},{n:'unix`tsc_gethrtimeunscaled',v:59}],n:'genunix`syscall_mstate',v:1336},{n:'unix`atomic_add_64',v:205}],n:'unix`sys_syscall',v:51908}],n:'root',v:57412}; diff --git a/stories/icicle/01_unix_icicle.tsx b/stories/icicle/01_unix_icicle.tsx new file mode 100644 index 0000000000..d4bbecdf3b --- /dev/null +++ b/stories/icicle/01_unix_icicle.tsx @@ -0,0 +1,43 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from 'react'; + +import { Chart, Datum, Partition, PartitionLayout, Settings } from '../../src'; +import { STORYBOOK_LIGHT_THEME } from '../shared'; +import { config, getFlatData, getLayerSpec, maxDepth } from '../utils/hierarchical_input_utils'; +import { viridis18 as palette } from '../utils/utils'; + +const color = palette.slice().reverse(); + +export const Example = () => { + return ( + + + d.value as number} + valueFormatter={() => ''} + layers={getLayerSpec(color)} + config={{ ...config, partitionLayout: PartitionLayout.icicle }} + /> + + ); +}; diff --git a/stories/icicle/02_unix_flame.tsx b/stories/icicle/02_unix_flame.tsx new file mode 100644 index 0000000000..b76a714eab --- /dev/null +++ b/stories/icicle/02_unix_flame.tsx @@ -0,0 +1,43 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from 'react'; + +import { Chart, Datum, Partition, PartitionLayout, Settings } from '../../src'; +import { STORYBOOK_LIGHT_THEME } from '../shared'; +import { config, getFlatData, getLayerSpec, maxDepth } from '../utils/hierarchical_input_utils'; +import { plasma18 as palette } from '../utils/utils'; + +const color = palette.slice().reverse(); + +export const Example = () => { + return ( + + + d.value as number} + valueFormatter={() => ''} + layers={getLayerSpec(color)} + config={{ ...config, partitionLayout: PartitionLayout.flame }} + /> + + ); +}; diff --git a/stories/icicle/icicle.stories.tsx b/stories/icicle/icicle.stories.tsx new file mode 100644 index 0000000000..82e96bf81b --- /dev/null +++ b/stories/icicle/icicle.stories.tsx @@ -0,0 +1,30 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { SB_SOURCE_PANEL } from '../utils/storybook'; + +export default { + title: 'Flame (@alpha)', + parameters: { + options: { selectedPanel: SB_SOURCE_PANEL }, + }, +}; + +export { Example as flameChart } from './02_unix_flame'; +export { Example as icicleChart } from './01_unix_icicle'; diff --git a/stories/interactions/4_sunburst_slice_clicks.tsx b/stories/interactions/4_sunburst_slice_clicks.tsx index 5aa1a54122..1ac43f5d46 100644 --- a/stories/interactions/4_sunburst_slice_clicks.tsx +++ b/stories/interactions/4_sunburst_slice_clicks.tsx @@ -26,7 +26,7 @@ import { STORYBOOK_LIGHT_THEME } from '../shared'; import { indexInterpolatedFillColor, interpolatorCET2s, - categoricalFillColor, + discreteColor, colorBrewerCategoricalPastel12, } from '../utils/utils'; @@ -87,7 +87,7 @@ export const Example = () => { // pick color from color palette based on mean angle - rather distinct colors in the inner ring return indexInterpolatedFillColor(interpolatorCET2s)(d, (d.x0 + d.x1) / 2 / (2 * Math.PI), []); } - return categoricalFillColor(colorBrewerCategoricalPastel12)(d.sortIndex); + return discreteColor(colorBrewerCategoricalPastel12)(d.sortIndex); }, }, }, @@ -100,7 +100,7 @@ export const Example = () => { // pick color from color palette based on mean angle - rather distinct colors in the inner ring return indexInterpolatedFillColor(interpolatorCET2s)(d, (d.x0 + d.x1) / 2 / (2 * Math.PI), []); } - return categoricalFillColor(colorBrewerCategoricalPastel12)(d.sortIndex); + return discreteColor(colorBrewerCategoricalPastel12)(d.sortIndex); }, }, }, diff --git a/stories/legend/10_sunburst.tsx b/stories/legend/10_sunburst.tsx index 448678c414..0cf4951048 100644 --- a/stories/legend/10_sunburst.tsx +++ b/stories/legend/10_sunburst.tsx @@ -26,7 +26,7 @@ import { ShapeTreeNode } from '../../src/chart_types/partition_chart/layout/type import { mocks } from '../../src/mocks/hierarchical'; import { STORYBOOK_LIGHT_THEME } from '../shared'; import { - categoricalFillColor, + discreteColor, colorBrewerCategoricalStark9, countryLookup, productLookup, @@ -54,15 +54,14 @@ export const Example = () => { groupByRollup: (d: Datum) => d.sitc1, nodeLabel: (d: any) => productLookup[d].name, shape: { - fillColor: (d: ShapeTreeNode) => categoricalFillColor(colorBrewerCategoricalStark9, 0.7)(d.sortIndex), + fillColor: (d: ShapeTreeNode) => discreteColor(colorBrewerCategoricalStark9, 0.7)(d.sortIndex), }, }, { groupByRollup: (d: Datum) => countryLookup[d.dest].continentCountry.slice(0, 2), nodeLabel: (d: any) => regionLookup[d].regionName, shape: { - fillColor: (d: ShapeTreeNode) => - categoricalFillColor(colorBrewerCategoricalStark9, 0.5)(d.parent.sortIndex), + fillColor: (d: ShapeTreeNode) => discreteColor(colorBrewerCategoricalStark9, 0.5)(d.parent.sortIndex), }, }, { @@ -70,7 +69,7 @@ export const Example = () => { nodeLabel: (d: any) => countryLookup[d].name, shape: { fillColor: (d: ShapeTreeNode) => - categoricalFillColor(colorBrewerCategoricalStark9, 0.3)(d.parent.parent.sortIndex), + discreteColor(colorBrewerCategoricalStark9, 0.3)(d.parent.parent.sortIndex), }, }, ]} diff --git a/stories/stylings/20_partition_background.tsx b/stories/stylings/20_partition_background.tsx index bccab7e430..2db37ff4bc 100644 --- a/stories/stylings/20_partition_background.tsx +++ b/stories/stylings/20_partition_background.tsx @@ -25,7 +25,7 @@ import { config } from '../../src/chart_types/partition_chart/layout/config/conf import { ShapeTreeNode } from '../../src/chart_types/partition_chart/layout/types/viewmodel_types'; import { mocks } from '../../src/mocks/hierarchical'; import { - categoricalFillColor, + discreteColor, colorBrewerCategoricalStark9, countryLookup, productLookup, @@ -55,15 +55,14 @@ export const Example = () => { groupByRollup: (d: Datum) => d.sitc1, nodeLabel: (d: any) => productLookup[d].name, shape: { - fillColor: (d: ShapeTreeNode) => categoricalFillColor(colorBrewerCategoricalStark9, 0.7)(d.sortIndex), + fillColor: (d: ShapeTreeNode) => discreteColor(colorBrewerCategoricalStark9, 0.7)(d.sortIndex), }, }, { groupByRollup: (d: Datum) => countryLookup[d.dest].continentCountry.slice(0, 2), nodeLabel: (d: any) => regionLookup[d].regionName, shape: { - fillColor: (d: ShapeTreeNode) => - categoricalFillColor(colorBrewerCategoricalStark9, 0.5)(d.parent.sortIndex), + fillColor: (d: ShapeTreeNode) => discreteColor(colorBrewerCategoricalStark9, 0.5)(d.parent.sortIndex), }, }, { @@ -71,7 +70,7 @@ export const Example = () => { nodeLabel: (d: any) => countryLookup[d].name, shape: { fillColor: (d: ShapeTreeNode) => - categoricalFillColor(colorBrewerCategoricalStark9, 0.3)(d.parent.parent.sortIndex), + discreteColor(colorBrewerCategoricalStark9, 0.3)(d.parent.parent.sortIndex), }, }, ]} diff --git a/stories/sunburst/15_single_sunburst.tsx b/stories/sunburst/15_single_sunburst.tsx index 124ac6d25f..94400fb77d 100644 --- a/stories/sunburst/15_single_sunburst.tsx +++ b/stories/sunburst/15_single_sunburst.tsx @@ -25,7 +25,7 @@ import { ShapeTreeNode } from '../../src/chart_types/partition_chart/layout/type import { mocks } from '../../src/mocks/hierarchical'; import { STORYBOOK_LIGHT_THEME } from '../shared'; import { - categoricalFillColor, + discreteColor, colorBrewerCategoricalStark9, countryLookup, productLookup, @@ -45,15 +45,14 @@ export const Example = () => ( groupByRollup: (d: Datum) => d.sitc1, nodeLabel: (d: any) => productLookup[d].name, shape: { - fillColor: (d: ShapeTreeNode) => categoricalFillColor(colorBrewerCategoricalStark9, 0.7)(d.sortIndex), + fillColor: (d: ShapeTreeNode) => discreteColor(colorBrewerCategoricalStark9, 0.7)(d.sortIndex), }, }, { groupByRollup: (d: Datum) => countryLookup[d.dest].continentCountry.slice(0, 2), nodeLabel: (d: any) => regionLookup[d].regionName.replace(/\s/g, '\u00A0'), shape: { - fillColor: (d: ShapeTreeNode) => - categoricalFillColor(colorBrewerCategoricalStark9, 0.5)(d.parent.sortIndex), + fillColor: (d: ShapeTreeNode) => discreteColor(colorBrewerCategoricalStark9, 0.5)(d.parent.sortIndex), }, }, { @@ -61,7 +60,7 @@ export const Example = () => ( nodeLabel: (d: any) => countryLookup[d].name.replace(/\s/g, '\u00A0'), shape: { fillColor: (d: ShapeTreeNode) => - categoricalFillColor(colorBrewerCategoricalStark9, 0.3)(d.parent.parent.sortIndex), + discreteColor(colorBrewerCategoricalStark9, 0.3)(d.parent.parent.sortIndex), }, }, ]} diff --git a/stories/sunburst/26_percentage.tsx b/stories/sunburst/26_percentage.tsx index 5c7dd3add4..db53cb0405 100644 --- a/stories/sunburst/26_percentage.tsx +++ b/stories/sunburst/26_percentage.tsx @@ -25,7 +25,7 @@ import { ShapeTreeNode } from '../../src/chart_types/partition_chart/layout/type import { mocks } from '../../src/mocks/hierarchical'; import { STORYBOOK_LIGHT_THEME } from '../shared'; import { - categoricalFillColor, + discreteColor, colorBrewerCategoricalStark9, countryLookup, productLookup, @@ -47,15 +47,14 @@ export const Example = () => ( groupByRollup: (d: Datum) => d.sitc1, nodeLabel: (d: any) => productLookup[d].name, shape: { - fillColor: (d: ShapeTreeNode) => categoricalFillColor(colorBrewerCategoricalStark9, 0.7)(d.sortIndex), + fillColor: (d: ShapeTreeNode) => discreteColor(colorBrewerCategoricalStark9, 0.7)(d.sortIndex), }, }, { groupByRollup: (d: Datum) => countryLookup[d.dest].continentCountry.slice(0, 2), nodeLabel: (d: any) => regionLookup[d].regionName, shape: { - fillColor: (d: ShapeTreeNode) => - categoricalFillColor(colorBrewerCategoricalStark9, 0.5)(d.parent.sortIndex), + fillColor: (d: ShapeTreeNode) => discreteColor(colorBrewerCategoricalStark9, 0.5)(d.parent.sortIndex), }, }, { @@ -63,7 +62,7 @@ export const Example = () => ( nodeLabel: (d: any) => countryLookup[d].name, shape: { fillColor: (d: ShapeTreeNode) => - categoricalFillColor(colorBrewerCategoricalStark9, 0.3)(d.parent.parent.sortIndex), + discreteColor(colorBrewerCategoricalStark9, 0.3)(d.parent.parent.sortIndex), }, }, ]} diff --git a/stories/sunburst/27_heterogeneous_depth.tsx b/stories/sunburst/27_heterogeneous_depth.tsx index a12411cfb0..6cf4fa06e0 100644 --- a/stories/sunburst/27_heterogeneous_depth.tsx +++ b/stories/sunburst/27_heterogeneous_depth.tsx @@ -26,7 +26,7 @@ import { PrimitiveValue } from '../../src/chart_types/partition_chart/layout/uti import { mocks } from '../../src/mocks/hierarchical'; import { STORYBOOK_LIGHT_THEME } from '../shared'; import { - categoricalFillColor, + discreteColor, colorBrewerCategoricalStark9, countryLookup, productLookup, @@ -46,15 +46,14 @@ export const Example = () => ( groupByRollup: (d: Datum) => d.sitc1, nodeLabel: (d: PrimitiveValue) => d !== null && productLookup[d].name, shape: { - fillColor: (d: ShapeTreeNode) => categoricalFillColor(colorBrewerCategoricalStark9, 0.7)(d.sortIndex), + fillColor: (d: ShapeTreeNode) => discreteColor(colorBrewerCategoricalStark9, 0.7)(d.sortIndex), }, }, { groupByRollup: (d: Datum) => countryLookup[d.dest].continentCountry.slice(0, 2), nodeLabel: (d: PrimitiveValue) => d !== null && regionLookup[d].regionName, shape: { - fillColor: (d: ShapeTreeNode) => - categoricalFillColor(colorBrewerCategoricalStark9, 0.5)(d.parent.sortIndex), + fillColor: (d: ShapeTreeNode) => discreteColor(colorBrewerCategoricalStark9, 0.5)(d.parent.sortIndex), }, }, { @@ -63,7 +62,7 @@ export const Example = () => ( showAccessor: (d: PrimitiveValue) => !(['chn', 'hkg', 'jpn', 'kor'] as PrimitiveValue[]).includes(d), shape: { fillColor: (d: ShapeTreeNode) => - categoricalFillColor(colorBrewerCategoricalStark9, 0.3)(d.parent.parent.sortIndex), + discreteColor(colorBrewerCategoricalStark9, 0.3)(d.parent.parent.sortIndex), }, }, ]} diff --git a/stories/sunburst/3_value_formatted_2.tsx b/stories/sunburst/3_value_formatted_2.tsx index 401f0f0667..4fc81533b7 100644 --- a/stories/sunburst/3_value_formatted_2.tsx +++ b/stories/sunburst/3_value_formatted_2.tsx @@ -23,7 +23,7 @@ import { Chart, Datum, Partition } from '../../src'; import { config } from '../../src/chart_types/partition_chart/layout/config/config'; import { ShapeTreeNode } from '../../src/chart_types/partition_chart/layout/types/viewmodel_types'; import { mocks } from '../../src/mocks/hierarchical'; -import { categoricalFillColor, colorBrewerCategoricalPastel12, productLookup } from '../utils/utils'; +import { discreteColor, colorBrewerCategoricalPastel12, productLookup } from '../utils/utils'; export const Example = () => ( @@ -47,7 +47,7 @@ export const Example = () => ( }, }, shape: { - fillColor: (d: ShapeTreeNode) => categoricalFillColor(colorBrewerCategoricalPastel12)(d.sortIndex), + fillColor: (d: ShapeTreeNode) => discreteColor(colorBrewerCategoricalPastel12)(d.sortIndex), }, }, ]} diff --git a/stories/sunburst/9_sunburst_three_layers.tsx b/stories/sunburst/9_sunburst_three_layers.tsx index 8a8b0b8aae..f3218e8d38 100644 --- a/stories/sunburst/9_sunburst_three_layers.tsx +++ b/stories/sunburst/9_sunburst_three_layers.tsx @@ -26,7 +26,7 @@ import { ShapeTreeNode } from '../../src/chart_types/partition_chart/layout/type import { mocks } from '../../src/mocks/hierarchical'; import { STORYBOOK_LIGHT_THEME } from '../shared'; import { - categoricalFillColor, + discreteColor, colorBrewerCategoricalStark9, countryLookup, productLookup, @@ -47,7 +47,7 @@ export const Example = () => ( nodeLabel: (d: any) => productLookup[d].name, fillLabel: { maximizeFontSize: boolean('Maximize font size layer 1', true) }, shape: { - fillColor: (d: ShapeTreeNode) => categoricalFillColor(colorBrewerCategoricalStark9, 0.7)(d.sortIndex), + fillColor: (d: ShapeTreeNode) => discreteColor(colorBrewerCategoricalStark9, 0.7)(d.sortIndex), }, }, { @@ -55,8 +55,7 @@ export const Example = () => ( nodeLabel: (d: any) => regionLookup[d].regionName, fillLabel: { maximizeFontSize: boolean('Maximize font size layer 2', true) }, shape: { - fillColor: (d: ShapeTreeNode) => - categoricalFillColor(colorBrewerCategoricalStark9, 0.5)(d.parent.sortIndex), + fillColor: (d: ShapeTreeNode) => discreteColor(colorBrewerCategoricalStark9, 0.5)(d.parent.sortIndex), }, }, { @@ -65,7 +64,7 @@ export const Example = () => ( fillLabel: { maximizeFontSize: boolean('Maximize font size layer 3', true) }, shape: { fillColor: (d: ShapeTreeNode) => - categoricalFillColor(colorBrewerCategoricalStark9, 0.3)(d.parent.parent.sortIndex), + discreteColor(colorBrewerCategoricalStark9, 0.3)(d.parent.parent.sortIndex), }, }, ]} diff --git a/stories/treemap/2_one_layer_2.tsx b/stories/treemap/2_one_layer_2.tsx index 41ffac1305..d01b4f0023 100644 --- a/stories/treemap/2_one_layer_2.tsx +++ b/stories/treemap/2_one_layer_2.tsx @@ -25,7 +25,7 @@ import { ShapeTreeNode } from '../../src/chart_types/partition_chart/layout/type import { arrayToLookup } from '../../src/chart_types/partition_chart/layout/utils/calcs'; import { mocks } from '../../src/mocks/hierarchical'; import { productDimension } from '../../src/mocks/hierarchical/dimension_codes'; -import { categoricalFillColor, colorBrewerCategoricalPastel12 } from '../utils/utils'; +import { discreteColor, colorBrewerCategoricalPastel12 } from '../utils/utils'; const productLookup = arrayToLookup((d: Datum) => d.sitc1, productDimension); @@ -48,7 +48,7 @@ export const Example = () => ( }, }, shape: { - fillColor: (d: ShapeTreeNode) => categoricalFillColor(colorBrewerCategoricalPastel12)(d.sortIndex), + fillColor: (d: ShapeTreeNode) => discreteColor(colorBrewerCategoricalPastel12)(d.sortIndex), }, }, ]} diff --git a/stories/utils/hierarchical_input_utils.tsx b/stories/utils/hierarchical_input_utils.tsx new file mode 100644 index 0000000000..3d738036a8 --- /dev/null +++ b/stories/utils/hierarchical_input_utils.tsx @@ -0,0 +1,84 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { Datum, RecursivePartial } from '../../src'; +import { Config } from '../../src/chart_types/partition_chart/layout/types/config_types'; +import { PrimitiveValue } from '../../src/chart_types/partition_chart/layout/utils/group_by_rollup'; +import { mocks } from '../../src/mocks/hierarchical'; +import { discreteColor } from './utils'; + +const raw = mocks.observabilityTree; + +interface Node { + c?: Node[]; + n: string; + v: number; +} + +type Row = { [layerKey: string]: unknown; value: number; depth: number }; + +const flatTree = ({ c, n, v }: Node, depth: number): Row[] => { + if (!c) { + return [{ [`layer_${depth}`]: n, value: v, depth }]; + } + // as of writing this, the test runner can't run c.flatMap(...) + const childrenRows = c.reduce((a, child) => [...a, ...flatTree(child, depth + 1)], []); + const childrenTotal = childrenRows.reduce((p, { value }) => p + value, 0); + const missing = Math.max(0, v - childrenTotal); + if (missing > 0) { + childrenRows.unshift({ [`layer_${depth + 1}`]: undefined, value: missing / 2, depth }); + childrenRows.push({ [`layer_${depth + 1}`]: undefined, value: missing / 2, depth }); + } + childrenRows.forEach((innerChild) => { + innerChild[`layer_${depth}`] = n; + }); + return childrenRows; +}; + +/** @internal */ +export const getFlatData = () => flatTree(raw, 0); + +/** @internal */ +export const maxDepth = getFlatData().reduce((p, n) => Math.max(p, n.depth), 0); + +/** @internal */ +export const getLayerSpec = (color: [string, string, string][]) => + [...new Array(maxDepth + 1)].map((_, depth) => ({ + groupByRollup: (d: Datum) => d[`layer_${depth}`], + nodeLabel: (d: PrimitiveValue) => String(d), + showAccessor: (d: PrimitiveValue) => d !== undefined, + shape: { + fillColor: () => discreteColor(color, 0.8)(depth), + }, + })); + +/** @internal */ +export const config: RecursivePartial = { + fontFamily: 'Arial', + fillLabel: { + valueFormatter: (d: number) => d, + textInvertible: true, + fontWeight: 500, + }, + margin: { top: 0, bottom: 0, left: 0, right: 0 }, + minFontSize: 5, + maxFontSize: 9, + idealFontSizeJump: 1.01, + backgroundColor: 'rgba(229,229,229,1)', +}; diff --git a/stories/utils/utils.ts b/stories/utils/utils.ts index 975526d58f..5894548a28 100644 --- a/stories/utils/utils.ts +++ b/stories/utils/utils.ts @@ -36,7 +36,122 @@ export const indexInterpolatedFillColor = (colorMaker: ColorMaker) => (d: any, i // colorbrewer2.org based, categorical color example type RGBStrings = [string, string, string][]; const colorBrewerExportMatcher = /rgb\((\d{1,3}),(\d{1,3}),(\d{1,3})\)/; -const colorStringToTuple = (s: string) => (colorBrewerExportMatcher.exec(s) as string[]).slice(1); +const rgbStringToTuple = (s: string) => (colorBrewerExportMatcher.exec(s) as string[]).slice(1); +const hexStringToTuple = (s: string) => [ + String(parseInt(s.slice(1, 3), 16)), + String(parseInt(s.slice(3, 5), 16)), + String(parseInt(s.slice(5, 7), 16)), +]; + +export const plasma18 = [ + '#0d0887', + '#2f0596', + '#4903a0', + '#6100a7', + '#7801a8', + '#8e0ca4', + '#a21d9a', + '#b42e8d', + '#c43e7f', + '#d24f71', + '#de6164', + '#e97257', + '#f3854b', + '#f99a3e', + '#fdaf31', + '#fdc627', + '#f8df25', + '#f0f921', +].map(hexStringToTuple) as RGBStrings; + +export const viridis18 = [ + '#440154', + '#481769', + '#472a7a', + '#433d84', + '#3d4e8a', + '#355e8d', + '#2e6d8e', + '#297b8e', + '#23898e', + '#1f978b', + '#21a585', + '#2eb37c', + '#46c06f', + '#65cb5e', + '#89d548', + '#b0dd2f', + '#d8e219', + '#fde725', +].map(hexStringToTuple) as RGBStrings; + +export const cividis18 = [ + '#002051', + '#002b64', + '#0f356c', + '#23406e', + '#374a6e', + '#4b556d', + '#5c606e', + '#6c6b70', + '#797673', + '#858176', + '#928d78', + '#9f9978', + '#aea575', + '#bfb26f', + '#d2bf66', + '#e4cd5a', + '#f4db4e', + '#fdea45', +].map(hexStringToTuple) as RGBStrings; + +export const inferno18 = [ + '#000004', + '#0a0722', + '#1e0c45', + '#380962', + '#510e6c', + '#69166e', + '#801f6c', + '#982766', + '#b0315b', + '#c63d4d', + '#d94d3d', + '#e9612b', + '#f47918', + '#fa9407', + '#fcb014', + '#f8cd37', + '#f2ea69', + '#fcffa4', +].map(hexStringToTuple) as RGBStrings; + +export const colorBrewerSequential9: RGBStrings = [ + 'rgb(255,247,251)', + 'rgb(236,231,242)', + 'rgb(208,209,230)', + 'rgb(166,189,219)', + 'rgb(116,169,207)', + 'rgb(54,144,192)', + 'rgb(5,112,176)', + 'rgb(4,90,141)', + 'rgb(2,56,88)', +].map(rgbStringToTuple) as RGBStrings; + +export const colorBrewerDiverging11: RGBStrings = [ + 'rgb(158,1,66)', + 'rgb(213,62,79)', + 'rgb(244,109,67)', + 'rgb(253,174,97)', + 'rgb(254,224,139)', + 'rgb(255,255,191)', + 'rgb(230,245,152)', + 'rgb(171,221,164)', + 'rgb(102,194,165)', + 'rgb(50,136,189)', + 'rgb(94,79,162)', +].map(rgbStringToTuple) as RGBStrings; export const colorBrewerCategorical12: RGBStrings = [ 'rgb(166,206,227)', @@ -51,7 +166,7 @@ export const colorBrewerCategorical12: RGBStrings = [ 'rgb(106,61,154)', 'rgb(255,255,153)', 'rgb(177,89,40)', -].map(colorStringToTuple) as RGBStrings; +].map(rgbStringToTuple) as RGBStrings; export const colorBrewerCategoricalPastel12: RGBStrings = [ 'rgb(166,206,227)', @@ -66,7 +181,7 @@ export const colorBrewerCategoricalPastel12: RGBStrings = [ 'rgb(106,61,154)', 'rgb(255,255,153)', 'rgb(177,89,40)', -].map(colorStringToTuple) as RGBStrings; +].map(rgbStringToTuple) as RGBStrings; export const colorBrewerCategoricalStark9: RGBStrings = [ 'rgb(228,26,28)', @@ -78,9 +193,9 @@ export const colorBrewerCategoricalStark9: RGBStrings = [ 'rgb(166,86,40)', 'rgb(247,129,191)', 'rgb(153,153,153)', -].map(colorStringToTuple) as RGBStrings; +].map(rgbStringToTuple) as RGBStrings; -export const categoricalFillColor = (categoricalColors: RGBStrings, opacity = 1) => (i: number) => +export const discreteColor = (categoricalColors: RGBStrings, opacity = 1) => (i: number) => `rgba(${categoricalColors[i % categoricalColors.length].concat([opacity.toString()]).join(',')})`; export const decreasingOpacityCET2 = (opacity: number) => (d: any, i: number, a: any[]) =>