evui 3.3.36 → 3.3.39

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.
Files changed (141) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +40 -40
  3. package/dist/evui.common.js +1907 -1832
  4. package/dist/evui.common.js.map +1 -1
  5. package/dist/evui.umd.js +1907 -1832
  6. package/dist/evui.umd.js.map +1 -1
  7. package/dist/evui.umd.min.js +1 -1
  8. package/dist/evui.umd.min.js.map +1 -1
  9. package/dist/img/{EVUI.7f3588fb.svg → EVUI.b82ee81a.svg} +292 -292
  10. package/dist/img/{icon_mysql.7ea26d5d.svg → icon_mysql.1085fdc9.svg} +78 -78
  11. package/dist/img/{icon_oracle.9009b108.svg → icon_oracle.0572d3ee.svg} +13 -13
  12. package/dist/img/{icon_postgresql.f8fffba9.svg → icon_postgresql.ee12bde8.svg} +58 -58
  13. package/package.json +61 -61
  14. package/src/common/emitter.js +20 -20
  15. package/src/common/utils.debounce.js +223 -223
  16. package/src/common/utils.js +134 -134
  17. package/src/common/utils.table.js +78 -78
  18. package/src/common/utils.throttle.js +83 -83
  19. package/src/common/utils.tree.js +18 -18
  20. package/src/components/button/Button.vue +198 -198
  21. package/src/components/button/index.js +7 -7
  22. package/src/components/buttonGroup/ButtonGroup.vue +11 -11
  23. package/src/components/buttonGroup/index.js +7 -7
  24. package/src/components/calendar/Calendar.vue +661 -661
  25. package/src/components/calendar/index.js +7 -7
  26. package/src/components/calendar/uses.js +1272 -1272
  27. package/src/components/chart/Chart.vue +189 -192
  28. package/src/components/chart/chart.core.js +870 -870
  29. package/src/components/chart/element/element.bar.js +524 -524
  30. package/src/components/chart/element/element.bar.time.js +156 -156
  31. package/src/components/chart/element/element.heatmap.js +533 -533
  32. package/src/components/chart/element/element.line.js +339 -339
  33. package/src/components/chart/element/element.pie.js +197 -197
  34. package/src/components/chart/element/element.scatter.js +184 -184
  35. package/src/components/chart/element/element.tip.js +550 -542
  36. package/src/components/chart/helpers/helpers.canvas.js +265 -265
  37. package/src/components/chart/helpers/helpers.constant.js +206 -206
  38. package/src/components/chart/helpers/helpers.util.js +346 -338
  39. package/src/components/chart/index.js +9 -9
  40. package/src/components/chart/model/index.js +4 -4
  41. package/src/components/chart/model/model.series.js +93 -93
  42. package/src/components/chart/model/model.store.js +977 -967
  43. package/src/components/chart/plugins/plugins.interaction.js +769 -769
  44. package/src/components/chart/plugins/plugins.legend.gradient.js +602 -602
  45. package/src/components/chart/plugins/plugins.legend.js +1155 -1151
  46. package/src/components/chart/plugins/plugins.pie.js +254 -254
  47. package/src/components/chart/plugins/plugins.title.js +56 -56
  48. package/src/components/chart/plugins/plugins.tooltip.js +692 -692
  49. package/src/components/chart/scale/scale.js +848 -848
  50. package/src/components/chart/scale/scale.linear.js +38 -38
  51. package/src/components/chart/scale/scale.logarithmic.js +128 -128
  52. package/src/components/chart/scale/scale.step.js +336 -336
  53. package/src/components/chart/scale/scale.time.category.js +277 -277
  54. package/src/components/chart/scale/scale.time.js +48 -48
  55. package/src/components/chart/style/chart.scss +312 -312
  56. package/src/components/chart/uses.js +264 -252
  57. package/src/components/checkbox/Checkbox.vue +200 -200
  58. package/src/components/checkbox/index.js +7 -7
  59. package/src/components/checkboxGroup/CheckboxGroup.vue +44 -44
  60. package/src/components/checkboxGroup/index.js +7 -7
  61. package/src/components/contextMenu/ContextMenu.vue +80 -80
  62. package/src/components/contextMenu/MenuList.vue +149 -149
  63. package/src/components/contextMenu/index.js +7 -7
  64. package/src/components/contextMenu/uses.js +203 -203
  65. package/src/components/datePicker/DatePicker.vue +437 -437
  66. package/src/components/datePicker/index.js +7 -7
  67. package/src/components/datePicker/uses.js +419 -419
  68. package/src/components/grid/Grid.vue +827 -827
  69. package/src/components/grid/grid.filter.window.vue +493 -493
  70. package/src/components/grid/grid.pagination.vue +75 -75
  71. package/src/components/grid/grid.summary.vue +265 -265
  72. package/src/components/grid/grid.toolbar.vue +26 -26
  73. package/src/components/grid/index.js +11 -11
  74. package/src/components/grid/style/grid.scss +263 -263
  75. package/src/components/grid/uses.js +1002 -1007
  76. package/src/components/icon/Icon.vue +49 -49
  77. package/src/components/icon/index.js +8 -8
  78. package/src/components/inputNumber/InputNumber.vue +212 -212
  79. package/src/components/inputNumber/index.js +7 -7
  80. package/src/components/inputNumber/uses.js +217 -217
  81. package/src/components/loading/Loading.vue +125 -125
  82. package/src/components/loading/index.js +7 -7
  83. package/src/components/menu/Menu.vue +68 -68
  84. package/src/components/menu/MenuItem.vue +187 -187
  85. package/src/components/menu/index.js +7 -7
  86. package/src/components/message/Message.vue +223 -223
  87. package/src/components/message/index.js +31 -31
  88. package/src/components/messageBox/MessageBox.vue +358 -358
  89. package/src/components/messageBox/index.js +22 -22
  90. package/src/components/notification/Notification.vue +316 -316
  91. package/src/components/notification/index.js +49 -49
  92. package/src/components/pagination/Pagination.vue +271 -271
  93. package/src/components/pagination/index.js +7 -7
  94. package/src/components/pagination/pageButton.vue +30 -30
  95. package/src/components/progress/Progress.vue +139 -139
  96. package/src/components/progress/index.js +7 -7
  97. package/src/components/radio/Radio.vue +159 -159
  98. package/src/components/radio/index.js +7 -7
  99. package/src/components/radioGroup/RadioGroup.vue +41 -41
  100. package/src/components/radioGroup/index.js +7 -7
  101. package/src/components/scheduler/Scheduler.vue +149 -149
  102. package/src/components/scheduler/index.js +7 -7
  103. package/src/components/scheduler/uses.js +183 -183
  104. package/src/components/select/Select.vue +440 -440
  105. package/src/components/select/index.js +7 -7
  106. package/src/components/select/uses.js +270 -270
  107. package/src/components/slider/Slider.vue +505 -505
  108. package/src/components/slider/index.js +7 -7
  109. package/src/components/slider/uses.js +390 -390
  110. package/src/components/tabPanel/TabPanel.vue +74 -74
  111. package/src/components/tabPanel/index.js +7 -7
  112. package/src/components/tabs/Tabs.vue +517 -517
  113. package/src/components/tabs/index.js +7 -7
  114. package/src/components/textField/TextField.vue +375 -375
  115. package/src/components/textField/index.js +7 -7
  116. package/src/components/timePicker/TimePicker.vue +352 -352
  117. package/src/components/timePicker/index.js +7 -7
  118. package/src/components/toggle/Toggle.vue +115 -115
  119. package/src/components/toggle/index.js +7 -7
  120. package/src/components/tree/Tree.vue +313 -313
  121. package/src/components/tree/TreeNode.vue +293 -293
  122. package/src/components/tree/index.js +7 -7
  123. package/src/components/treeGrid/TreeGrid.vue +758 -758
  124. package/src/components/treeGrid/TreeGridNode.vue +275 -275
  125. package/src/components/treeGrid/index.js +9 -9
  126. package/src/components/treeGrid/style/treeGrid.scss +261 -261
  127. package/src/components/treeGrid/treeGrid.toolbar.vue +26 -26
  128. package/src/components/treeGrid/uses.js +867 -867
  129. package/src/components/window/Window.vue +329 -329
  130. package/src/components/window/index.js +7 -7
  131. package/src/components/window/uses.js +899 -899
  132. package/src/directives/clickoutside.js +90 -90
  133. package/src/main.js +116 -116
  134. package/src/style/components/input.scss +108 -108
  135. package/src/style/functions.scss +3 -3
  136. package/src/style/index.scss +6 -6
  137. package/src/style/lib/fonts/EVUI.svg +292 -292
  138. package/src/style/lib/icon.css +888 -888
  139. package/src/style/mixins.scss +94 -94
  140. package/src/style/themes.scss +67 -67
  141. package/src/style/variables.scss +22 -22
@@ -1,542 +1,550 @@
1
- import { numberWithComma } from '@/common/utils';
2
- import dayjs from 'dayjs';
3
- import Canvas from '../helpers/helpers.canvas';
4
-
5
- const modules = {
6
- /**
7
- * Draw TextTip with tip's locationInfo
8
- * @param {object} [tipLocationInfo=undefined] tip location information
9
- *
10
- * @returns {undefined}
11
- */
12
- drawTips(tipLocationInfo) {
13
- const opt = this.options;
14
- const isHorizontal = !!opt.horizontal;
15
- const maxTipOpt = opt.maxTip;
16
- const selTipOpt = opt.selectItem;
17
- const labelTipOpt = opt.selectLabel;
18
- let maxArgs;
19
- let isExistSelectedLabel;
20
-
21
- if (labelTipOpt.use && labelTipOpt.showTip) {
22
- isExistSelectedLabel = this.drawLabelTip();
23
- }
24
-
25
- if (selTipOpt.use && tipLocationInfo && !isExistSelectedLabel) {
26
- const seriesInfo = this.seriesList[tipLocationInfo?.sId];
27
-
28
- if (!seriesInfo?.show) {
29
- return;
30
- }
31
-
32
- const selArgs = this.calculateTipInfo(
33
- seriesInfo,
34
- 'sel',
35
- tipLocationInfo,
36
- );
37
-
38
- if (selArgs) {
39
- let isSamePos = false;
40
-
41
- if (maxTipOpt.use && maxArgs?.dp === selArgs.dp) {
42
- isSamePos = true;
43
- }
44
-
45
- if (selTipOpt.showTextTip || selTipOpt.showTip) {
46
- if (selTipOpt.tipText === 'label') {
47
- const axisOpt = isHorizontal ? opt.axesY[0] : opt.axesX[0];
48
- const label = selArgs.label;
49
- selArgs.text = axisOpt.type === 'time' ? dayjs(label).format(axisOpt.timeFormat) : label;
50
- } else {
51
- selArgs.text = numberWithComma(selArgs.value);
52
- }
53
-
54
- this.drawTextTip({ opt: selTipOpt, tipType: 'sel', seriesOpt: seriesInfo, isSamePos, ...selArgs });
55
- }
56
-
57
- if (selTipOpt.showIndicator) {
58
- this.drawFixedIndicator({ opt: selTipOpt, seriesOpt: seriesInfo, ...selArgs });
59
- }
60
- }
61
-
62
- if (tipLocationInfo && tipLocationInfo?.label && tipLocationInfo?.label === 0) {
63
- this.lastHitInfo = tipLocationInfo;
64
- }
65
- }
66
-
67
- if (maxTipOpt.use && !isExistSelectedLabel) {
68
- const maxSID = this.minMax[isHorizontal ? 'x' : 'y'][0].maxSID;
69
- const seriesInfo = this.seriesList[maxSID];
70
- maxArgs = this.calculateTipInfo(seriesInfo, 'max', null);
71
-
72
- if (maxTipOpt.use && maxArgs) {
73
- maxArgs.text = numberWithComma(maxArgs.value);
74
- this.drawTextTip({ opt: maxTipOpt, tipType: 'max', seriesOpt: seriesInfo, ...maxArgs });
75
-
76
- if (maxTipOpt.showIndicator) {
77
- this.drawFixedIndicator({ opt: maxTipOpt, seriesOpt: seriesInfo, ...maxArgs });
78
- }
79
- }
80
- }
81
- },
82
-
83
- /**
84
- * Calculate tip size and contents
85
- * @param {object} series series information (max series or selected series)
86
- * @param {string} tipType tip type
87
- * [sel = user select series, label = user select label, max = max value]
88
- * @param {object} hitInfo mouse hit information
89
- *
90
- * @returns {object} size and tip contents
91
- */
92
- calculateTipInfo(series, tipType, hitInfo) {
93
- if (!series) {
94
- return false;
95
- }
96
-
97
- const isHorizontal = !!this.options.horizontal;
98
- const lastTip = this.lastTip;
99
- const chartRect = this.chartRect;
100
- const labelOffset = this.labelOffset;
101
- const graphPos = {
102
- x1: chartRect.x1 + labelOffset.left,
103
- x2: chartRect.x2 - labelOffset.right,
104
- y1: chartRect.y1 + labelOffset.top,
105
- y2: chartRect.y2 - labelOffset.bottom,
106
- };
107
-
108
- const yArea = chartRect.chartHeight - (labelOffset.top + labelOffset.bottom);
109
- const xArea = chartRect.chartWidth - (labelOffset.left + labelOffset.right);
110
-
111
- const graphX = this.axesSteps.x[series.xAxisIndex];
112
- const graphY = this.axesSteps.y[series.yAxisIndex];
113
-
114
- const xsp = graphPos.x1;
115
- const xep = graphPos.x2;
116
- const ysp = graphPos.y2;
117
-
118
- const { type, size } = series;
119
- const { maxDomain, maxDomainIndex } = series.minMax;
120
-
121
- if (maxDomain === null || maxDomainIndex < 0) {
122
- return false;
123
- }
124
-
125
- let ldata = type === 'bar' ? maxDomainIndex : maxDomain;
126
-
127
- if (tipType === 'sel') {
128
- if (hitInfo && hitInfo.label !== null) {
129
- lastTip.pos = type === 'bar' ? hitInfo.maxIndex : hitInfo.label;
130
- ldata = lastTip.pos;
131
- } else if (lastTip.pos !== null) {
132
- ldata = lastTip.pos;
133
- }
134
- }
135
-
136
- let value = isHorizontal ? series.minMax.maxX : series.minMax.maxY;
137
- let label;
138
- if (tipType === 'sel') {
139
- if (hitInfo && hitInfo.value !== null) {
140
- value = hitInfo.useStack ? hitInfo.acc : hitInfo.value;
141
- label = hitInfo.label;
142
- lastTip.value = value;
143
- lastTip.label = label;
144
- } else if (lastTip.value !== null) {
145
- value = lastTip.value;
146
- label = lastTip.label;
147
- } else if (lastTip.pos !== null) {
148
- const item = type === 'bar'
149
- ? this.getItemByLabelIndex(lastTip.pos) : this.getItemByLabel(lastTip.pos);
150
-
151
- value = item.useStack ? item.acc : item.value;
152
- label = item.label;
153
- lastTip.value = value;
154
- lastTip.label = label;
155
- }
156
- }
157
-
158
- let cp;
159
- let halfBarSize;
160
- let dp;
161
-
162
- if (type === 'bar') {
163
- if (isHorizontal) {
164
- halfBarSize = Math.round(size.h / 2);
165
- cp = ysp - (size.cat * ldata) - size.cPad;
166
- dp = (cp - ((size.bar * size.ix) - (size.h + size.bPad))) - halfBarSize;
167
- } else {
168
- halfBarSize = Math.round(size.w / 2);
169
- cp = xsp + (size.cat * ldata) + size.cPad;
170
- dp = cp + ((size.bar * size.ix) - (size.w + size.bPad)) + halfBarSize;
171
- }
172
- } else if (type === 'line') {
173
- dp = Canvas.calculateX(
174
- ldata,
175
- graphX.graphMin,
176
- graphX.graphMax,
177
- xArea - size.comboOffset,
178
- xsp + (size.comboOffset / 2),
179
- );
180
- } else if (type === 'scatter') {
181
- dp = Canvas.calculateX(
182
- ldata,
183
- graphX.graphMin,
184
- graphX.graphMax,
185
- xArea,
186
- xsp,
187
- );
188
- }
189
-
190
- const sizeObj = { xArea, yArea, graphX, graphY, xsp, xep, ysp };
191
- const dataObj = { dp, value, label, type };
192
-
193
- return { ...sizeObj, ...dataObj };
194
- },
195
- drawFixedIndicator(param) {
196
- const isHorizontal = !!this.options.horizontal;
197
- const ctx = this.bufferCtx;
198
- const { graphX, graphY, xArea, yArea, xsp, ysp, dp, type, value, opt, seriesOpt } = param;
199
- let offset = 0;
200
-
201
- if (type === 'line') {
202
- offset += 3;
203
- } else if (type === 'scatter') {
204
- offset += seriesOpt?.pointSize ?? 0;
205
- }
206
-
207
- let gp;
208
-
209
- if (opt.fixedPosTop) {
210
- if (isHorizontal) {
211
- gp = Canvas.calculateX(graphX.graphMax, graphX.graphMin, graphX.graphMax, xArea, xsp);
212
- } else {
213
- gp = Canvas.calculateY(graphY.graphMax, graphY.graphMin, graphY.graphMax, yArea, ysp);
214
- gp -= offset;
215
- }
216
- } else if (isHorizontal) {
217
- gp = Canvas.calculateX(value, graphX.graphMin, graphX.graphMax, xArea, xsp);
218
- } else {
219
- gp = Canvas.calculateY(value, graphY.graphMin, graphY.graphMax, yArea, ysp);
220
- gp -= offset;
221
- }
222
-
223
- if (dp === null) {
224
- return;
225
- }
226
-
227
- ctx.beginPath();
228
- ctx.save();
229
- ctx.strokeStyle = opt.indicatorColor;
230
- ctx.lineWidth = 2;
231
-
232
- if (isHorizontal) {
233
- ctx.moveTo(xsp, dp);
234
- ctx.lineTo(gp, dp);
235
- } else {
236
- ctx.moveTo(dp, ysp);
237
- ctx.lineTo(dp, gp);
238
- }
239
-
240
- ctx.stroke();
241
- ctx.restore();
242
- ctx.closePath();
243
- },
244
-
245
- /**
246
- * Draw Selected Label Tip
247
- * @returns {boolean} Whether drew at least one tip
248
- */
249
- drawLabelTip() {
250
- const opt = this.options;
251
- const isHorizontal = !!opt.horizontal;
252
- const labelTipOpt = opt.selectLabel;
253
- const { dataIndex, data, label } = this.defaultSelectInfo;
254
- let drawTip = false;
255
-
256
- if (dataIndex.length) {
257
- drawTip = true;
258
-
259
- const chartRect = this.chartRect;
260
- const labelOffset = this.labelOffset;
261
- const aPos = {
262
- x1: chartRect.x1 + labelOffset.left,
263
- x2: chartRect.x2 - labelOffset.right,
264
- y1: chartRect.y1 + labelOffset.top,
265
- y2: chartRect.y2 - labelOffset.bottom,
266
- };
267
- const labelAxes = isHorizontal ? this.axesY[0] : this.axesX[0];
268
- const valueAxes = isHorizontal ? this.axesX[0] : this.axesY[0];
269
- const valueAxesRange = isHorizontal ? this.axesRange.x[0] : this.axesRange.y[0];
270
- const valuePositionCalcFunction = isHorizontal ? Canvas.calculateX : Canvas.calculateY;
271
- const labelPositionCalcFunction = isHorizontal ? Canvas.calculateY : Canvas.calculateX;
272
-
273
- const chartWidth = chartRect.chartWidth - (labelOffset.left + labelOffset.right);
274
- const chartHeight = chartRect.chartHeight - (labelOffset.top + labelOffset.bottom);
275
- const valueSpace = isHorizontal ? chartWidth : chartHeight;
276
- const valueStartPoint = aPos[valueAxes.units.rectStart];
277
- let offset = this.options.type === 'bar' ? 4 : 6;
278
- offset *= isHorizontal ? 1 : -1;
279
-
280
- const seriesList = Object.keys(this.seriesList ?? {});
281
- const visibleSeries = seriesList.filter(sId => this.seriesList[sId].show);
282
- const isExistGrp = seriesList.some(sId => this.seriesList[sId].isExistGrp);
283
- const groups = this.data.groups?.[0] ?? [];
284
-
285
- let gp;
286
- let dp;
287
- let value;
288
- let labelStartPoint;
289
- let labelEndPoint;
290
- let labelGap;
291
- let graphX;
292
- let lineSeries;
293
- let sizeObj;
294
-
295
- if (labelAxes.labels) {
296
- labelStartPoint = aPos[labelAxes.units.rectStart];
297
- labelEndPoint = aPos[labelAxes.units.rectEnd];
298
- labelGap = (labelEndPoint - labelStartPoint) / labelAxes.labels.length;
299
- } else {
300
- graphX = this.axesSteps.x[0];
301
- lineSeries = seriesList.find(sId => this.seriesList[sId]?.type === 'line');
302
- sizeObj = this.seriesList[lineSeries].size;
303
- }
304
-
305
- data.forEach((selectedData, i) => {
306
- if (labelTipOpt.fixedPosTop) {
307
- value = valueAxesRange.max;
308
- } else if (isExistGrp) {
309
- const sumValue = visibleSeries.reduce((ac, sId) => (
310
- groups.includes(sId) ? ac + (selectedData[sId]?.value ?? selectedData[sId]) : ac), 0);
311
- const nonGroupValues = visibleSeries
312
- .filter(sId => !groups.includes(sId))
313
- .map(sId => selectedData[sId]?.value ?? selectedData[sId]);
314
- value = Math.max(...nonGroupValues, sumValue);
315
- } else if (visibleSeries.length) {
316
- const visibleValue = visibleSeries
317
- .map(sId => selectedData[sId]?.value ?? selectedData[sId]);
318
- value = Math.max(...visibleValue);
319
- } else {
320
- value = valueAxesRange.max;
321
- }
322
-
323
- if (labelAxes.labels) {
324
- const labelCenter = Math.round(labelStartPoint + (labelGap * dataIndex[i]));
325
-
326
- dp = labelCenter + (labelGap / 2);
327
- } else {
328
- dp = labelPositionCalcFunction(
329
- label[i],
330
- graphX.graphMin,
331
- graphX.graphMax,
332
- chartWidth - sizeObj.comboOffset,
333
- aPos.x1 + (sizeObj.comboOffset / 2),
334
- );
335
- }
336
- gp = valuePositionCalcFunction(
337
- value,
338
- valueAxesRange.min,
339
- valueAxesRange.max,
340
- valueSpace,
341
- valueStartPoint);
342
- gp += offset;
343
-
344
- this.showTip({
345
- context: this.bufferCtx,
346
- x: isHorizontal ? gp : dp,
347
- y: isHorizontal ? dp : gp,
348
- opt: labelTipOpt,
349
- isSamePos: false,
350
- });
351
- });
352
- }
353
-
354
- return drawTip;
355
- },
356
- /**
357
- * Calculate x, y position to draw text tip
358
- * @param {object} param object for drawing text tip
359
- *
360
- * @returns {undefined}
361
- */
362
- drawTextTip(param) {
363
- const isHorizontal = !!this.options.horizontal;
364
- const ctx = this.bufferCtx;
365
- const { graphX, graphY, xArea, yArea, xsp, xep, ysp } = param;
366
- const { dp, value, text, opt, type, tipType, isSamePos, seriesOpt } = param;
367
-
368
- const arrowSize = 4;
369
- const maxTipHeight = 20;
370
- const borderRadius = 4;
371
-
372
- let offset = 1;
373
- if (type === 'line') {
374
- offset += 6;
375
- } else if (type === 'scatter') {
376
- offset += seriesOpt?.pointSize;
377
- } else if (type === 'bar') {
378
- offset += 4;
379
- }
380
-
381
- let gp;
382
- let tdp = dp;
383
-
384
- if (opt.fixedPosTop) {
385
- if (isHorizontal) {
386
- gp = Canvas.calculateX(graphX.graphMax, graphX.graphMin, graphX.graphMax, xArea, xsp);
387
- gp += offset;
388
- } else {
389
- gp = Canvas.calculateY(graphY.graphMax, graphY.graphMin, graphY.graphMax, yArea, ysp);
390
- gp -= offset;
391
- }
392
- } else if (isHorizontal) {
393
- gp = Canvas.calculateX(value, graphX.graphMin, graphX.graphMax, xArea, xsp);
394
- gp += offset;
395
- } else {
396
- gp = Canvas.calculateY(value, graphY.graphMin, graphY.graphMax, yArea, ysp);
397
- gp -= offset;
398
- }
399
-
400
- let maxTipType = 'center';
401
-
402
- ctx.save();
403
- ctx.font = 'normal normal bold 14px Roboto';
404
- const maxTipWidth = Math.round(Math.max(ctx.measureText(text).width + 12, 40));
405
-
406
- if (!isHorizontal) {
407
- if (dp + (maxTipWidth / 2) > xep - 10) {
408
- maxTipType = 'right';
409
- tdp -= (maxTipWidth / 2) - (arrowSize * 2);
410
- } else if (dp - (maxTipWidth / 2) < xsp + 10) {
411
- maxTipType = 'left';
412
- tdp += (maxTipWidth / 2) - (arrowSize * 2);
413
- }
414
- }
415
-
416
- ctx.restore();
417
-
418
- if (opt.showTextTip || tipType === 'max') {
419
- this.showTextTip({
420
- context: ctx,
421
- type: maxTipType,
422
- width: maxTipWidth,
423
- height: maxTipHeight,
424
- x: isHorizontal ? gp + (maxTipWidth / 2) : tdp,
425
- y: isHorizontal ? tdp + (maxTipHeight / 2) : gp,
426
- opt,
427
- arrowSize,
428
- borderRadius,
429
- text,
430
- });
431
- }
432
-
433
- if (opt.showTip && tipType === 'sel') {
434
- this.showTip({
435
- context: ctx,
436
- x: isHorizontal ? gp : dp,
437
- y: isHorizontal ? dp : gp,
438
- opt,
439
- isSamePos,
440
- });
441
- }
442
- },
443
-
444
- /**
445
- * Draw text tip
446
- * @param {object} param object for drawing text tip
447
- *
448
- * @returns {undefined}
449
- */
450
- showTextTip(param) {
451
- const isHorizontal = !!this.options.horizontal;
452
- const { type, width, height, x, y, arrowSize, borderRadius, text, opt } = param;
453
- const ctx = param.context;
454
-
455
- const sx = x - (width / 2);
456
- const ex = x + (width / 2);
457
- const sy = y - height;
458
- const ey = y;
459
-
460
- ctx.save();
461
- ctx.font = 'normal normal bold 14px Roboto';
462
-
463
- ctx.fillStyle = opt.tipBackground;
464
- ctx.shadowBlur = 0;
465
-
466
- ctx.beginPath();
467
- ctx.moveTo(sx + borderRadius, sy);
468
- ctx.quadraticCurveTo(sx, sy, sx, sy + borderRadius);
469
-
470
- if (isHorizontal) {
471
- ctx.lineTo(sx, sy + borderRadius + (arrowSize / 2));
472
- ctx.lineTo(sx - arrowSize, ey - (height / 2));
473
- ctx.lineTo(sx, ey - borderRadius - (arrowSize / 2));
474
- }
475
-
476
- ctx.lineTo(sx, ey - borderRadius);
477
- ctx.quadraticCurveTo(sx, ey, sx + borderRadius, ey);
478
-
479
- if (!isHorizontal) {
480
- if (type === 'left') {
481
- ctx.lineTo(sx + borderRadius + arrowSize, ey + arrowSize);
482
- ctx.lineTo(sx + borderRadius + (arrowSize * 2), ey);
483
- } else if (type === 'right') {
484
- ctx.lineTo(ex - (arrowSize * 2) - borderRadius, ey);
485
- ctx.lineTo(ex - arrowSize - borderRadius, ey + arrowSize);
486
- } else {
487
- ctx.lineTo(x - arrowSize, ey);
488
- ctx.lineTo(x, ey + arrowSize);
489
- ctx.lineTo(x + arrowSize, ey);
490
- }
491
- }
492
-
493
- ctx.lineTo(ex - borderRadius, ey);
494
- ctx.quadraticCurveTo(ex, ey, ex, ey - borderRadius);
495
- ctx.lineTo(ex, sy + borderRadius);
496
- ctx.quadraticCurveTo(ex, sy, ex - borderRadius, sy);
497
- ctx.lineTo(sx + borderRadius, sy);
498
- ctx.closePath();
499
- ctx.fill();
500
- ctx.restore();
501
- ctx.save();
502
- ctx.font = 'normal normal bold 14px Roboto';
503
- ctx.fillStyle = opt.tipTextColor;
504
- ctx.textBaseline = 'middle';
505
- ctx.textAlign = 'center';
506
- ctx.fillText(`${text}`, x, sy + (height / 2));
507
- ctx.restore();
508
- },
509
-
510
- /**
511
- * Draw arrow tip
512
- * @param {object} param object for drawing arrow tip
513
- *
514
- * @returns {undefined}
515
- */
516
- showTip(param) {
517
- const isHorizontal = !!this.options.horizontal;
518
- const { x, y, opt, isSamePos } = param;
519
- const ctx = param.context;
520
- const offset = isSamePos ? 24 : 0;
521
- const cy = y - offset;
522
- ctx.save();
523
-
524
- ctx.fillStyle = opt.tipBackground;
525
- ctx.beginPath();
526
- ctx.moveTo(x, cy);
527
- if (isHorizontal) {
528
- ctx.lineTo(x + 6, cy - 6);
529
- ctx.lineTo(x + 6, cy + 6);
530
- } else {
531
- ctx.lineTo(x + 6, cy - 6);
532
- ctx.lineTo(x - 6, cy - 6);
533
- }
534
- ctx.lineTo(x, cy);
535
- ctx.closePath();
536
- ctx.fill();
537
-
538
- ctx.restore();
539
- },
540
- };
541
-
542
- export default modules;
1
+ import { numberWithComma } from '@/common/utils';
2
+ import dayjs from 'dayjs';
3
+ import Canvas from '../helpers/helpers.canvas';
4
+
5
+ const modules = {
6
+ /**
7
+ * Draw TextTip with tip's locationInfo
8
+ * @param {object} [tipLocationInfo=undefined] tip location information
9
+ *
10
+ * @returns {undefined}
11
+ */
12
+ drawTips(tipLocationInfo) {
13
+ const opt = this.options;
14
+ const isHorizontal = !!opt.horizontal;
15
+ const maxTipOpt = opt.maxTip;
16
+ const selTipOpt = opt.selectItem;
17
+ const labelTipOpt = opt.selectLabel;
18
+ let maxArgs;
19
+ let isExistSelectedLabel;
20
+
21
+ if (labelTipOpt.use && labelTipOpt.showTip) {
22
+ isExistSelectedLabel = this.drawLabelTip();
23
+ }
24
+
25
+ if (selTipOpt.use && tipLocationInfo && !isExistSelectedLabel) {
26
+ const seriesInfo = this.seriesList[tipLocationInfo?.sId];
27
+
28
+ if (!seriesInfo?.show) {
29
+ return;
30
+ }
31
+
32
+ const selArgs = this.calculateTipInfo(
33
+ seriesInfo,
34
+ 'sel',
35
+ tipLocationInfo,
36
+ );
37
+
38
+ if (selArgs) {
39
+ let isSamePos = false;
40
+
41
+ if (maxTipOpt.use && maxArgs?.dp === selArgs.dp) {
42
+ isSamePos = true;
43
+ }
44
+
45
+ if (selTipOpt.showTextTip || selTipOpt.showTip) {
46
+ if (selTipOpt.tipText === 'label') {
47
+ const axisOpt = isHorizontal ? opt.axesY[0] : opt.axesX[0];
48
+ const label = selArgs.label;
49
+ selArgs.text = axisOpt.type === 'time' ? dayjs(label).format(axisOpt.timeFormat) : label;
50
+ } else {
51
+ selArgs.text = numberWithComma(selArgs.value);
52
+ }
53
+
54
+ this.drawTextTip({ opt: selTipOpt, tipType: 'sel', seriesOpt: seriesInfo, isSamePos, ...selArgs });
55
+ }
56
+
57
+ if (selTipOpt.showIndicator) {
58
+ this.drawFixedIndicator({ opt: selTipOpt, seriesOpt: seriesInfo, ...selArgs });
59
+ }
60
+ }
61
+
62
+ if (tipLocationInfo && tipLocationInfo?.label && tipLocationInfo?.label === 0) {
63
+ this.lastHitInfo = tipLocationInfo;
64
+ }
65
+ }
66
+
67
+ if (maxTipOpt.use && !isExistSelectedLabel) {
68
+ const maxSID = this.minMax[isHorizontal ? 'x' : 'y'][0].maxSID;
69
+ const seriesInfo = this.seriesList[maxSID];
70
+ maxArgs = this.calculateTipInfo(seriesInfo, 'max', null);
71
+
72
+ if (maxTipOpt.use && maxArgs) {
73
+ maxArgs.text = numberWithComma(maxArgs.value);
74
+ this.drawTextTip({ opt: maxTipOpt, tipType: 'max', seriesOpt: seriesInfo, ...maxArgs });
75
+
76
+ if (maxTipOpt.showIndicator) {
77
+ this.drawFixedIndicator({ opt: maxTipOpt, seriesOpt: seriesInfo, ...maxArgs });
78
+ }
79
+ }
80
+ }
81
+ },
82
+
83
+ /**
84
+ * Calculate tip size and contents
85
+ * @param {object} series series information (max series or selected series)
86
+ * @param {string} tipType tip type
87
+ * [sel = user select series, label = user select label, max = max value]
88
+ * @param {object} hitInfo mouse hit information
89
+ *
90
+ * @returns {object} size and tip contents
91
+ */
92
+ calculateTipInfo(series, tipType, hitInfo) {
93
+ if (!series) {
94
+ return false;
95
+ }
96
+
97
+ const isHorizontal = !!this.options.horizontal;
98
+ const lastTip = this.lastTip;
99
+ const chartRect = this.chartRect;
100
+ const labelOffset = this.labelOffset;
101
+ const graphPos = {
102
+ x1: chartRect.x1 + labelOffset.left,
103
+ x2: chartRect.x2 - labelOffset.right,
104
+ y1: chartRect.y1 + labelOffset.top,
105
+ y2: chartRect.y2 - labelOffset.bottom,
106
+ };
107
+
108
+ const yArea = chartRect.chartHeight - (labelOffset.top + labelOffset.bottom);
109
+ const xArea = chartRect.chartWidth - (labelOffset.left + labelOffset.right);
110
+
111
+ const graphX = this.axesSteps.x[series.xAxisIndex];
112
+ const graphY = this.axesSteps.y[series.yAxisIndex];
113
+
114
+ const xsp = graphPos.x1;
115
+ const xep = graphPos.x2;
116
+ const ysp = graphPos.y2;
117
+
118
+ const { type, size } = series;
119
+ const { maxDomain, maxDomainIndex } = series.minMax;
120
+
121
+ if (maxDomain === null || maxDomainIndex < 0) {
122
+ return false;
123
+ }
124
+
125
+ let ldata = type === 'bar' ? maxDomainIndex : maxDomain;
126
+
127
+ if (tipType === 'sel') {
128
+ if (hitInfo && hitInfo.label !== null) {
129
+ lastTip.pos = type === 'bar' ? hitInfo.maxIndex : hitInfo.label;
130
+ ldata = lastTip.pos;
131
+ } else if (lastTip.pos !== null) {
132
+ ldata = lastTip.pos;
133
+ }
134
+ }
135
+
136
+ let value = isHorizontal ? series.minMax.maxX : series.minMax.maxY;
137
+ let label;
138
+ if (tipType === 'sel') {
139
+ if (hitInfo && hitInfo.value !== null) {
140
+ value = hitInfo.useStack ? hitInfo.acc : hitInfo.value;
141
+ label = hitInfo.label;
142
+ lastTip.value = value;
143
+ lastTip.label = label;
144
+ } else if (lastTip.value !== null) {
145
+ value = lastTip.value;
146
+ label = lastTip.label;
147
+ } else if (lastTip.pos !== null) {
148
+ const item = type === 'bar'
149
+ ? this.getItemByLabelIndex(lastTip.pos) : this.getItemByLabel(lastTip.pos);
150
+
151
+ value = item.useStack ? item.acc : item.value;
152
+ label = item.label;
153
+ lastTip.value = value;
154
+ lastTip.label = label;
155
+ }
156
+ }
157
+
158
+ let cp;
159
+ let halfBarSize;
160
+ let dp;
161
+
162
+ if (type === 'bar') {
163
+ if (isHorizontal) {
164
+ halfBarSize = Math.round(size.h / 2);
165
+ cp = ysp - (size.cat * ldata) - size.cPad;
166
+ dp = (cp - ((size.bar * size.ix) - (size.h + size.bPad))) - halfBarSize;
167
+ } else {
168
+ halfBarSize = Math.round(size.w / 2);
169
+ cp = xsp + (size.cat * ldata) + size.cPad;
170
+ dp = cp + ((size.bar * size.ix) - (size.w + size.bPad)) + halfBarSize;
171
+ }
172
+ } else if (type === 'line') {
173
+ dp = Canvas.calculateX(
174
+ ldata,
175
+ graphX.graphMin,
176
+ graphX.graphMax,
177
+ xArea - size.comboOffset,
178
+ xsp + (size.comboOffset / 2),
179
+ );
180
+ } else if (type === 'scatter') {
181
+ dp = Canvas.calculateX(
182
+ ldata,
183
+ graphX.graphMin,
184
+ graphX.graphMax,
185
+ xArea,
186
+ xsp,
187
+ );
188
+ }
189
+
190
+ const sizeObj = { xArea, yArea, graphX, graphY, xsp, xep, ysp };
191
+ const dataObj = { dp, value, label, type };
192
+
193
+ return { ...sizeObj, ...dataObj };
194
+ },
195
+ drawFixedIndicator(param) {
196
+ const isHorizontal = !!this.options.horizontal;
197
+ const ctx = this.bufferCtx;
198
+ const { graphX, graphY, xArea, yArea, xsp, ysp, dp, type, value, opt, seriesOpt } = param;
199
+ let offset = 0;
200
+
201
+ if (type === 'line') {
202
+ offset += 3;
203
+ } else if (type === 'scatter') {
204
+ offset += seriesOpt?.pointSize ?? 0;
205
+ }
206
+
207
+ let gp;
208
+
209
+ if (opt.fixedPosTop) {
210
+ if (isHorizontal) {
211
+ gp = Canvas.calculateX(graphX.graphMax, graphX.graphMin, graphX.graphMax, xArea, xsp);
212
+ } else {
213
+ gp = Canvas.calculateY(graphY.graphMax, graphY.graphMin, graphY.graphMax, yArea, ysp);
214
+ gp -= offset;
215
+ }
216
+ } else if (isHorizontal) {
217
+ gp = Canvas.calculateX(value, graphX.graphMin, graphX.graphMax, xArea, xsp);
218
+ } else {
219
+ gp = Canvas.calculateY(value, graphY.graphMin, graphY.graphMax, yArea, ysp);
220
+ gp -= offset;
221
+ }
222
+
223
+ if (dp === null) {
224
+ return;
225
+ }
226
+
227
+ ctx.beginPath();
228
+ ctx.save();
229
+ ctx.strokeStyle = opt.indicatorColor;
230
+ ctx.lineWidth = 2;
231
+
232
+ if (isHorizontal) {
233
+ ctx.moveTo(xsp, dp);
234
+ ctx.lineTo(gp, dp);
235
+ } else {
236
+ ctx.moveTo(dp, ysp);
237
+ ctx.lineTo(dp, gp);
238
+ }
239
+
240
+ ctx.stroke();
241
+ ctx.restore();
242
+ ctx.closePath();
243
+ },
244
+
245
+ /**
246
+ * Draw Selected Label Tip
247
+ * @returns {boolean} Whether drew at least one tip
248
+ */
249
+ drawLabelTip() {
250
+ const opt = this.options;
251
+ const isHorizontal = !!opt.horizontal;
252
+ const labelTipOpt = opt.selectLabel;
253
+ const { dataIndex, data, label } = this.defaultSelectInfo;
254
+ let drawTip = false;
255
+
256
+ if (dataIndex.length) {
257
+ drawTip = true;
258
+
259
+ const chartRect = this.chartRect;
260
+ const labelOffset = this.labelOffset;
261
+ const aPos = {
262
+ x1: chartRect.x1 + labelOffset.left,
263
+ x2: chartRect.x2 - labelOffset.right,
264
+ y1: chartRect.y1 + labelOffset.top,
265
+ y2: chartRect.y2 - labelOffset.bottom,
266
+ };
267
+ const labelAxes = isHorizontal ? this.axesY[0] : this.axesX[0];
268
+ const valueAxes = isHorizontal ? this.axesX[0] : this.axesY[0];
269
+ const valueAxesRange = isHorizontal ? this.axesRange.x[0] : this.axesRange.y[0];
270
+ const valuePositionCalcFunction = isHorizontal ? Canvas.calculateX : Canvas.calculateY;
271
+ const labelPositionCalcFunction = isHorizontal ? Canvas.calculateY : Canvas.calculateX;
272
+
273
+ const chartWidth = chartRect.chartWidth - (labelOffset.left + labelOffset.right);
274
+ const chartHeight = chartRect.chartHeight - (labelOffset.top + labelOffset.bottom);
275
+ const valueSpace = isHorizontal ? chartWidth : chartHeight;
276
+ const valueStartPoint = aPos[valueAxes.units.rectStart];
277
+ let offset = this.options.type === 'bar' ? 4 : 6;
278
+ offset *= isHorizontal ? 1 : -1;
279
+
280
+ const seriesList = Object.keys(this.seriesList ?? {});
281
+ const visibleSeries = seriesList.filter(sId => this.seriesList[sId].show);
282
+ const isExistGrp = seriesList.some(sId => this.seriesList[sId].isExistGrp);
283
+ const groups = this.data.groups?.[0] ?? [];
284
+
285
+ let gp;
286
+ let dp;
287
+ let value;
288
+ let labelStartPoint;
289
+ let labelEndPoint;
290
+ let labelGap;
291
+ let graphX;
292
+ let lineSeries;
293
+ let sizeObj;
294
+
295
+ if (labelAxes.labels) {
296
+ labelStartPoint = aPos[labelAxes.units.rectStart];
297
+ labelEndPoint = aPos[labelAxes.units.rectEnd];
298
+ labelGap = (labelEndPoint - labelStartPoint) / labelAxes.labels.length;
299
+ } else {
300
+ graphX = this.axesSteps.x[0];
301
+ lineSeries = seriesList.find(sId => this.seriesList[sId]?.type === 'line');
302
+ sizeObj = this.seriesList[lineSeries].size;
303
+ }
304
+
305
+ data.forEach((selectedData, i) => {
306
+ if (labelTipOpt.fixedPosTop) {
307
+ value = valueAxesRange.max;
308
+ } else if (isExistGrp) {
309
+ const sumValue = visibleSeries.reduce((ac, sId) => (
310
+ groups.includes(sId) ? ac + (selectedData[sId]?.value ?? selectedData[sId]) : ac), 0);
311
+ const nonGroupValues = visibleSeries
312
+ .filter(sId => !groups.includes(sId))
313
+ .map(sId => selectedData[sId]?.value ?? selectedData[sId]);
314
+ value = Math.max(...nonGroupValues, sumValue);
315
+ } else if (visibleSeries.length) {
316
+ const visibleValue = visibleSeries
317
+ .map(sId => selectedData[sId]?.value ?? selectedData[sId]);
318
+ value = Math.max(...visibleValue);
319
+ } else {
320
+ value = valueAxesRange.max;
321
+ }
322
+
323
+ if (labelAxes.labels) {
324
+ const labelCenter = Math.round(labelStartPoint + (labelGap * dataIndex[i]));
325
+
326
+ dp = labelCenter + (labelGap / 2);
327
+ } else {
328
+ dp = labelPositionCalcFunction(
329
+ label[i],
330
+ graphX.graphMin,
331
+ graphX.graphMax,
332
+ chartWidth - sizeObj.comboOffset,
333
+ aPos.x1 + (sizeObj.comboOffset / 2),
334
+ );
335
+ }
336
+ gp = valuePositionCalcFunction(
337
+ value,
338
+ valueAxesRange.min,
339
+ valueAxesRange.max,
340
+ valueSpace,
341
+ valueStartPoint);
342
+ gp += offset;
343
+
344
+ this.showTip({
345
+ context: this.bufferCtx,
346
+ x: isHorizontal ? gp : dp,
347
+ y: isHorizontal ? dp : gp,
348
+ opt: labelTipOpt,
349
+ isSamePos: false,
350
+ });
351
+ });
352
+ }
353
+
354
+ return drawTip;
355
+ },
356
+ /**
357
+ * Calculate x, y position to draw text tip
358
+ * @param {object} param object for drawing text tip
359
+ *
360
+ * @returns {undefined}
361
+ */
362
+ drawTextTip(param) {
363
+ const isHorizontal = !!this.options.horizontal;
364
+ const ctx = this.bufferCtx;
365
+ const { graphX, graphY, xArea, yArea, xsp, xep, ysp } = param;
366
+ const { dp, value, text, opt, type, tipType, isSamePos, seriesOpt } = param;
367
+
368
+ const arrowSize = 4;
369
+ const borderRadius = 4;
370
+ const {
371
+ fontSize,
372
+ fontFamily,
373
+ fontWeight,
374
+ height: maxTipHeight,
375
+ } = opt.tipStyle;
376
+ const textStyle = `normal normal ${fontWeight} ${fontSize}px ${fontFamily}`;
377
+
378
+ let offset = 1;
379
+ if (type === 'line') {
380
+ offset += 6;
381
+ } else if (type === 'scatter') {
382
+ offset += seriesOpt?.pointSize;
383
+ } else if (type === 'bar') {
384
+ offset += 4;
385
+ }
386
+
387
+ let gp;
388
+ let tdp = dp;
389
+
390
+ if (opt.fixedPosTop) {
391
+ if (isHorizontal) {
392
+ gp = Canvas.calculateX(graphX.graphMax, graphX.graphMin, graphX.graphMax, xArea, xsp);
393
+ gp += offset;
394
+ } else {
395
+ gp = Canvas.calculateY(graphY.graphMax, graphY.graphMin, graphY.graphMax, yArea, ysp);
396
+ gp -= offset;
397
+ }
398
+ } else if (isHorizontal) {
399
+ gp = Canvas.calculateX(value, graphX.graphMin, graphX.graphMax, xArea, xsp);
400
+ gp += offset;
401
+ } else {
402
+ gp = Canvas.calculateY(value, graphY.graphMin, graphY.graphMax, yArea, ysp);
403
+ gp -= offset;
404
+ }
405
+
406
+ let maxTipType = 'center';
407
+
408
+ ctx.save();
409
+ ctx.font = textStyle;
410
+ const maxTipWidth = Math.round(Math.max(ctx.measureText(text).width + 12, 40));
411
+
412
+ if (!isHorizontal) {
413
+ if (dp + (maxTipWidth / 2) > xep - 10) {
414
+ maxTipType = 'right';
415
+ tdp -= (maxTipWidth / 2) - (arrowSize * 2);
416
+ } else if (dp - (maxTipWidth / 2) < xsp + 10) {
417
+ maxTipType = 'left';
418
+ tdp += (maxTipWidth / 2) - (arrowSize * 2);
419
+ }
420
+ }
421
+
422
+ ctx.restore();
423
+
424
+ if (opt.showTextTip || tipType === 'max') {
425
+ this.showTextTip({
426
+ context: ctx,
427
+ type: maxTipType,
428
+ width: maxTipWidth,
429
+ height: maxTipHeight,
430
+ x: isHorizontal ? gp + (maxTipWidth / 2) : tdp,
431
+ y: isHorizontal ? tdp + (maxTipHeight / 2) : gp,
432
+ opt,
433
+ arrowSize,
434
+ borderRadius,
435
+ text,
436
+ textStyle,
437
+ });
438
+ }
439
+
440
+ if (opt.showTip && tipType === 'sel') {
441
+ this.showTip({
442
+ context: ctx,
443
+ x: isHorizontal ? gp : dp,
444
+ y: isHorizontal ? dp : gp,
445
+ opt,
446
+ isSamePos,
447
+ });
448
+ }
449
+ },
450
+
451
+ /**
452
+ * Draw text tip
453
+ * @param {object} param object for drawing text tip
454
+ *
455
+ * @returns {undefined}
456
+ */
457
+ showTextTip(param) {
458
+ const isHorizontal = !!this.options.horizontal;
459
+ const { type, width, height, x, y, arrowSize, borderRadius, text, opt, textStyle } = param;
460
+
461
+ const ctx = param.context;
462
+
463
+ const sx = x - (width / 2);
464
+ const ex = x + (width / 2);
465
+ const sy = y - height;
466
+ const ey = y;
467
+
468
+ ctx.save();
469
+ ctx.font = textStyle;
470
+
471
+ ctx.fillStyle = opt.tipBackground ?? opt.tipStyle.background;
472
+ ctx.shadowBlur = 0;
473
+
474
+ ctx.beginPath();
475
+ ctx.moveTo(sx + borderRadius, sy);
476
+ ctx.quadraticCurveTo(sx, sy, sx, sy + borderRadius);
477
+
478
+ if (isHorizontal) {
479
+ ctx.lineTo(sx, sy + borderRadius + (arrowSize / 2));
480
+ ctx.lineTo(sx - arrowSize, ey - (height / 2));
481
+ ctx.lineTo(sx, ey - borderRadius - (arrowSize / 2));
482
+ }
483
+
484
+ ctx.lineTo(sx, ey - borderRadius);
485
+ ctx.quadraticCurveTo(sx, ey, sx + borderRadius, ey);
486
+
487
+ if (!isHorizontal) {
488
+ if (type === 'left') {
489
+ ctx.lineTo(sx + borderRadius + arrowSize, ey + arrowSize);
490
+ ctx.lineTo(sx + borderRadius + (arrowSize * 2), ey);
491
+ } else if (type === 'right') {
492
+ ctx.lineTo(ex - (arrowSize * 2) - borderRadius, ey);
493
+ ctx.lineTo(ex - arrowSize - borderRadius, ey + arrowSize);
494
+ } else {
495
+ ctx.lineTo(x - arrowSize, ey);
496
+ ctx.lineTo(x, ey + arrowSize);
497
+ ctx.lineTo(x + arrowSize, ey);
498
+ }
499
+ }
500
+
501
+ ctx.lineTo(ex - borderRadius, ey);
502
+ ctx.quadraticCurveTo(ex, ey, ex, ey - borderRadius);
503
+ ctx.lineTo(ex, sy + borderRadius);
504
+ ctx.quadraticCurveTo(ex, sy, ex - borderRadius, sy);
505
+ ctx.lineTo(sx + borderRadius, sy);
506
+ ctx.closePath();
507
+ ctx.fill();
508
+ ctx.restore();
509
+ ctx.save();
510
+ ctx.font = textStyle;
511
+ ctx.fillStyle = opt.tipTextColor ?? opt.tipStyle.textColor;
512
+ ctx.textBaseline = 'middle';
513
+ ctx.textAlign = 'center';
514
+ ctx.fillText(`${text}`, x, sy + (height / 2));
515
+ ctx.restore();
516
+ },
517
+
518
+ /**
519
+ * Draw arrow tip
520
+ * @param {object} param object for drawing arrow tip
521
+ *
522
+ * @returns {undefined}
523
+ */
524
+ showTip(param) {
525
+ const isHorizontal = !!this.options.horizontal;
526
+ const { x, y, opt, isSamePos } = param;
527
+ const ctx = param.context;
528
+ const offset = isSamePos ? 24 : 0;
529
+ const cy = y - offset;
530
+ ctx.save();
531
+
532
+ ctx.fillStyle = opt.tipBackground ?? opt.tipStyle.background;
533
+ ctx.beginPath();
534
+ ctx.moveTo(x, cy);
535
+ if (isHorizontal) {
536
+ ctx.lineTo(x + 6, cy - 6);
537
+ ctx.lineTo(x + 6, cy + 6);
538
+ } else {
539
+ ctx.lineTo(x + 6, cy - 6);
540
+ ctx.lineTo(x - 6, cy - 6);
541
+ }
542
+ ctx.lineTo(x, cy);
543
+ ctx.closePath();
544
+ ctx.fill();
545
+
546
+ ctx.restore();
547
+ },
548
+ };
549
+
550
+ export default modules;