@unovis/ts 1.5.1-exf.12 → 1.5.1-exf.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -24,5 +24,7 @@ export interface TreemapConfigInterface<Datum> extends ComponentConfigInterface
24
24
  labelOffsetX?: number;
25
25
  /** Label offset in the Y direction. Default: `4` */
26
26
  labelOffsetY?: number;
27
+ /** Border radius of the tiles in pixels. Default: `2` */
28
+ tileBorderRadius?: number;
27
29
  }
28
30
  export declare const TreemapDefaultConfig: TreemapConfigInterface<unknown>;
@@ -1,6 +1,6 @@
1
1
  import { ComponentDefaultConfig } from '../../core/component/config.js';
2
2
 
3
- const TreemapDefaultConfig = Object.assign(Object.assign({}, ComponentDefaultConfig), { id: (d, i) => { var _a; return (_a = d.id) !== null && _a !== void 0 ? _a : i; }, value: undefined, tileColor: undefined, layers: [], tilePadding: 2, tilePaddingTop: undefined, labelInternalNodes: false, labelOffsetX: 4, labelOffsetY: 4 });
3
+ const TreemapDefaultConfig = Object.assign(Object.assign({}, ComponentDefaultConfig), { id: (d, i) => { var _a; return (_a = d.id) !== null && _a !== void 0 ? _a : i; }, value: undefined, tileColor: undefined, layers: [], tilePadding: 2, tilePaddingTop: undefined, labelInternalNodes: false, labelOffsetX: 4, labelOffsetY: 4, tileBorderRadius: 2 });
4
4
 
5
5
  export { TreemapDefaultConfig };
6
6
  //# sourceMappingURL=config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sources":["../../../src/components/treemap/config.ts"],"sourcesContent":["import { ComponentConfigInterface, ComponentDefaultConfig } from 'core/component/config'\nimport { ColorAccessor, NumericAccessor, StringAccessor } from 'types/accessor'\nimport { TreemapNode } from './types'\n\nexport interface TreemapConfigInterface<Datum> extends ComponentConfigInterface {\n id?: ((d: Datum, i: number) => string | number);\n /* Numeric accessor for segment size value. Default: `undefined`. */\n value?: NumericAccessor<Datum>;\n\n /** Array of accessor functions to defined the nested groups. Default: `[]` */\n layers: StringAccessor<Datum>[];\n\n /** A function that accepts a value number and returns a string. Default: `undefined` */\n numberFormat?: (value: number) => string;\n\n /** Color accessor function for tiles. Default: `undefined` */\n tileColor?: ColorAccessor<TreemapNode<Datum>>;\n\n /** Padding passed to D3 treemap layout. Default: `2` */\n tilePadding?: number;\n\n /**\n * Top padding passed to D3 treemap layout.\n * Useful to make room for internal node labels.\n * Default: `undefined`\n */\n tilePaddingTop?: number;\n\n /** Label internal nodes. Default: `false` */\n labelInternalNodes?: boolean;\n\n /** Label offset in the X direction. Default: `4` */\n labelOffsetX?: number;\n\n /** Label offset in the Y direction. Default: `4` */\n labelOffsetY?: number;\n}\n\nexport const TreemapDefaultConfig: TreemapConfigInterface<unknown> = {\n ...ComponentDefaultConfig,\n id: (d: unknown, i: number): string | number => (d as { id: string }).id ?? i,\n value: undefined,\n tileColor: undefined,\n layers: [],\n tilePadding: 2,\n tilePaddingTop: undefined,\n labelInternalNodes: false,\n labelOffsetX: 4,\n labelOffsetY: 4,\n}\n"],"names":[],"mappings":";;AAsCa,MAAA,oBAAoB,GAC5B,MAAA,CAAA,MAAA,CAAA,MAAA,CAAA,MAAA,CAAA,EAAA,EAAA,sBAAsB,CACzB,EAAA,EAAA,EAAE,EAAE,CAAC,CAAU,EAAE,CAAS,KAAsB,EAAA,IAAA,EAAA,CAAA,CAAA,OAAA,CAAC,EAAA,GAAA,CAAoB,CAAC,EAAE,MAAI,IAAA,IAAA,EAAA,KAAA,KAAA,CAAA,GAAA,EAAA,GAAA,CAAC,CAAA,EAAA,EAC7E,KAAK,EAAE,SAAS,EAChB,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,EAAE,EACV,WAAW,EAAE,CAAC,EACd,cAAc,EAAE,SAAS,EACzB,kBAAkB,EAAE,KAAK,EACzB,YAAY,EAAE,CAAC,EACf,YAAY,EAAE,CAAC,EAAA;;;;"}
1
+ {"version":3,"file":"config.js","sources":["../../../src/components/treemap/config.ts"],"sourcesContent":["import { ComponentConfigInterface, ComponentDefaultConfig } from 'core/component/config'\nimport { ColorAccessor, NumericAccessor, StringAccessor } from 'types/accessor'\nimport { TreemapNode } from './types'\n\nexport interface TreemapConfigInterface<Datum> extends ComponentConfigInterface {\n id?: ((d: Datum, i: number) => string | number);\n /* Numeric accessor for segment size value. Default: `undefined`. */\n value?: NumericAccessor<Datum>;\n\n /** Array of accessor functions to defined the nested groups. Default: `[]` */\n layers: StringAccessor<Datum>[];\n\n /** A function that accepts a value number and returns a string. Default: `undefined` */\n numberFormat?: (value: number) => string;\n\n /** Color accessor function for tiles. Default: `undefined` */\n tileColor?: ColorAccessor<TreemapNode<Datum>>;\n\n /** Padding passed to D3 treemap layout. Default: `2` */\n tilePadding?: number;\n\n /**\n * Top padding passed to D3 treemap layout.\n * Useful to make room for internal node labels.\n * Default: `undefined`\n */\n tilePaddingTop?: number;\n\n /** Label internal nodes. Default: `false` */\n labelInternalNodes?: boolean;\n\n /** Label offset in the X direction. Default: `4` */\n labelOffsetX?: number;\n\n /** Label offset in the Y direction. Default: `4` */\n labelOffsetY?: number;\n\n /** Border radius of the tiles in pixels. Default: `2` */\n tileBorderRadius?: number;\n}\n\nexport const TreemapDefaultConfig: TreemapConfigInterface<unknown> = {\n ...ComponentDefaultConfig,\n id: (d: unknown, i: number): string | number => (d as { id: string }).id ?? i,\n value: undefined,\n tileColor: undefined,\n layers: [],\n tilePadding: 2,\n tilePaddingTop: undefined,\n labelInternalNodes: false,\n labelOffsetX: 4,\n labelOffsetY: 4,\n tileBorderRadius: 2,\n}\n"],"names":[],"mappings":";;AAyCO,MAAM,oBAAoB,GAAA,MAAA,CAAA,MAAA,CAAA,MAAA,CAAA,MAAA,CAAA,EAAA,EAC5B,sBAAsB,CAAA,EAAA,EACzB,EAAE,EAAE,CAAC,CAAU,EAAE,CAAS,KAAsB,EAAA,IAAA,EAAA,CAAA,CAAA,OAAA,CAAC,EAAA,GAAA,CAAoB,CAAC,EAAE,MAAI,IAAA,IAAA,EAAA,KAAA,KAAA,CAAA,GAAA,EAAA,GAAA,CAAC,CAAA,EAAA,EAC7E,KAAK,EAAE,SAAS,EAChB,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,EAAE,EACV,WAAW,EAAE,CAAC,EACd,cAAc,EAAE,SAAS,EACzB,kBAAkB,EAAE,KAAK,EACzB,YAAY,EAAE,CAAC,EACf,YAAY,EAAE,CAAC,EACf,gBAAgB,EAAE,CAAC;;;;"}
@@ -1,14 +1,16 @@
1
+ import { select } from 'd3-selection';
1
2
  import { hierarchy, treemap } from 'd3-hierarchy';
2
3
  import { group, max } from 'd3-array';
3
4
  import { scaleLinear } from 'd3-scale';
5
+ import { wrapSVGText } from '../../utils/text.js';
4
6
  import { ComponentCore } from '../../core/component/index.js';
5
7
  import { SeriesDataModel } from '../../data-models/series.js';
6
- import { getColor } from '../../utils/color.js';
8
+ import { getColor, getHexValue, brighter, isDarkBackground } from '../../utils/color.js';
7
9
  import { isNumber, getString, getNumber } from '../../utils/data.js';
8
10
  import { smartTransition } from '../../utils/d3.js';
9
11
  import { TreemapDefaultConfig } from './config.js';
10
12
  import * as style from './style.js';
11
- import { tiles, tile, tileBackground, tileForeground, label } from './style.js';
13
+ import { tiles, tile, label } from './style.js';
12
14
 
13
15
  const defaultNumberFormat = (value) => `${value}`;
14
16
  class Treemap extends ComponentCore {
@@ -67,11 +69,11 @@ class Treemap extends ComponentCore {
67
69
  });
68
70
  const treemapData = treemapLayout(rootNode);
69
71
  const descendants = treemapData.descendants();
70
- // Set up the opacity scale based on depth
72
+ // Set up the brightness increase scale based on depth
71
73
  const maxDepth = max(descendants, d => d.depth);
72
- const opacity = scaleLinear()
74
+ const brightnessIncrease = scaleLinear()
73
75
  .domain([1, maxDepth])
74
- .range([1, 0.2]);
76
+ .range([0, 1]);
75
77
  // Set fill color and opacity for each node
76
78
  treemapData
77
79
  .eachBefore((node) => {
@@ -79,12 +81,14 @@ class Treemap extends ComponentCore {
79
81
  return;
80
82
  node.children.forEach((child, i) => {
81
83
  const treemapChild = child;
82
- // Calculate color for this child using the color accessor function
83
- const color = getColor(treemapChild, config.tileColor, i, treemapChild.depth !== 1);
84
+ // Calculate base color for this child using the color accessor function
85
+ let color = getColor(treemapChild, config.tileColor, i, treemapChild.depth !== 1);
84
86
  // If no color for this child, use the parent's color
85
- treemapChild._fill = color !== null && color !== void 0 ? color : node._fill;
86
- // Set opacity based on depth
87
- treemapChild._fillOpacity = color === null ? opacity(treemapChild.depth) : null;
87
+ color = color !== null && color !== void 0 ? color : node._fill;
88
+ // Convert CSS variables to hex values if needed
89
+ const hexColor = color ? getHexValue(color, this.g.node()) : null;
90
+ // Make the color brighter based on depth
91
+ treemapChild._fill = hexColor ? brighter(hexColor, brightnessIncrease(treemapChild.depth)) : null;
88
92
  });
89
93
  });
90
94
  // Render tiles
@@ -100,38 +104,26 @@ class Treemap extends ComponentCore {
100
104
  tilesEnter
101
105
  .append('clipPath')
102
106
  .attr('id', d => `clip-${d._id}`)
103
- .append('rect');
104
- // Tile background rectangles
105
- tilesEnter
106
107
  .append('rect')
107
- .attr('class', tileBackground)
108
- // Initialize tile positions so that the initial transition is smooth
109
- .attr('x', d => d.x0)
110
- .attr('y', d => d.y0)
111
- .attr('width', d => d.x1 - d.x0)
112
- .attr('height', d => d.y1 - d.y0);
113
- tiles.merge(tilesEnter).select(`rect.${tileBackground}`)
114
- .call(selection => smartTransition(selection, duration)
115
- .attr('x', d => d.x0)
116
- .attr('y', d => d.y0)
117
- .attr('width', d => d.x1 - d.x0)
118
- .attr('height', d => d.y1 - d.y0));
119
- // Tile foreground rectangles
108
+ .attr('rx', config.tileBorderRadius)
109
+ .attr('ry', config.tileBorderRadius);
110
+ // Tile rectangles
120
111
  tilesEnter
121
112
  .append('rect')
122
- .attr('class', tileForeground)
113
+ .attr('class', tile)
114
+ .attr('rx', config.tileBorderRadius)
115
+ .attr('ry', config.tileBorderRadius)
123
116
  // Initialize tile positions so that the initial transition is smooth
124
117
  .attr('x', d => d.x0)
125
118
  .attr('y', d => d.y0)
126
119
  .attr('width', d => d.x1 - d.x0)
127
120
  .attr('height', d => d.y1 - d.y0)
128
121
  .style('fill', d => { var _a; return (_a = d._fill) !== null && _a !== void 0 ? _a : getColor(d, config.tileColor); })
129
- // Make the tiles fade in on enter
130
- .style('fill-opacity', 0);
131
- tiles.merge(tilesEnter).select(`rect.${tileForeground}`)
122
+ .style('opacity', 0);
123
+ tiles.merge(tilesEnter).select(`rect.${tile}`)
132
124
  .call(selection => smartTransition(selection, duration)
133
125
  .style('fill', d => { var _a; return (_a = d._fill) !== null && _a !== void 0 ? _a : getColor(d, config.tileColor); })
134
- .style('fill-opacity', d => { var _a; return (_a = d._fillOpacity) !== null && _a !== void 0 ? _a : 1; })
126
+ .style('opacity', 1)
135
127
  .attr('x', d => d.x0)
136
128
  .attr('y', d => d.y0)
137
129
  .attr('width', d => d.x1 - d.x0)
@@ -156,9 +148,21 @@ class Treemap extends ComponentCore {
156
148
  .attr('clip-path', d => `url(#clip-${d._id})`)
157
149
  .attr('x', d => d.x0 + config.labelOffsetX)
158
150
  .attr('y', d => d.y0 + config.labelOffsetY)
159
- .text(d => {
151
+ .each(function (d) {
152
+ var _a;
153
+ const text = select(this);
160
154
  // @ts-expect-error This is a workaround for the D3 types
161
- return `${d.data[0]}: ${numberFormat(d.value)}`;
155
+ const label = `${d.data[0]}: ${numberFormat(d.value)}`;
156
+ text.text(label);
157
+ // Set text color based on background darkness
158
+ const backgroundColor = (_a = d._fill) !== null && _a !== void 0 ? _a : getColor(d, config.tileColor);
159
+ const textColor = backgroundColor && isDarkBackground(backgroundColor) ? '#ffffff' : '#000000';
160
+ text.style('fill', textColor);
161
+ // Apply text wrapping to leaf nodes
162
+ if (!d.children) {
163
+ const availableWidth = d.x1 - d.x0 - (2 * config.labelOffsetX);
164
+ wrapSVGText(text, availableWidth);
165
+ }
162
166
  });
163
167
  // Exit
164
168
  const tilesExit = tiles.exit();
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../src/components/treemap/index.ts"],"sourcesContent":["import { Selection } from 'd3-selection'\nimport { hierarchy, treemap } from 'd3-hierarchy'\nimport { group, max } from 'd3-array'\nimport { scaleLinear } from 'd3-scale'\nimport { ComponentCore } from 'core/component'\nimport { SeriesDataModel } from 'data-models/series'\nimport { getColor } from 'utils/color'\nimport { getString, getNumber, isNumber } from 'utils/data'\nimport { smartTransition } from 'utils/d3'\nimport { TreemapConfigInterface, TreemapDefaultConfig } from './config'\nimport { TreemapNode } from './types'\n\nimport * as s from './style'\n\nconst defaultNumberFormat = (value: number): string => `${value}`\n\nexport class Treemap<Datum> extends ComponentCore<Datum[], TreemapConfigInterface<Datum>> {\n static selectors = s\n protected _defaultConfig = TreemapDefaultConfig as TreemapConfigInterface<Datum>\n public config: TreemapConfigInterface<Datum> = this._defaultConfig\n\n datamodel: SeriesDataModel<Datum> = new SeriesDataModel()\n tiles: Selection<SVGGElement, unknown, SVGGElement, unknown>\n\n constructor (config?: TreemapConfigInterface<Datum>) {\n super()\n if (config) this.setConfig(config)\n this.tiles = this.g.append('g').attr('class', s.tiles)\n }\n\n _render (customDuration?: number): void {\n const { config, datamodel: { data }, _width, _height } = this\n const duration = isNumber(customDuration) ? customDuration : config.duration\n const { numberFormat = defaultNumberFormat } = config\n\n if (!config.layers?.length) {\n console.warn('Unovis | Treemap: No layers defined')\n return\n }\n\n // Map each layer accessor function to get string values from the data array\n const layerAccessors = config.layers.map(layerAccessor => {\n return (i: number) => getString(data[i], layerAccessor, i)\n })\n\n // Group the data indices by the layer accessors to create a hierarchical structure\n const nestedData = group(data.keys(), ...layerAccessors as [(d: number) => string])\n\n // Create the hierarchy from the grouped data,\n // which by itself is not quite right because there is an extra\n // level of nesting that we don't want, just above the leaf nodes.\n const rootNode = hierarchy(nestedData)\n\n // Compute the aggregation\n if (config.value) {\n rootNode.sum(index => typeof index === 'number' && getNumber(data[index], config.value, index))\n } else {\n rootNode.count()\n }\n\n // Fix the hierarchy by removing the extra level of nesting\n rootNode.each(d => {\n if (!d.children) {\n d.parent.children = null\n }\n })\n\n const treemapLayout = treemap()\n .size([_width, _height])\n .round(true)\n .padding(config.tilePadding)\n\n if (this.config.tilePaddingTop !== undefined) {\n treemapLayout.paddingTop(config.tilePaddingTop)\n }\n\n // Generate unique IDs for each node before creating the treemap layout\n let nodeId = 0\n rootNode.each(d => {\n (d as unknown as TreemapNode<Datum>)._id = `node-${nodeId++}`\n })\n\n const treemapData = treemapLayout(rootNode) as TreemapNode<Datum>\n const descendants = treemapData.descendants()\n\n // Set up the opacity scale based on depth\n const maxDepth = max(descendants, d => d.depth)\n const opacity = scaleLinear()\n .domain([1, maxDepth])\n .range([1, 0.2])\n\n // Set fill color and opacity for each node\n treemapData\n .eachBefore((node) => {\n if (!node.children) return\n node.children.forEach((child, i) => {\n const treemapChild = child as TreemapNode<Datum>\n\n // Calculate color for this child using the color accessor function\n const color = getColor(treemapChild, config.tileColor, i, treemapChild.depth !== 1)\n\n // If no color for this child, use the parent's color\n treemapChild._fill = color ?? (node as TreemapNode<Datum>)._fill\n\n // Set opacity based on depth\n treemapChild._fillOpacity = color === null ? opacity(treemapChild.depth) : null\n })\n })\n\n // Render tiles\n const visibleNodes = descendants.filter(d => d.depth > 0)\n const tiles = this.tiles\n .selectAll<SVGGElement, TreemapNode<Datum>>(`g.${s.tile}`)\n .data(visibleNodes, d => d._id)\n const tilesEnter = tiles\n .enter()\n .append('g')\n .attr('class', s.tile)\n\n // Add clipPath elements\n tilesEnter\n .append('clipPath')\n .attr('id', d => `clip-${d._id}`)\n .append('rect')\n\n // Tile background rectangles\n tilesEnter\n .append('rect')\n .attr('class', s.tileBackground)\n\n // Initialize tile positions so that the initial transition is smooth\n .attr('x', d => d.x0)\n .attr('y', d => d.y0)\n .attr('width', d => d.x1 - d.x0)\n .attr('height', d => d.y1 - d.y0)\n\n tiles.merge(tilesEnter).select(`rect.${s.tileBackground}`)\n .call(selection => smartTransition(selection, duration)\n .attr('x', d => d.x0)\n .attr('y', d => d.y0)\n .attr('width', d => d.x1 - d.x0)\n .attr('height', d => d.y1 - d.y0)\n )\n\n // Tile foreground rectangles\n tilesEnter\n .append('rect')\n .attr('class', s.tileForeground)\n // Initialize tile positions so that the initial transition is smooth\n .attr('x', d => d.x0)\n .attr('y', d => d.y0)\n .attr('width', d => d.x1 - d.x0)\n .attr('height', d => d.y1 - d.y0)\n .style('fill', d => d._fill ?? getColor(d, config.tileColor))\n\n // Make the tiles fade in on enter\n .style('fill-opacity', 0)\n\n tiles.merge(tilesEnter).select(`rect.${s.tileForeground}`)\n .call(selection => smartTransition(selection, duration)\n .style('fill', d => d._fill ?? getColor(d, config.tileColor))\n .style('fill-opacity', d => d._fillOpacity ?? 1)\n .attr('x', d => d.x0)\n .attr('y', d => d.y0)\n .attr('width', d => d.x1 - d.x0)\n .attr('height', d => d.y1 - d.y0)\n )\n\n // Update clipPath rects\n tiles.merge(tilesEnter).select('clipPath rect')\n .call(selection => smartTransition(selection, duration)\n .attr('x', d => d.x0)\n .attr('y', d => d.y0)\n .attr('width', d => d.x1 - d.x0)\n .attr('height', d => d.y1 - d.y0)\n )\n\n // Tile labels\n tilesEnter\n .append('text')\n .attr('class', s.label)\n .attr('clip-path', d => `url(#clip-${d._id})`)\n tiles.merge(tilesEnter)\n .filter(config.labelInternalNodes\n ? () => true\n : d => !d.children\n )\n .select(`text.${s.label}`)\n .attr('clip-path', d => `url(#clip-${d._id})`)\n .attr('x', d => d.x0 + config.labelOffsetX)\n .attr('y', d => d.y0 + config.labelOffsetY)\n .text(d => {\n // @ts-expect-error This is a workaround for the D3 types\n return `${d.data[0]}: ${numberFormat(d.value)}`\n })\n\n // Exit\n const tilesExit = tiles.exit()\n smartTransition(tilesExit, duration)\n .style('opacity', 0)\n .remove()\n }\n}\n"],"names":["s.tiles","s.tile","s.tileBackground","s.tileForeground","s.label","s"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../../src/components/treemap/index.ts"],"sourcesContent":["import { Selection, select } from 'd3-selection'\nimport { hierarchy, treemap } from 'd3-hierarchy'\nimport { group, max } from 'd3-array'\nimport { scaleLinear } from 'd3-scale'\nimport { wrapSVGText } from 'utils/text'\nimport { ComponentCore } from 'core/component'\nimport { SeriesDataModel } from 'data-models/series'\nimport { getColor, brighter, getHexValue, isDarkBackground } from 'utils/color'\nimport { getString, getNumber, isNumber } from 'utils/data'\nimport { smartTransition } from 'utils/d3'\nimport { TreemapConfigInterface, TreemapDefaultConfig } from './config'\nimport { TreemapNode } from './types'\n\nimport * as s from './style'\n\nconst defaultNumberFormat = (value: number): string => `${value}`\n\nexport class Treemap<Datum> extends ComponentCore<Datum[], TreemapConfigInterface<Datum>> {\n static selectors = s\n protected _defaultConfig = TreemapDefaultConfig as TreemapConfigInterface<Datum>\n public config: TreemapConfigInterface<Datum> = this._defaultConfig\n\n datamodel: SeriesDataModel<Datum> = new SeriesDataModel()\n tiles: Selection<SVGGElement, unknown, SVGGElement, unknown>\n\n constructor (config?: TreemapConfigInterface<Datum>) {\n super()\n if (config) this.setConfig(config)\n this.tiles = this.g.append('g').attr('class', s.tiles)\n }\n\n _render (customDuration?: number): void {\n const { config, datamodel: { data }, _width, _height } = this\n const duration = isNumber(customDuration) ? customDuration : config.duration\n const { numberFormat = defaultNumberFormat } = config\n\n if (!config.layers?.length) {\n console.warn('Unovis | Treemap: No layers defined')\n return\n }\n\n // Map each layer accessor function to get string values from the data array\n const layerAccessors = config.layers.map(layerAccessor => {\n return (i: number) => getString(data[i], layerAccessor, i)\n })\n\n // Group the data indices by the layer accessors to create a hierarchical structure\n const nestedData = group(data.keys(), ...layerAccessors as [(d: number) => string])\n\n // Create the hierarchy from the grouped data,\n // which by itself is not quite right because there is an extra\n // level of nesting that we don't want, just above the leaf nodes.\n const rootNode = hierarchy(nestedData)\n\n // Compute the aggregation\n if (config.value) {\n rootNode.sum(index => typeof index === 'number' && getNumber(data[index], config.value, index))\n } else {\n rootNode.count()\n }\n\n // Fix the hierarchy by removing the extra level of nesting\n rootNode.each(d => {\n if (!d.children) {\n d.parent.children = null\n }\n })\n\n const treemapLayout = treemap()\n .size([_width, _height])\n .round(true)\n .padding(config.tilePadding)\n\n if (this.config.tilePaddingTop !== undefined) {\n treemapLayout.paddingTop(config.tilePaddingTop)\n }\n\n // Generate unique IDs for each node before creating the treemap layout\n let nodeId = 0\n rootNode.each(d => {\n (d as unknown as TreemapNode<Datum>)._id = `node-${nodeId++}`\n })\n\n const treemapData = treemapLayout(rootNode) as TreemapNode<Datum>\n const descendants = treemapData.descendants()\n\n // Set up the brightness increase scale based on depth\n const maxDepth = max(descendants, d => d.depth)\n const brightnessIncrease = scaleLinear()\n .domain([1, maxDepth])\n .range([0, 1])\n\n // Set fill color and opacity for each node\n treemapData\n .eachBefore((node) => {\n if (!node.children) return\n node.children.forEach((child, i) => {\n const treemapChild = child as TreemapNode<Datum>\n\n // Calculate base color for this child using the color accessor function\n let color = getColor(treemapChild, config.tileColor, i, treemapChild.depth !== 1)\n\n // If no color for this child, use the parent's color\n color = color ?? (node as TreemapNode<Datum>)._fill\n\n // Convert CSS variables to hex values if needed\n const hexColor = color ? getHexValue(color, this.g.node()) : null\n\n // Make the color brighter based on depth\n treemapChild._fill = hexColor ? brighter(hexColor, brightnessIncrease(treemapChild.depth)) : null\n })\n })\n\n // Render tiles\n const visibleNodes = descendants.filter(d => d.depth > 0)\n const tiles = this.tiles\n .selectAll<SVGGElement, TreemapNode<Datum>>(`g.${s.tile}`)\n .data(visibleNodes, d => d._id)\n const tilesEnter = tiles\n .enter()\n .append('g')\n .attr('class', s.tile)\n\n // Add clipPath elements\n tilesEnter\n .append('clipPath')\n .attr('id', d => `clip-${d._id}`)\n .append('rect')\n .attr('rx', config.tileBorderRadius)\n .attr('ry', config.tileBorderRadius)\n\n // Tile rectangles\n tilesEnter\n .append('rect')\n .attr('class', s.tile)\n .attr('rx', config.tileBorderRadius)\n .attr('ry', config.tileBorderRadius)\n // Initialize tile positions so that the initial transition is smooth\n .attr('x', d => d.x0)\n .attr('y', d => d.y0)\n .attr('width', d => d.x1 - d.x0)\n .attr('height', d => d.y1 - d.y0)\n .style('fill', d => d._fill ?? getColor(d, config.tileColor))\n .style('opacity', 0)\n\n tiles.merge(tilesEnter).select(`rect.${s.tile}`)\n .call(selection => smartTransition(selection, duration)\n .style('fill', d => d._fill ?? getColor(d, config.tileColor))\n .style('opacity', 1)\n .attr('x', d => d.x0)\n .attr('y', d => d.y0)\n .attr('width', d => d.x1 - d.x0)\n .attr('height', d => d.y1 - d.y0)\n )\n\n // Update clipPath rects\n tiles.merge(tilesEnter).select('clipPath rect')\n .call(selection => smartTransition(selection, duration)\n .attr('x', d => d.x0)\n .attr('y', d => d.y0)\n .attr('width', d => d.x1 - d.x0)\n .attr('height', d => d.y1 - d.y0)\n )\n\n // Tile labels\n tilesEnter\n .append('text')\n .attr('class', s.label)\n .attr('clip-path', d => `url(#clip-${d._id})`)\n tiles.merge(tilesEnter)\n .filter(config.labelInternalNodes\n ? () => true\n : d => !d.children\n )\n .select(`text.${s.label}`)\n .attr('clip-path', d => `url(#clip-${d._id})`)\n .attr('x', d => d.x0 + config.labelOffsetX)\n .attr('y', d => d.y0 + config.labelOffsetY)\n .each(function (d) {\n const text = select(this) as unknown as Selection<SVGTextElement, any, SVGElement, any>\n\n // @ts-expect-error This is a workaround for the D3 types\n const label = `${d.data[0]}: ${numberFormat(d.value)}`\n text.text(label)\n\n // Set text color based on background darkness\n const backgroundColor = d._fill ?? getColor(d, config.tileColor)\n const textColor = backgroundColor && isDarkBackground(backgroundColor) ? '#ffffff' : '#000000'\n text.style('fill', textColor)\n\n // Apply text wrapping to leaf nodes\n if (!d.children) {\n const availableWidth = d.x1 - d.x0 - (2 * config.labelOffsetX)\n wrapSVGText(text, availableWidth)\n }\n })\n\n // Exit\n const tilesExit = tiles.exit()\n smartTransition(tilesExit, duration)\n .style('opacity', 0)\n .remove()\n }\n}\n"],"names":["s.tiles","s.tile","s.label","s"],"mappings":"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"}
package/index.js CHANGED
@@ -63,7 +63,7 @@ export { NestedDonutDirection, NestedDonutSegmentLabelAlignment } from './compon
63
63
  export { arrayOfIndices, clamp, clean, cloneDeep, countUnique, ensureArray, filterDataByRange, flatten, getBoolean, getExtent, getMax, getMin, getNearest, getNumber, getStackedData, getStackedExtent, getStackedValues, getString, getValue, groupBy, isAClassInstance, isArray, isEmpty, isEqual, isFunction, isNil, isNumber, isNumberWithinRange, isObject, isPlainObject, isString, isUndefined, merge, omit, shallowDiff, sortBy, throttle, unique, without } from './utils/data.js';
64
64
  export { allowedSvgTextTags, escapeStringKeepHash, estimateStringPixelLength, estimateTextSize, estimateWrappedTextHeight, getPreciseStringLengthPx, getWrappedText, kebabCase, kebabCaseToCamel, renderTextIntoFrame, renderTextToSvgTextElement, splitString, trimSVGText, trimString, trimStringEnd, trimStringMiddle, trimStringStart, wrapSVGText } from './utils/text.js';
65
65
  export { allowedSvgTags, getTransformValues, isStringSvg, sanitizeSvgString, transformValuesToString } from './utils/svg.js';
66
- export { getColor, getHexValue, hexToBrightness, hexToRgb, rgbToBrightness, rgbaToRgb } from './utils/color.js';
66
+ export { brighter, getColor, getHexValue, hexToBrightness, hexToRgb, isDarkBackground, rgbToBrightness, rgbaToRgb } from './utils/color.js';
67
67
  export { circlePath, convertLineToArc, polygon, roundedRectPath, scoreRectPath } from './utils/path.js';
68
68
  export { getCSSVariableValue, getCSSVariableValueInPixels, getHref, getPixelValue, guid, isStringCSSVariable, parseUnit, rectIntersect, stringToHtmlId } from './utils/misc.js';
69
69
  export { DefaultRange } from './utils/scale.js';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@unovis/ts",
3
3
  "description": "Modular data visualization framework for React, Angular, Svelte, Vue, Solid, and vanilla TypeScript or JavaScript",
4
- "version": "1.5.1-exf.12",
4
+ "version": "1.5.1-exf.13",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/f5/unovis.git",
package/utils/color.d.ts CHANGED
@@ -11,4 +11,18 @@ export declare function rgbToBrightness(rgb: RGBColor): number;
11
11
  export declare function hexToBrightness(hex: string): number;
12
12
  export declare function getHexValue(s: string, context: HTMLElement | SVGElement): string;
13
13
  export declare function rgbaToRgb(rgba: string, backgroundColor?: string): RGBColor;
14
+ /**
15
+ * Determines if a background color is considered "dark" based on its brightness
16
+ * @param backgroundColor - The color to check (hex, rgb, or rgba)
17
+ * @param threshold - Optional brightness threshold (0-1, default 0.5)
18
+ * @returns true if the background is dark, false if it's light
19
+ */
20
+ export declare function isDarkBackground(backgroundColor: string, threshold?: number): boolean;
21
+ /**
22
+ * Makes a color brighter by a certain amount
23
+ * @param inputColor - The color to brighten (hex, rgb, or rgba)
24
+ * @param amount - Amount to brighten by (0-1)
25
+ * @returns The brightened color in hex format
26
+ */
27
+ export declare function brighter(inputColor: string, amount: number): string;
14
28
  export {};
package/utils/color.js CHANGED
@@ -1,4 +1,4 @@
1
- import { color } from 'd3-color';
1
+ import { color, hcl } from 'd3-color';
2
2
  import { getCSSColorVariable } from '../styles/colors.js';
3
3
  import { getString, isNumber } from './data.js';
4
4
  import { isStringCSSVariable, getCSSVariableValue } from './misc.js';
@@ -42,7 +42,31 @@ function rgbaToRgb(rgba, backgroundColor) {
42
42
  g: Math.round((rgb.opacity * (rgb.g / 255) + (alpha * (bg.g / 255))) * 255),
43
43
  b: Math.round((rgb.opacity * (rgb.b / 255) + (alpha * (bg.b / 255))) * 255),
44
44
  };
45
+ }
46
+ /**
47
+ * Determines if a background color is considered "dark" based on its brightness
48
+ * @param backgroundColor - The color to check (hex, rgb, or rgba)
49
+ * @param threshold - Optional brightness threshold (0-1, default 0.5)
50
+ * @returns true if the background is dark, false if it's light
51
+ */
52
+ function isDarkBackground(backgroundColor, threshold = 0.6) {
53
+ const hex = getHexValue(backgroundColor, document.body);
54
+ if (!hex)
55
+ return false;
56
+ return hexToBrightness(hex) < threshold;
57
+ }
58
+ /**
59
+ * Makes a color brighter by a certain amount
60
+ * @param inputColor - The color to brighten (hex, rgb, or rgba)
61
+ * @param amount - Amount to brighten by (0-1)
62
+ * @returns The brightened color in hex format
63
+ */
64
+ function brighter(inputColor, amount) {
65
+ const c = hcl(inputColor);
66
+ if (!c)
67
+ return inputColor;
68
+ return c.brighter(amount).formatHex();
45
69
  }
46
70
 
47
- export { getColor, getHexValue, hexToBrightness, hexToRgb, rgbToBrightness, rgbaToRgb };
71
+ export { brighter, getColor, getHexValue, hexToBrightness, hexToRgb, isDarkBackground, rgbToBrightness, rgbaToRgb };
48
72
  //# sourceMappingURL=color.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"color.js","sources":["../../src/utils/color.ts"],"sourcesContent":["import { color } from 'd3-color'\n\n// Core\nimport { getCSSColorVariable } from 'styles/colors'\n\n// Utils\nimport { ColorAccessor, StringAccessor } from 'types/accessor'\nimport { getString, isNumber } from 'utils/data'\nimport { isStringCSSVariable, getCSSVariableValue } from 'utils/misc'\n\ntype RGBColor = { r: number; g: number; b: number }\n\n/** Retrieves color from the data if provided, fallbacks to CSS variables if the index was passed */\nexport function getColor<T> (\n d: T,\n accessor: ColorAccessor<T>,\n index?: number,\n dontFallbackToCssVar?: boolean\n): string | null {\n if (Array.isArray(accessor) && isFinite(index)) return accessor[index % accessor.length]\n\n const value = getString(d, accessor as StringAccessor<T>, index)\n return (value || ((isNumber(index) && !dontFallbackToCssVar) ? `var(${getCSSColorVariable(index)})` : null))\n}\n\nexport function hexToRgb (hex: string): RGBColor {\n const parsed = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex)\n return parsed ? {\n r: parseInt(parsed[1], 16),\n g: parseInt(parsed[2], 16),\n b: parseInt(parsed[3], 16),\n } : { r: 0, g: 0, b: 0 }\n}\n\nexport function rgbToBrightness (rgb: RGBColor): number {\n return (0.2126 * rgb.r + 0.7152 * rgb.g + 0.0722 * rgb.b) / 255\n}\n\nexport function hexToBrightness (hex: string): number {\n const rgb = hexToRgb(hex)\n return rgbToBrightness(rgb)\n}\n\nexport function getHexValue (s: string, context: HTMLElement | SVGElement): string {\n const hex = isStringCSSVariable(s) ? getCSSVariableValue(s, context) : s\n return color(hex)?.formatHex()\n}\n\nexport function rgbaToRgb (rgba: string, backgroundColor?: string): RGBColor {\n const rgb = color(rgba)?.rgb()\n if (!rgb || rgb.opacity === 1) return rgb\n const alpha = 1 - rgb.opacity\n const bg = color(backgroundColor ?? '#fff').rgb()\n return {\n r: Math.round((rgb.opacity * (rgb.r / 255) + (alpha * (bg.r / 255))) * 255),\n g: Math.round((rgb.opacity * (rgb.g / 255) + (alpha * (bg.g / 255))) * 255),\n b: Math.round((rgb.opacity * (rgb.b / 255) + (alpha * (bg.b / 255))) * 255),\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"color.js","sources":["../../src/utils/color.ts"],"sourcesContent":["import { color, hcl } from 'd3-color'\n\n// Core\nimport { getCSSColorVariable } from 'styles/colors'\n\n// Utils\nimport { ColorAccessor, StringAccessor } from 'types/accessor'\nimport { getString, isNumber } from 'utils/data'\nimport { isStringCSSVariable, getCSSVariableValue } from 'utils/misc'\n\ntype RGBColor = { r: number; g: number; b: number }\n\n/** Retrieves color from the data if provided, fallbacks to CSS variables if the index was passed */\nexport function getColor<T> (\n d: T,\n accessor: ColorAccessor<T>,\n index?: number,\n dontFallbackToCssVar?: boolean\n): string | null {\n if (Array.isArray(accessor) && isFinite(index)) return accessor[index % accessor.length]\n\n const value = getString(d, accessor as StringAccessor<T>, index)\n return (value || ((isNumber(index) && !dontFallbackToCssVar) ? `var(${getCSSColorVariable(index)})` : null))\n}\n\nexport function hexToRgb (hex: string): RGBColor {\n const parsed = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex)\n return parsed ? {\n r: parseInt(parsed[1], 16),\n g: parseInt(parsed[2], 16),\n b: parseInt(parsed[3], 16),\n } : { r: 0, g: 0, b: 0 }\n}\n\nexport function rgbToBrightness (rgb: RGBColor): number {\n return (0.2126 * rgb.r + 0.7152 * rgb.g + 0.0722 * rgb.b) / 255\n}\n\nexport function hexToBrightness (hex: string): number {\n const rgb = hexToRgb(hex)\n return rgbToBrightness(rgb)\n}\n\nexport function getHexValue (s: string, context: HTMLElement | SVGElement): string {\n const hex = isStringCSSVariable(s) ? getCSSVariableValue(s, context) : s\n return color(hex)?.formatHex()\n}\n\nexport function rgbaToRgb (rgba: string, backgroundColor?: string): RGBColor {\n const rgb = color(rgba)?.rgb()\n if (!rgb || rgb.opacity === 1) return rgb\n const alpha = 1 - rgb.opacity\n const bg = color(backgroundColor ?? '#fff').rgb()\n return {\n r: Math.round((rgb.opacity * (rgb.r / 255) + (alpha * (bg.r / 255))) * 255),\n g: Math.round((rgb.opacity * (rgb.g / 255) + (alpha * (bg.g / 255))) * 255),\n b: Math.round((rgb.opacity * (rgb.b / 255) + (alpha * (bg.b / 255))) * 255),\n }\n}\n\n/**\n * Determines if a background color is considered \"dark\" based on its brightness\n * @param backgroundColor - The color to check (hex, rgb, or rgba)\n * @param threshold - Optional brightness threshold (0-1, default 0.5)\n * @returns true if the background is dark, false if it's light\n */\nexport function isDarkBackground (backgroundColor: string, threshold = 0.6): boolean {\n const hex = getHexValue(backgroundColor, document.body)\n if (!hex) return false\n return hexToBrightness(hex) < threshold\n}\n\n/**\n * Makes a color brighter by a certain amount\n * @param inputColor - The color to brighten (hex, rgb, or rgba)\n * @param amount - Amount to brighten by (0-1)\n * @returns The brightened color in hex format\n */\nexport function brighter (inputColor: string, amount: number): string {\n const c = hcl(inputColor)\n if (!c) return inputColor\n return c.brighter(amount).formatHex()\n}\n"],"names":[],"mappings":"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"}
package/utils/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  export { arrayOfIndices, clamp, clean, cloneDeep, countUnique, ensureArray, filterDataByRange, flatten, getBoolean, getExtent, getMax, getMin, getNearest, getNumber, getStackedData, getStackedExtent, getStackedValues, getString, getValue, groupBy, isAClassInstance, isArray, isEmpty, isEqual, isFunction, isNil, isNumber, isNumberWithinRange, isObject, isPlainObject, isString, isUndefined, merge, omit, shallowDiff, sortBy, throttle, unique, without } from './data.js';
2
2
  export { allowedSvgTextTags, escapeStringKeepHash, estimateStringPixelLength, estimateTextSize, estimateWrappedTextHeight, getPreciseStringLengthPx, getWrappedText, kebabCase, kebabCaseToCamel, renderTextIntoFrame, renderTextToSvgTextElement, splitString, trimSVGText, trimString, trimStringEnd, trimStringMiddle, trimStringStart, wrapSVGText } from './text.js';
3
3
  export { allowedSvgTags, getTransformValues, isStringSvg, sanitizeSvgString, transformValuesToString } from './svg.js';
4
- export { getColor, getHexValue, hexToBrightness, hexToRgb, rgbToBrightness, rgbaToRgb } from './color.js';
4
+ export { brighter, getColor, getHexValue, hexToBrightness, hexToRgb, isDarkBackground, rgbToBrightness, rgbaToRgb } from './color.js';
5
5
  export { circlePath, convertLineToArc, polygon, roundedRectPath, scoreRectPath } from './path.js';
6
6
  export { getCSSVariableValue, getCSSVariableValueInPixels, getHref, getPixelValue, guid, isStringCSSVariable, parseUnit, rectIntersect, stringToHtmlId } from './misc.js';
7
7
  import './type.js';