@componyx/ui 0.0.0-stage → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AppSkin/AppSkin.css +1268 -0
- package/AppSkin/AppSkin.js +2748 -0
- package/AppSkin/Themes/Default.css +241 -0
- package/Base/Base.js +3407 -0
- package/Base/ComponentIcons.css +66 -0
- package/Base/Font/ComponentIcons.woff +0 -0
- package/Base/Font/UI.woff +0 -0
- package/Base/Library.js +8432 -0
- package/Base/NavigationManager.js +462 -0
- package/Base/ResponsiveTemplates.js +371 -0
- package/Base/Sanitizer.js +288 -0
- package/Base/Themes/Default.css +255 -0
- package/Base/UI.css +618 -0
- package/Base/UIResourcePath.js +6 -0
- package/Bindary/Bindary.js +2011 -0
- package/Bindary/Modules/Connection.js +216 -0
- package/Bindary/Modules/Core.js +854 -0
- package/Bindary/Modules/DataUpdater.js +351 -0
- package/Bindary/Modules/ExpressionEngine.js +347 -0
- package/Bindary/Modules/ProxyManager.js +482 -0
- package/Bindary/Modules/Renderer.js +605 -0
- package/Bindary/Modules/Router.js +291 -0
- package/Bindary/Modules/Scroller.js +89 -0
- package/Bindary/Modules/Template.js +1273 -0
- package/BookmarkSpy/BookmarkSpy.js +430 -0
- package/Box/Box.css +36 -0
- package/Box/Box.js +1685 -0
- package/Button/Button.css +470 -0
- package/Button/Button.js +1398 -0
- package/Button/Themes/Default.css +200 -0
- package/Carousel/Carousel.css +273 -0
- package/Carousel/Carousel.js +607 -0
- package/ColorButton/ColorButton.css +39 -0
- package/ColorButton/ColorButton.js +336 -0
- package/ColorPicker/ColorPicker.css +359 -0
- package/ColorPicker/ColorPicker.js +972 -0
- package/ComboBox/ComboBox.css +357 -0
- package/ComboBox/ComboBox.js +2342 -0
- package/ComboBox/Themes/Default.css +23 -0
- package/DataPager/DataPager.css +72 -0
- package/DataPager/DataPager.js +674 -0
- package/DatePicker/DatePicker.css +227 -0
- package/DatePicker/DatePicker.js +1531 -0
- package/DatePicker/Themes/Default.css +26 -0
- package/Dialog/Dialog.css +106 -0
- package/Dialog/Dialog.js +572 -0
- package/Dialog/Themes/Default.css +10 -0
- package/Editor/Data/Emoji.json +8285 -0
- package/Editor/Data/Special.json +1042 -0
- package/Editor/Editor.css +1562 -0
- package/Editor/Editor.js +4058 -0
- package/Editor/Font/Editor.woff +0 -0
- package/Editor/Modules/ComponentFactory.js +565 -0
- package/Editor/Modules/ContentManager.js +748 -0
- package/Editor/Modules/DialogManager.js +1234 -0
- package/Editor/Modules/EventManager.js +458 -0
- package/Editor/Modules/Format.js +950 -0
- package/Editor/Modules/History.js +191 -0
- package/Editor/Modules/LayoutState.js +379 -0
- package/Editor/Modules/ListManager.js +296 -0
- package/Editor/Modules/MenuManager.js +388 -0
- package/Editor/Modules/NodeManager.js +681 -0
- package/Editor/Modules/ParagraphButtons.js +122 -0
- package/Editor/Modules/Resizer.js +176 -0
- package/Editor/Modules/SelectionRange.js +564 -0
- package/Editor/Modules/SourceViewBuilder.js +212 -0
- package/Editor/Modules/SymbolPicker.js +208 -0
- package/Editor/Modules/Table.js +2327 -0
- package/Editor/Modules/TableDialog.js +757 -0
- package/Editor/Modules/Toolbar.js +375 -0
- package/Editor/Modules/TooltipMenu.js +125 -0
- package/Editor/Modules/Utility.js +131 -0
- package/Editor/Themes/Default.css +204 -0
- package/FileUpload/FileUpload.css +156 -0
- package/FileUpload/FileUpload.js +898 -0
- package/FileUpload/Themes/Default.css +17 -0
- package/Form/Form.css +1934 -0
- package/Form/Form.js +4943 -0
- package/Form/Modules/ActionManager.js +368 -0
- package/Form/Modules/BuildPanelManager.js +319 -0
- package/Form/Modules/ComponentFactory.js +468 -0
- package/Form/Modules/ComponentPanel.js +265 -0
- package/Form/Modules/ConfigPanelManager.js +685 -0
- package/Form/Modules/DataObserver.js +717 -0
- package/Form/Modules/Databinder.js +602 -0
- package/Form/Modules/Draggable.js +756 -0
- package/Form/Modules/OptionsPanel.js +342 -0
- package/Form/Modules/Renderer.js +1889 -0
- package/Form/Modules/RuleEngine.js +585 -0
- package/Form/Modules/RulesPanel.js +1158 -0
- package/Form/Modules/Types.js +1709 -0
- package/Form/Modules/ValidationManager.js +194 -0
- package/Form/Themes/Default.css +216 -0
- package/FormField/FormField.css +468 -0
- package/FormField/FormField.js +576 -0
- package/FormField/Themes/Default.css +99 -0
- package/Grid/Grid.css +544 -0
- package/Grid/Grid.js +3761 -0
- package/Grid/Themes/Default.css +43 -0
- package/LICENSE +126 -0
- package/MaskedTextBox/MaskedTextBox.css +28 -0
- package/MaskedTextBox/MaskedTextBox.js +642 -0
- package/MaskedTextBox/Themes/Default.css +6 -0
- package/Menu/Menu.css +328 -0
- package/Menu/Menu.js +2386 -0
- package/Menu/Themes/Default.css +24 -0
- package/NumericBox/NumericBox.css +120 -0
- package/NumericBox/NumericBox.js +984 -0
- package/PanelBar/PanelBar.css +123 -0
- package/PanelBar/PanelBar.js +505 -0
- package/PanelBar/Themes/Default.css +51 -0
- package/PieChart/PieChart.css +95 -0
- package/PieChart/PieChart.js +820 -0
- package/PieChart/Themes/Default.css +9 -0
- package/README.md +178 -3
- package/Slider/Slider.css +348 -0
- package/Slider/Slider.js +1306 -0
- package/Slider/Themes/Default.css +44 -0
- package/TabStrip/TabStrip.css +52 -0
- package/TabStrip/TabStrip.js +362 -0
- package/TabStrip/Themes/Default.css +35 -0
- package/TimePicker/Themes/Default.css +30 -0
- package/TimePicker/TimePicker.css +253 -0
- package/TimePicker/TimePicker.js +1485 -0
- package/TooltipManager/Themes/Default.css +21 -0
- package/TooltipManager/TooltipManager.css +227 -0
- package/TooltipManager/TooltipManager.js +791 -0
- package/Validator/Validator.css +54 -0
- package/Validator/Validator.js +2508 -0
- package/componyx.html-data.json +619 -0
- package/index.js +27 -0
- package/package.json +43 -4
- package/types/AppSkin.d.ts +842 -0
- package/types/Base.d.ts +1034 -0
- package/types/Bindary.d.ts +1196 -0
- package/types/BookmarkSpy.d.ts +112 -0
- package/types/Box.d.ts +374 -0
- package/types/Button.d.ts +455 -0
- package/types/Carousel.d.ts +136 -0
- package/types/ColorButton.d.ts +120 -0
- package/types/ColorPicker.d.ts +225 -0
- package/types/ComboBox.d.ts +507 -0
- package/types/DataPager.d.ts +152 -0
- package/types/DatePicker.d.ts +354 -0
- package/types/Dialog.d.ts +160 -0
- package/types/Editor.d.ts +1289 -0
- package/types/FileUpload.d.ts +206 -0
- package/types/Form.d.ts +3078 -0
- package/types/FormField.d.ts +204 -0
- package/types/Grid.d.ts +911 -0
- package/types/Library.d.ts +1899 -0
- package/types/MaskedTextBox.d.ts +91 -0
- package/types/Menu.d.ts +577 -0
- package/types/NumericBox.d.ts +310 -0
- package/types/PanelBar.d.ts +223 -0
- package/types/PieChart.d.ts +224 -0
- package/types/ResponsiveTemplates.d.ts +108 -0
- package/types/Slider.d.ts +227 -0
- package/types/TabStrip.d.ts +185 -0
- package/types/TimePicker.d.ts +265 -0
- package/types/TooltipManager.d.ts +178 -0
- package/types/UI.d.ts +29 -0
- package/types/Validator.d.ts +653 -0
- package/types/index.d.ts +59 -0
- package/ui.css +11783 -0
- package/ui.js +79477 -0
- package/ui.min.css +138 -0
- package/ui.min.js +264 -0
- package/ui.min.js.map +1 -0
|
@@ -0,0 +1,820 @@
|
|
|
1
|
+
/*! Componyx.UI | (c) E.H. Daanen / Componyx | BUSL-1.1 | componyx.com/license */
|
|
2
|
+
import '../Base/Base.js';
|
|
3
|
+
import '../Base/Library.js';
|
|
4
|
+
import '../TooltipManager/TooltipManager.js';
|
|
5
|
+
|
|
6
|
+
(function ()
|
|
7
|
+
{
|
|
8
|
+
/**
|
|
9
|
+
* PieChart CSS Variables.
|
|
10
|
+
* @typedef {Object} CSSVariables
|
|
11
|
+
* @memberof componyx.UI.PieChart
|
|
12
|
+
* @property {string} ["--donut-inner-stop"] - This CSS value is based on the donutInnerRatio setting.
|
|
13
|
+
* @property {string} ["--chart-size"] - The rendered chart size in pixels (half-pie only), used to align the legend with the semicircle.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* PieChart class.
|
|
18
|
+
* @class
|
|
19
|
+
* @memberof componyx.UI
|
|
20
|
+
* @augments componyx.UI.base.WebComponent
|
|
21
|
+
* @mixes componyx.UI.base.methods
|
|
22
|
+
* @param {String} id The id of the component.
|
|
23
|
+
* @param {Object|HTMLElement} properties The properties used to initialize the component or the container element.
|
|
24
|
+
* @returns {componyx.UI.PieChart} An instance of the component.
|
|
25
|
+
*/
|
|
26
|
+
class PieChart extends componyx.UI.base.WebComponent
|
|
27
|
+
{
|
|
28
|
+
#chart;
|
|
29
|
+
#segmentOverlay;
|
|
30
|
+
#legend;
|
|
31
|
+
#size;
|
|
32
|
+
#totalAngleDeg;
|
|
33
|
+
#startAngleDeg;
|
|
34
|
+
#totalValue;
|
|
35
|
+
#segmentAngleRanges = []; // Cache for segment angle ranges
|
|
36
|
+
#currentHoveredIndex = null;
|
|
37
|
+
#tooltipManager;
|
|
38
|
+
#leaveTimerId;
|
|
39
|
+
#segmentLabels = []; // label elements with their mid angle, for repositioning
|
|
40
|
+
#resizeObserver;
|
|
41
|
+
#outsidePointerDown;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Internal CSS class name constants.
|
|
45
|
+
* You can override any of these classes on the Component instance by defining a property named
|
|
46
|
+
* `cssClass<Key>` where <Key> is the PascalCase key from this object.
|
|
47
|
+
* Example:
|
|
48
|
+
* 'PANEL' -> 'cssClassPanel'
|
|
49
|
+
* Be cautious: overriding these classes without including the default names may break styling and functionality.
|
|
50
|
+
* @constant
|
|
51
|
+
* @type {Readonly<Object<string, string>>}
|
|
52
|
+
*/
|
|
53
|
+
classOption =
|
|
54
|
+
{
|
|
55
|
+
CHART: 'chart',
|
|
56
|
+
HALF: 'half-pie',
|
|
57
|
+
DONUT: 'donut',
|
|
58
|
+
LEGEND: 'legend',
|
|
59
|
+
LEGEND_ITEM: 'legend-item',
|
|
60
|
+
LEGEND_ITEM_COLOR: 'legend-item-color',
|
|
61
|
+
LEGEND_ITEM_LABEL: 'legend-item-label',
|
|
62
|
+
SEGMENT_LABEL: 'segment-label',
|
|
63
|
+
SEGMENT_OVERLAY: 'segment-overlay',
|
|
64
|
+
SEGMENT_HOVER: 'segment-hover'
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
constructor(id, properties)
|
|
68
|
+
{
|
|
69
|
+
super(id, properties);
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Gets or sets the shape of the pie chart (PIE or DONUT).
|
|
73
|
+
* @type {componyx.UI.PieChart.ShapeOption}
|
|
74
|
+
*/
|
|
75
|
+
this.shape = PieChart.ShapeOption.PIE;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Gets or sets where the segment labels are displayed (NONE, INNER, or OUTER).
|
|
79
|
+
* @type {componyx.UI.PieChart.SegmentLabelDisplayOption}
|
|
80
|
+
*/
|
|
81
|
+
this.segmentLabelDisplay = PieChart.SegmentLabelDisplayOption.OUTER;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Gets or sets the content of the segment labels (VALUE, LABEL, LABEL_VALUE).
|
|
85
|
+
* @type {componyx.UI.PieChart.SegmentLabelContentOption}
|
|
86
|
+
*/
|
|
87
|
+
this.segmentLabelContent = PieChart.SegmentLabelContentOption.VALUE;
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Gets or sets a value indicating whether the chart spans half a circle.
|
|
91
|
+
* @type {Boolean}
|
|
92
|
+
*/
|
|
93
|
+
this.isHalf = false;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Gets or sets a value indicating whether the legend is displayed.
|
|
97
|
+
* @type {Boolean}
|
|
98
|
+
*/
|
|
99
|
+
this.showLegend = true;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Gets or sets a value indicating whether segment values are shown in the legend labels.
|
|
103
|
+
* @type {Boolean}
|
|
104
|
+
*/
|
|
105
|
+
this.showValuesInLegend = false;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Gets or sets the start angle in degrees (0 = top, clockwise). Only applies to FULL variant.
|
|
109
|
+
* @type {Number}
|
|
110
|
+
*/
|
|
111
|
+
this.startAngle = 0;
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Gets or sets the inner hole size for DONUT variant as a ratio (0-1, where 0.6 = 60% hole).
|
|
115
|
+
* @type {Number}
|
|
116
|
+
*/
|
|
117
|
+
this.donutInnerRatio = 0.6;
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Gets or sets the base HEX color used for segments without a specified color. The colors of such segments are generated by shifting the hue of the base color.
|
|
121
|
+
* @type {String}
|
|
122
|
+
*/
|
|
123
|
+
this.baseColor = '#3b82f6';
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Gets or sets the segment label positioning offset.
|
|
127
|
+
* For OUTER labels: distance in pixels from chart edge (default: 20).
|
|
128
|
+
* For INNER labels: position ratio from 0 (inner edge) to 1 (outer edge) (default: 0.5).
|
|
129
|
+
* @type {Number}
|
|
130
|
+
*/
|
|
131
|
+
this.segmentLabelOffset = null;
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Gets or sets the list of segments.
|
|
135
|
+
* @type {componyx.UI.PieChart.Segment[]}
|
|
136
|
+
*/
|
|
137
|
+
this.segments = [];
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Gets or sets the id of the component from which the settings are cloned for the tooltip manager used by the PieChart component.
|
|
141
|
+
* @type {string}
|
|
142
|
+
*/
|
|
143
|
+
this.tooltipManagerId = null;
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* @class
|
|
147
|
+
* @augments componyx.UI.base.Events
|
|
148
|
+
* @memberof componyx.UI.PieChart
|
|
149
|
+
* @property {componyx.UI.base.Event} onSegmentEnter - Fires when the pointer enters a segment. @see {@link componyx.UI.PieChart.PieChartEventArgs}
|
|
150
|
+
* @property {componyx.UI.base.Event} onSegmentLeave - Fires when the pointer leaves a segment. @see {@link componyx.UI.PieChart.PieChartEventArgs}
|
|
151
|
+
* @property {componyx.UI.base.Event} onSegmentClick - Fires when a segment is clicked. @see {@link componyx.UI.PieChart.PieChartEventArgs}
|
|
152
|
+
* @property {componyx.UI.base.Event} onRenderSegmentLabel - Fires when a segment label is rendered. @see {@link componyx.UI.PieChart.PieChartLabelRenderEventArgs}
|
|
153
|
+
* @property {componyx.UI.base.Event} onRenderLegendLabel - Fires when a legend label is rendered. @see {@link componyx.UI.PieChart.PieChartLabelRenderEventArgs}
|
|
154
|
+
* @see {@link componyx.UI.base.Events}
|
|
155
|
+
*/
|
|
156
|
+
function PieChartEvents(events)
|
|
157
|
+
{
|
|
158
|
+
Object.assign(this, events);
|
|
159
|
+
|
|
160
|
+
this.onSegmentEnter = $base.static.createEvent('onSegmentEnter');
|
|
161
|
+
this.onSegmentLeave = $base.static.createEvent('onSegmentLeave');
|
|
162
|
+
this.onSegmentClick = $base.static.createEvent('onSegmentClick');
|
|
163
|
+
this.onRenderSegmentLabel = $base.static.createEvent('onRenderSegmentLabel');
|
|
164
|
+
this.onRenderLegendLabel = $base.static.createEvent('onRenderLegendLabel');
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* PieChart events
|
|
168
|
+
* @type {componyx.UI.PieChart.PieChartEvents}
|
|
169
|
+
*/
|
|
170
|
+
this.events = new PieChartEvents(this.events);
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* @typedef {Object} componyx.UI.PieChart.PieChartEventArgs
|
|
174
|
+
* @property {componyx.UI.PieChart} PieChart - The PieChart instance.
|
|
175
|
+
* @property {Object} eventArgs - The event object containing more detailed information about the event.
|
|
176
|
+
* @property {componyx.UI.PieChart.Segment} eventArgs.segment - The data segment.
|
|
177
|
+
* @property {Event} eventArgs.event - The original event object.
|
|
178
|
+
*/
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* @typedef {Object} componyx.UI.PieChart.PieChartLabelRenderEventArgs
|
|
182
|
+
* @property {componyx.UI.PieChart} PieChart - The PieChart instance.
|
|
183
|
+
* @property {componyx.UI.PieChart.Segment} segment - The data segment.
|
|
184
|
+
* @property {HTMLElement} element - The label DOM element (segment label or legend label) that can be customized.
|
|
185
|
+
*/
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Renders the component.
|
|
190
|
+
*/
|
|
191
|
+
render()
|
|
192
|
+
{
|
|
193
|
+
if (this.renderState != $base.static.RenderState.RENDERING)
|
|
194
|
+
{
|
|
195
|
+
super.render(this.#preRender, 'pie-chart');
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// render logic after loading resources
|
|
200
|
+
this.#draw();
|
|
201
|
+
this.renderChildren();
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Executes post render tasks.
|
|
206
|
+
* @private
|
|
207
|
+
*/
|
|
208
|
+
async postRender()
|
|
209
|
+
{
|
|
210
|
+
if (this.renderState != $base.static.RenderState.RENDERING) // extra safety to never execute a postRender when the component state is incorrect
|
|
211
|
+
return;
|
|
212
|
+
|
|
213
|
+
super.postRender();
|
|
214
|
+
this.#positionSegmentLabels();
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Destroys the component.
|
|
219
|
+
* @param {Boolean} keepEvents A value indicating if component events should be kept.
|
|
220
|
+
* @param {Boolean} removeElement=true A value indicating if the corresponding HTML Element should be removed.
|
|
221
|
+
* @see {@link componyx.UI.base.methods#destroy}
|
|
222
|
+
* @function
|
|
223
|
+
*/
|
|
224
|
+
destroy(keepEvents, removeElement = true)
|
|
225
|
+
{
|
|
226
|
+
this.#dispose();
|
|
227
|
+
super.destroy(keepEvents, removeElement);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Gets the css class if it exists and otherwise the default css class.
|
|
232
|
+
* @returns {String} The css class.
|
|
233
|
+
*/
|
|
234
|
+
getCssClass(cssClassValue)
|
|
235
|
+
{
|
|
236
|
+
return super.getCssClass(this.classOption, cssClassValue);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
#preRender()
|
|
240
|
+
{
|
|
241
|
+
let script = [];
|
|
242
|
+
|
|
243
|
+
script.push('TooltipManager');
|
|
244
|
+
return ['PieChart', script];
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
#draw()
|
|
248
|
+
{
|
|
249
|
+
// Sum values for normalization
|
|
250
|
+
this.#totalValue = this.segments.reduce((sum, seg) => sum + seg.value, 0);
|
|
251
|
+
|
|
252
|
+
// For HALF variant, we'll start at 270° (bottom/6 o'clock) and go 180° clockwise to 90° (top/12 o'clock)
|
|
253
|
+
// This way the semicircle goes from left to right across the top
|
|
254
|
+
if (this.isHalf)
|
|
255
|
+
{
|
|
256
|
+
this.classList.add(this.getCssClass(this.classOption.HALF));
|
|
257
|
+
this.#startAngleDeg = 270; // Start at bottom
|
|
258
|
+
this.#totalAngleDeg = 180; // Half circle
|
|
259
|
+
}
|
|
260
|
+
else
|
|
261
|
+
{
|
|
262
|
+
this.#startAngleDeg = this.startAngle ?? 0;
|
|
263
|
+
this.#totalAngleDeg = 360; // Full circle
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (this.shape === PieChart.ShapeOption.DONUT)
|
|
267
|
+
{
|
|
268
|
+
this.classList.add(this.getCssClass(this.classOption.DONUT));
|
|
269
|
+
this.style.setProperty('--donut-inner-stop', `${this.donutInnerRatio * 100}%`);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
this.#tooltipManager = this.#createTooltipManager(this, this.id + '_TooltipManager', this.tooltipManagerId);
|
|
273
|
+
this.#buildSegmentAngleRanges();
|
|
274
|
+
this.#generateSegmentColors();
|
|
275
|
+
this.#createChart();
|
|
276
|
+
|
|
277
|
+
if (this.showLegend)
|
|
278
|
+
this.#createLegend();
|
|
279
|
+
|
|
280
|
+
this.style.removeProperty('--chart-size');
|
|
281
|
+
|
|
282
|
+
if (this.isHalf)
|
|
283
|
+
{
|
|
284
|
+
this.style.setProperty('--chart-size', `${this.#size}px`); // used by the CSS to align the legend with the semicircle
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
#createTooltipManager(container, id, cloneId)
|
|
289
|
+
{
|
|
290
|
+
const tooltipBox = $UI.createComponent(componyx.UI.Box, {
|
|
291
|
+
id: id + '_TooltipManagerBox',
|
|
292
|
+
containerElement: container,
|
|
293
|
+
trackPointer: true,
|
|
294
|
+
alignX: componyx.UI.Box.AlignXOption.CENTER,
|
|
295
|
+
alignY: componyx.UI.Box.AlignYOption.BOTTOM,
|
|
296
|
+
expandDirection: componyx.UI.Box.ExpandDirectionOption.UP,
|
|
297
|
+
autoInvertFit: true,
|
|
298
|
+
animation: { showType: 0, hideType: 0 }
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
return this.#createComponent(container, componyx.UI.TooltipManager, id, cloneId, {
|
|
302
|
+
boxId: tooltipBox.id,
|
|
303
|
+
selectableTooltipContent: false,
|
|
304
|
+
arrowless: true
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
#createComponent(container, type, id, cloneId, config = {})
|
|
309
|
+
{
|
|
310
|
+
const component = $UI.createComponent(type, { id: id, containerElement: container });
|
|
311
|
+
|
|
312
|
+
component.clone($UI.store[cloneId], this);
|
|
313
|
+
Object.assign(component, Object.fromEntries(Object.entries(config).filter(([k, v]) => v !== undefined))); // don't assign undefined properties
|
|
314
|
+
component.showing = true;
|
|
315
|
+
component.events.onPostRender.priorityAdd(() => { this.isReady.apply(this); }, null, true);
|
|
316
|
+
|
|
317
|
+
return component;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Assign colors to segments if not already set.
|
|
322
|
+
* Colors are based on this.baseColor and evenly shifted in hue.
|
|
323
|
+
* @private
|
|
324
|
+
*/
|
|
325
|
+
#generateSegmentColors()
|
|
326
|
+
{
|
|
327
|
+
const segments = this.#segmentAngleRanges.map(r => r.segment),
|
|
328
|
+
segmentCount = segments.length,
|
|
329
|
+
[baseR, baseG, baseB] = $lib.hexToRgb(this.baseColor),
|
|
330
|
+
[baseHue, baseSaturation, baseValue] = $lib.rgbToHsv(baseR, baseG, baseB),
|
|
331
|
+
hueStep = (this.isHalf ? 0.5 : 1) / segmentCount; // Calculate hue step per segment, 0.5 = half pie, 1 = full pie
|
|
332
|
+
|
|
333
|
+
segments.forEach((segment, index) =>
|
|
334
|
+
{
|
|
335
|
+
if (!segment.color)
|
|
336
|
+
{
|
|
337
|
+
const newHue = (baseHue + index * hueStep) % 1, // Shift hue for this segment
|
|
338
|
+
saturation = Math.max(baseSaturation, 0.6), // clamp saturation/value for nicer colors
|
|
339
|
+
value = Math.max(baseValue, 0.75),
|
|
340
|
+
[r, g, b] = $lib.hsvToRgb(newHue, saturation, value);
|
|
341
|
+
|
|
342
|
+
segment.color = '#' + $lib.rgbToHex(r, g, b);
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
#createChart()
|
|
348
|
+
{
|
|
349
|
+
this.#chart = $lib.element({ container: this, attrs: { class: this.getCssClass(this.classOption.CHART) } });
|
|
350
|
+
this.#chart.style.background = this.#createConicGradient();
|
|
351
|
+
|
|
352
|
+
this.classList.remove('hidden');
|
|
353
|
+
this.#size = this.#chart.getBoundingClientRect().width;
|
|
354
|
+
this.classList.add('hidden');
|
|
355
|
+
|
|
356
|
+
if (this.segmentLabelDisplay !== PieChart.SegmentLabelDisplayOption.NONE)
|
|
357
|
+
this.#createSegmentLabels();
|
|
358
|
+
|
|
359
|
+
this.#segmentOverlay = $lib.element({ container: this.#chart, attrs: { class: this.getCssClass(this.classOption.SEGMENT_OVERLAY) } });
|
|
360
|
+
this.#bindEvents();
|
|
361
|
+
this.#observeResize();
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
#createSegmentLabels()
|
|
365
|
+
{
|
|
366
|
+
let currentAngleDeg = this.#startAngleDeg;
|
|
367
|
+
this.#segmentLabels = [];
|
|
368
|
+
|
|
369
|
+
this.segments.forEach(segment =>
|
|
370
|
+
{
|
|
371
|
+
const segmentAngleDeg = this.#getSegmentAngleDeg(segment.value),
|
|
372
|
+
midAngleDeg = this.#getMidAngleDeg(currentAngleDeg, segmentAngleDeg),
|
|
373
|
+
label = {
|
|
374
|
+
element: $lib.element({ container: this, attrs: { class: this.getCssClass(this.classOption.SEGMENT_LABEL) } }),
|
|
375
|
+
midAngleRad: this.#degToRad(this.#cssNormalize(midAngleDeg))
|
|
376
|
+
},
|
|
377
|
+
value = `${segment.value}${segment.valueSuffix || ''}`;
|
|
378
|
+
|
|
379
|
+
if (this.segmentLabelContent == PieChart.SegmentLabelContentOption.LABEL_VALUE)
|
|
380
|
+
label.element.innerText = `${segment.label} (${value})`;
|
|
381
|
+
else if (this.segmentLabelContent == PieChart.SegmentLabelContentOption.LABEL)
|
|
382
|
+
label.element.innerText = segment.label;
|
|
383
|
+
else // default to VALUE
|
|
384
|
+
label.element.innerText = value;
|
|
385
|
+
|
|
386
|
+
this.#segmentLabels.push(label);
|
|
387
|
+
this.#positionSegmentLabel(label);
|
|
388
|
+
this.events.onRenderSegmentLabel.fire(this, { segment, element: label.element });
|
|
389
|
+
|
|
390
|
+
currentAngleDeg += segmentAngleDeg;
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
#positionSegmentLabels()
|
|
395
|
+
{
|
|
396
|
+
this.#segmentLabels.forEach(label => this.#positionSegmentLabel(label));
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
#positionSegmentLabel(label)
|
|
400
|
+
{
|
|
401
|
+
const outerChartRadius = this.#size / 2,
|
|
402
|
+
innerChartRadius = this.shape === PieChart.ShapeOption.DONUT ? outerChartRadius * this.donutInnerRatio : 0,
|
|
403
|
+
isInnerLabel = (this.segmentLabelDisplay === PieChart.SegmentLabelDisplayOption.INNER),
|
|
404
|
+
labelOffset = this.segmentLabelOffset ?? (isInnerLabel ? 0.5 : 20),
|
|
405
|
+
labelRadius = isInnerLabel
|
|
406
|
+
? innerChartRadius + (outerChartRadius - innerChartRadius) * labelOffset // ratio (0-1) of the ring width
|
|
407
|
+
: outerChartRadius + labelOffset, // pixels from the outer edge
|
|
408
|
+
chartRect = this.#chart.getBoundingClientRect(), // rendered position of the chart, including any CSS transforms
|
|
409
|
+
hostRect = this.getBoundingClientRect(),
|
|
410
|
+
centerX = chartRect.left - hostRect.left + outerChartRadius,
|
|
411
|
+
centerY = chartRect.top - hostRect.top + outerChartRadius;
|
|
412
|
+
|
|
413
|
+
label.element.style.left = `${centerX + (labelRadius * Math.cos(label.midAngleRad))}px`;
|
|
414
|
+
label.element.style.top = `${centerY + (labelRadius * Math.sin(label.midAngleRad))}px`;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
#observeResize()
|
|
418
|
+
{
|
|
419
|
+
this.#resizeObserver?.disconnect();
|
|
420
|
+
this.#resizeObserver = new ResizeObserver(() =>
|
|
421
|
+
{
|
|
422
|
+
const size = this.#chart?.getBoundingClientRect().width;
|
|
423
|
+
|
|
424
|
+
if (!size || size === this.#size) // hidden (0) or unchanged
|
|
425
|
+
return;
|
|
426
|
+
|
|
427
|
+
this.#size = size;
|
|
428
|
+
this.#positionSegmentLabels();
|
|
429
|
+
|
|
430
|
+
if (this.isHalf)
|
|
431
|
+
{
|
|
432
|
+
this.style.setProperty('--chart-size', `${size}px`);
|
|
433
|
+
}
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
this.#resizeObserver.observe(this.#chart);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
#createLegend()
|
|
440
|
+
{
|
|
441
|
+
this.#legend = $lib.element({ container: this, attrs: { class: this.getCssClass(this.classOption.LEGEND) } });
|
|
442
|
+
|
|
443
|
+
this.segments.forEach(segment =>
|
|
444
|
+
{
|
|
445
|
+
const itemEl = $lib.element({ container: this.#legend, attrs: { class: this.getCssClass(this.classOption.LEGEND_ITEM) } }),
|
|
446
|
+
colorEl = $lib.element({ tag: 'span', container: itemEl, attrs: { class: this.getCssClass(this.classOption.LEGEND_ITEM_COLOR) } }),
|
|
447
|
+
labelEl = $lib.element({ tag: 'span', container: itemEl, attrs: { class: this.getCssClass(this.classOption.LEGEND_ITEM_LABEL) } });
|
|
448
|
+
|
|
449
|
+
colorEl.style.backgroundColor = segment.color;
|
|
450
|
+
|
|
451
|
+
if (this.showValuesInLegend)
|
|
452
|
+
labelEl.innerText = `${segment.label} (${segment.value}${segment.valueSuffix})`;
|
|
453
|
+
else
|
|
454
|
+
labelEl.innerText = segment.label;
|
|
455
|
+
|
|
456
|
+
this.events.onRenderLegendLabel.fire(this, { segment, element: labelEl });
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
#bindEvents()
|
|
461
|
+
{
|
|
462
|
+
$lib.on(this.#chart, 'pointermove pointerdown', (e) =>
|
|
463
|
+
{
|
|
464
|
+
clearTimeout(this.#leaveTimerId);
|
|
465
|
+
const segmentIndex = this.#getSegmentAtPointer(e);
|
|
466
|
+
|
|
467
|
+
if (segmentIndex !== this.#currentHoveredIndex)
|
|
468
|
+
{
|
|
469
|
+
this.#currentHoveredIndex = segmentIndex;
|
|
470
|
+
this.#hoverSegment(segmentIndex);
|
|
471
|
+
|
|
472
|
+
if (segmentIndex !== null)
|
|
473
|
+
{
|
|
474
|
+
this.#chart.style.cursor = 'pointer';
|
|
475
|
+
this.events.onSegmentEnter.fire(this, { segment: this.segments[segmentIndex], event: e });
|
|
476
|
+
}
|
|
477
|
+
else
|
|
478
|
+
{
|
|
479
|
+
this.#chart.style.cursor = 'default';
|
|
480
|
+
this.events.onSegmentLeave.fire(this, { segment: null, event: e });
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
$lib.on(this.#chart, 'click', (e) =>
|
|
486
|
+
{
|
|
487
|
+
const segmentIndex = this.#getSegmentAtPointer(e);
|
|
488
|
+
if (segmentIndex !== null)
|
|
489
|
+
{
|
|
490
|
+
this.events.onSegmentClick.fire(this, { segment: this.segments[segmentIndex], event: e });
|
|
491
|
+
}
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
$lib.on(this.#chart, 'pointerleave', (e) =>
|
|
495
|
+
{
|
|
496
|
+
if (e.pointerType === 'touch') // a touch pointer "leaves" when the finger lifts, the tooltip stays until a tap elsewhere
|
|
497
|
+
return;
|
|
498
|
+
|
|
499
|
+
this.#leaveTimerId = setTimeout(() => this.#clearHover(e));
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
// on touch, a tap outside the chart dismisses the hovered segment
|
|
503
|
+
this.#outsidePointerDown = (e) =>
|
|
504
|
+
{
|
|
505
|
+
if (e.pointerType === 'touch' && !this.#chart?.contains(e.target))
|
|
506
|
+
this.#clearHover(e);
|
|
507
|
+
};
|
|
508
|
+
|
|
509
|
+
this.ownerDocument.addEventListener('pointerdown', this.#outsidePointerDown);
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
#clearHover(e)
|
|
513
|
+
{
|
|
514
|
+
if (this.#currentHoveredIndex !== null)
|
|
515
|
+
{
|
|
516
|
+
this.#currentHoveredIndex = null;
|
|
517
|
+
this.#hoverSegment(null);
|
|
518
|
+
this.#chart.style.cursor = 'default';
|
|
519
|
+
this.events.onSegmentLeave.fire(this, { segment: null, event: e });
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
#buildSegmentAngleRanges()
|
|
524
|
+
{
|
|
525
|
+
this.#segmentAngleRanges = [];
|
|
526
|
+
let currentAngleDeg = 0;
|
|
527
|
+
|
|
528
|
+
this.segments.forEach((segment, index) =>
|
|
529
|
+
{
|
|
530
|
+
const segmentAngleDeg = this.#getSegmentAngleDeg(segment.value);
|
|
531
|
+
const nextAngleDeg = currentAngleDeg + segmentAngleDeg;
|
|
532
|
+
|
|
533
|
+
this.#segmentAngleRanges.push({
|
|
534
|
+
startAngle: currentAngleDeg,
|
|
535
|
+
endAngle: nextAngleDeg,
|
|
536
|
+
segment
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
currentAngleDeg = nextAngleDeg;
|
|
540
|
+
});
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
#createConicGradient()
|
|
544
|
+
{
|
|
545
|
+
let gradientParts = [];
|
|
546
|
+
|
|
547
|
+
this.#segmentAngleRanges.forEach((range) =>
|
|
548
|
+
{
|
|
549
|
+
const endColor = range.segment.endColor || range.segment.color;
|
|
550
|
+
gradientParts.push(`${range.segment.color} ${range.startAngle}deg, ${endColor} ${range.endAngle}deg`);
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
// For half-pie, fill the rest of the circle with transparent
|
|
554
|
+
if (this.isHalf)
|
|
555
|
+
gradientParts.push(`transparent ${this.#totalAngleDeg}deg 360deg`);
|
|
556
|
+
|
|
557
|
+
// Use 'from' to set where the gradient starts
|
|
558
|
+
return `conic-gradient(from ${this.#startAngleDeg}deg, ${gradientParts.join(', ')})`;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
#hoverSegment(hoveredIndex)
|
|
562
|
+
{
|
|
563
|
+
this.#tooltipManager.removeTooltip(this.id);
|
|
564
|
+
|
|
565
|
+
if (hoveredIndex === null)
|
|
566
|
+
{
|
|
567
|
+
this.#segmentOverlay.style.background = 'transparent';
|
|
568
|
+
this.#segmentOverlay.classList.remove(this.getCssClass(this.classOption.SEGMENT_HOVER));
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
const range = this.#segmentAngleRanges[hoveredIndex];
|
|
573
|
+
|
|
574
|
+
// Simple 3-stop gradient: transparent before, color on segment (the color is lightened with CSS), transparent after
|
|
575
|
+
this.#segmentOverlay.style.background = `conic-gradient(from ${this.#startAngleDeg}deg, transparent 0deg ${range.startAngle}deg, ${range.segment.color} ${range.startAngle}deg ${range.endAngle}deg, transparent ${range.endAngle}deg 360deg)`;
|
|
576
|
+
this.#segmentOverlay.classList.add(this.getCssClass(this.classOption.SEGMENT_HOVER));
|
|
577
|
+
|
|
578
|
+
if (range.segment.tooltip)
|
|
579
|
+
{
|
|
580
|
+
this.#tooltipManager.addTooltip(this.id, range.segment.tooltip);
|
|
581
|
+
this.#tooltipManager.addTrigger(this.#segmentOverlay, this.id);
|
|
582
|
+
this.#tooltipManager.showTooltip(this.#segmentOverlay, true);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
#getSegmentAtPointer(event)
|
|
587
|
+
{
|
|
588
|
+
const rect = this.#chart.getBoundingClientRect(),
|
|
589
|
+
size = rect.width,
|
|
590
|
+
x = event.clientX - rect.left,
|
|
591
|
+
y = event.clientY - rect.top,
|
|
592
|
+
centerX = size / 2,
|
|
593
|
+
centerY = size / 2,
|
|
594
|
+
dx = x - centerX,
|
|
595
|
+
dy = y - centerY,
|
|
596
|
+
distance = Math.hypot(dx, dy), // calculates Euclidean distance (same as sqrt(dx*dx + dy*dy)) using Pythagorean theorem
|
|
597
|
+
outerRadius = size / 2,
|
|
598
|
+
innerRadius = this.shape === PieChart.ShapeOption.DONUT ? outerRadius * this.donutInnerRatio : 0;
|
|
599
|
+
|
|
600
|
+
if (distance < innerRadius || distance > outerRadius)
|
|
601
|
+
{
|
|
602
|
+
return null;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
// Calculate angle from mouse position
|
|
606
|
+
let angleRad = Math.atan2(dy, dx);
|
|
607
|
+
let angleDeg = (angleRad * 180 / Math.PI);
|
|
608
|
+
if (angleDeg < 0) angleDeg += 360;
|
|
609
|
+
|
|
610
|
+
// Adjust for CSS coordinate system (0° = top, clockwise)
|
|
611
|
+
angleDeg = (angleDeg + 90) % 360;
|
|
612
|
+
|
|
613
|
+
// Adjust for startAngle to get relative angle
|
|
614
|
+
let relativeAngle = angleDeg - this.#startAngleDeg;
|
|
615
|
+
if (relativeAngle < 0) relativeAngle += 360;
|
|
616
|
+
|
|
617
|
+
// For HALF variant, check if in visible range
|
|
618
|
+
if (this.isHalf && relativeAngle > this.#totalAngleDeg)
|
|
619
|
+
{
|
|
620
|
+
return null;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
// Binary search through cached angle ranges
|
|
624
|
+
let left = 0;
|
|
625
|
+
let right = this.#segmentAngleRanges.length - 1;
|
|
626
|
+
|
|
627
|
+
while (left <= right)
|
|
628
|
+
{
|
|
629
|
+
const mid = Math.floor((left + right) / 2);
|
|
630
|
+
const range = this.#segmentAngleRanges[mid];
|
|
631
|
+
|
|
632
|
+
if (relativeAngle >= range.startAngle && relativeAngle < range.endAngle)
|
|
633
|
+
{
|
|
634
|
+
return mid;
|
|
635
|
+
}
|
|
636
|
+
else if (relativeAngle < range.startAngle)
|
|
637
|
+
{
|
|
638
|
+
right = mid - 1; // Search left half
|
|
639
|
+
}
|
|
640
|
+
else
|
|
641
|
+
{
|
|
642
|
+
left = mid + 1; // Search right half
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
return null;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
/**
|
|
650
|
+
* Convert degrees to radians
|
|
651
|
+
* @private
|
|
652
|
+
*/
|
|
653
|
+
#degToRad(degrees)
|
|
654
|
+
{
|
|
655
|
+
return (degrees / 180) * Math.PI;
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
/**
|
|
659
|
+
* Calculate the angle (in degrees) that a segment should occupy
|
|
660
|
+
* @private
|
|
661
|
+
*/
|
|
662
|
+
#getSegmentAngleDeg(segmentValue)
|
|
663
|
+
{
|
|
664
|
+
return (segmentValue / this.#totalValue) * this.#totalAngleDeg;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
/**
|
|
668
|
+
* Find the middle angle of a segment given its start angle and size
|
|
669
|
+
* @private
|
|
670
|
+
*/
|
|
671
|
+
#getMidAngleDeg(startAngleDeg, segmentAngleDeg)
|
|
672
|
+
{
|
|
673
|
+
return startAngleDeg + segmentAngleDeg / 2;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
/**
|
|
677
|
+
* Convert CSS conic-gradient angle (0° = top, clockwise) to standard math angle
|
|
678
|
+
* Math uses 0° = right, counterclockwise, so we need to adjust
|
|
679
|
+
* @private
|
|
680
|
+
*/
|
|
681
|
+
#cssNormalize(cssAngleDeg)
|
|
682
|
+
{
|
|
683
|
+
return cssAngleDeg - 90;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
#dispose()
|
|
687
|
+
{
|
|
688
|
+
// Clean up references
|
|
689
|
+
this.#resizeObserver?.disconnect();
|
|
690
|
+
this.#resizeObserver = null;
|
|
691
|
+
this.#chart = null;
|
|
692
|
+
this.#segmentOverlay = null;
|
|
693
|
+
this.#legend = null;
|
|
694
|
+
this.#segmentAngleRanges = [];
|
|
695
|
+
this.#segmentLabels = [];
|
|
696
|
+
this.#currentHoveredIndex = null;
|
|
697
|
+
this.#tooltipManager = null;
|
|
698
|
+
this.ownerDocument.removeEventListener('pointerdown', this.#outsidePointerDown);
|
|
699
|
+
this.#outsidePointerDown = null;
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
|
|
704
|
+
|
|
705
|
+
/**
|
|
706
|
+
* Represents a chart segment.
|
|
707
|
+
* @class
|
|
708
|
+
* @memberof componyx.UI.PieChart
|
|
709
|
+
*/
|
|
710
|
+
class Segment
|
|
711
|
+
{
|
|
712
|
+
/**
|
|
713
|
+
* @param {Object} [properties] The properties used to initialize the object.
|
|
714
|
+
* @param {string} [properties.id] - Gets or sets the id of the segment.
|
|
715
|
+
* @param {string} [properties.label] - Gets or sets the label of the segment
|
|
716
|
+
* @param {string} [properties.tooltip] - Gets or sets the tooltip of the segment
|
|
717
|
+
* @param {any} [properties.color] - Gets or sets the CSS color value of the segment.
|
|
718
|
+
* @param {any} [properties.value] - Gets or sets the value of the segment.
|
|
719
|
+
* @param {any} [properties.valueSuffix] - Gets or sets the value suffix (e.g. %) of the segment.
|
|
720
|
+
*/
|
|
721
|
+
constructor(properties)
|
|
722
|
+
{
|
|
723
|
+
/**
|
|
724
|
+
* Gets or sets the id of the segment.
|
|
725
|
+
* @type {String}
|
|
726
|
+
*/
|
|
727
|
+
this.id = null;
|
|
728
|
+
|
|
729
|
+
/**
|
|
730
|
+
* Gets or sets the label of the segment
|
|
731
|
+
* @type {String}
|
|
732
|
+
*/
|
|
733
|
+
this.label = null;
|
|
734
|
+
|
|
735
|
+
/**
|
|
736
|
+
* Gets or sets the tooltip of the segment
|
|
737
|
+
* @type {String}
|
|
738
|
+
*/
|
|
739
|
+
this.tooltip = null;
|
|
740
|
+
|
|
741
|
+
/**
|
|
742
|
+
* Gets or sets the CSS color value of the segment.
|
|
743
|
+
* @type {String}
|
|
744
|
+
*/
|
|
745
|
+
this.color = null;
|
|
746
|
+
|
|
747
|
+
/**
|
|
748
|
+
* Gets or sets the optional CSS end color value of the segment.
|
|
749
|
+
* @type {String}
|
|
750
|
+
*/
|
|
751
|
+
this.endColor = null;
|
|
752
|
+
|
|
753
|
+
/**
|
|
754
|
+
* Gets or sets the value of the segment.
|
|
755
|
+
* @type {Number}
|
|
756
|
+
*/
|
|
757
|
+
this.value = null;
|
|
758
|
+
|
|
759
|
+
/**
|
|
760
|
+
* Gets or sets the value suffix (e.g. %) of the segment.
|
|
761
|
+
* @type {Number}
|
|
762
|
+
*/
|
|
763
|
+
this.valueSuffix = '';
|
|
764
|
+
|
|
765
|
+
_clone(this, properties);
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
PieChart.Segment = Segment;
|
|
770
|
+
|
|
771
|
+
/**
|
|
772
|
+
* ShapeOption
|
|
773
|
+
* @readonly
|
|
774
|
+
* @enum {string}
|
|
775
|
+
*/
|
|
776
|
+
PieChart.ShapeOption =
|
|
777
|
+
{
|
|
778
|
+
PIE: 'pie',
|
|
779
|
+
DONUT: 'donut'
|
|
780
|
+
};
|
|
781
|
+
|
|
782
|
+
/**
|
|
783
|
+
* SegmentLabelDisplayOption
|
|
784
|
+
* @readonly
|
|
785
|
+
* @enum {string}
|
|
786
|
+
*/
|
|
787
|
+
PieChart.SegmentLabelDisplayOption =
|
|
788
|
+
{
|
|
789
|
+
NONE: 'none',
|
|
790
|
+
INNER: 'inner',
|
|
791
|
+
OUTER: 'outer'
|
|
792
|
+
};
|
|
793
|
+
|
|
794
|
+
/**
|
|
795
|
+
* SegmentLabelContentOption
|
|
796
|
+
* @readonly
|
|
797
|
+
* @enum {string}
|
|
798
|
+
*/
|
|
799
|
+
PieChart.SegmentLabelContentOption =
|
|
800
|
+
{
|
|
801
|
+
VALUE: 'value',
|
|
802
|
+
LABEL: 'label',
|
|
803
|
+
LABEL_VALUE: 'label_value'
|
|
804
|
+
};
|
|
805
|
+
|
|
806
|
+
|
|
807
|
+
// Preserve HTMLElement prototype and extend it with $base.methods
|
|
808
|
+
Object.assign(PieChart.prototype, Object.fromEntries(Object.entries($base.methods).filter(([key]) => !['render', 'postRender', 'destroy', 'getCssClass'].includes(key))));
|
|
809
|
+
|
|
810
|
+
// Restore the constructor reference
|
|
811
|
+
PieChart.prototype.constructor = PieChart;
|
|
812
|
+
componyx.UI.PieChart = PieChart;
|
|
813
|
+
|
|
814
|
+
// Define the custom element
|
|
815
|
+
customElements.define(`${componyx.UI.tagPrefix}${PieChart.name.replace(/([A-Z])/g, '-$1').toLowerCase().replace(/^-/, '')}`, PieChart); // cui-pie-chart
|
|
816
|
+
})();
|
|
817
|
+
|
|
818
|
+
const PieChart = componyx.UI.PieChart;
|
|
819
|
+
|
|
820
|
+
export { PieChart };
|