cx 24.3.10 → 24.4.0

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.
@@ -12,15 +12,16 @@ export class PieChart extends BoundedObject {
12
12
  declareData() {
13
13
  super.declareData(...arguments, {
14
14
  angle: undefined,
15
- startAngle: 0,
15
+ startAngle: undefined,
16
16
  clockwise: undefined,
17
+ gap: undefined,
17
18
  });
18
19
  }
19
20
 
20
21
  explore(context, instance) {
21
22
  if (!instance.pie) instance.pie = new PieCalculator();
22
- var { data } = instance;
23
- instance.pie.reset(data.angle, data.startAngle, data.clockwise);
23
+ let { data } = instance;
24
+ instance.pie.reset(data.angle, data.startAngle, data.clockwise, data.gap);
24
25
 
25
26
  context.push("pie", instance.pie);
26
27
  super.explore(context, instance);
@@ -32,7 +33,7 @@ export class PieChart extends BoundedObject {
32
33
 
33
34
  prepare(context, instance) {
34
35
  this.prepareBounds(context, instance);
35
- var { data, pie } = instance;
36
+ let { data, pie } = instance;
36
37
  pie.measure(data.bounds);
37
38
  let hash = pie.hash();
38
39
  instance.cache("hash", hash);
@@ -45,17 +46,24 @@ export class PieChart extends BoundedObject {
45
46
  PieChart.prototype.anchors = "0 1 1 0";
46
47
 
47
48
  class PieCalculator {
48
- reset(angle, startAngle, clockwise) {
49
+ reset(angle, startAngle, clockwise, gap) {
50
+ if (angle == 360) angle = 359.99; // really hacky way to draw full circles
49
51
  this.angleTotal = (angle / 180) * Math.PI;
50
52
  this.startAngle = (startAngle / 180) * Math.PI;
51
53
  this.clockwise = clockwise;
54
+ this.gap = gap;
52
55
  this.stacks = {};
53
56
  }
54
57
 
55
- acknowledge(stack, value) {
56
- var s = this.stacks[stack];
57
- if (!s) s = this.stacks[stack] = { total: 0 };
58
- if (value > 0) s.total += value;
58
+ acknowledge(stack, value, r, r0, percentageRadius) {
59
+ let s = this.stacks[stack];
60
+ if (!s) s = this.stacks[stack] = { total: 0, r0s: this.gap > 0 ? [] : null, r0ps: this.gap > 0 ? [] : null };
61
+ if (value > 0) {
62
+ s.total += value;
63
+ if (this.gap > 0 && r0 > 0)
64
+ if (percentageRadius) s.r0ps.push(r0);
65
+ else s.r0s.push(r0);
66
+ }
59
67
  }
60
68
 
61
69
  hash() {
@@ -69,32 +77,63 @@ class PieCalculator {
69
77
  cx: this.cx,
70
78
  cy: this.cy,
71
79
  R: this.R,
80
+ gap: this.gap,
72
81
  };
73
82
  }
74
83
 
75
84
  measure(rect) {
76
- for (var s in this.stacks) {
77
- var stack = this.stacks[s];
78
- stack.angleFactor = stack.total > 0 ? this.angleTotal / stack.total : 0;
85
+ this.R = Math.max(0, Math.min(rect.width(), rect.height())) / 2;
86
+ for (let s in this.stacks) {
87
+ let stack = this.stacks[s];
88
+ let gapAngleTotal = 0;
89
+ stack.gap = this.gap;
90
+ if (this.gap > 0) {
91
+ // gap cannot be larger of two times the smallest r0
92
+ for (let index = 0; index < stack.r0s.length; index++)
93
+ if (2 * stack.r0s[index] < stack.gap) stack.gap = 2 * stack.r0s[index];
94
+ for (let index = 0; index < stack.r0ps.length; index++) {
95
+ let r0 = (stack.r0ps[index] * this.R) / 100;
96
+ if (2 * r0 < stack.gap) stack.gap = 2 * r0;
97
+ }
98
+ }
99
+ while (stack.gap > 0) {
100
+ for (let index = 0; index < stack.r0s.length; index++)
101
+ gapAngleTotal += Math.asin(stack.gap / stack.r0s[index] / 2);
102
+
103
+ for (let index = 0; index < stack.r0ps.length; index++)
104
+ gapAngleTotal += Math.asin(stack.gap / ((stack.r0ps[index] * this.R) / 100) / 2);
105
+
106
+ if (gapAngleTotal < 0.25 * this.angleTotal) break;
107
+ stack.gap = stack.gap * 0.9;
108
+ gapAngleTotal = 0;
109
+ }
110
+ if (gapAngleTotal == 0) stack.gap = 0;
111
+ stack.angleFactor = stack.total > 0 ? (this.angleTotal - gapAngleTotal) / stack.total : 0;
79
112
  stack.lastAngle = this.startAngle;
80
113
  }
81
114
  this.cx = (rect.l + rect.r) / 2;
82
115
  this.cy = (rect.t + rect.b) / 2;
83
- this.R = Math.max(0, Math.min(rect.width(), rect.height())) / 2;
84
116
  }
85
117
 
86
- map(stack, value) {
87
- var s = this.stacks[stack];
88
- var angle = value * s.angleFactor;
89
- var startAngle = s.lastAngle;
90
-
91
- if (!this.clockwise) s.lastAngle += angle;
92
- else s.lastAngle -= angle;
118
+ map(stack, value, r, r0, percentageRadius) {
119
+ if (percentageRadius) {
120
+ r = (r * this.R) / 100;
121
+ r0 = (r0 * this.R) / 100;
122
+ }
123
+ let s = this.stacks[stack];
124
+ let angle = value * s.angleFactor;
125
+ let startAngle = s.lastAngle;
126
+ let clockFactor = this.clockwise ? -1 : 1;
127
+ let gapAngle = r0 > 0 && s.gap > 0 ? Math.asin(s.gap / r0 / 2) : 0;
128
+ s.lastAngle += clockFactor * (angle + gapAngle);
129
+ let endAngle = startAngle + clockFactor * angle + gapAngle;
93
130
 
94
131
  return {
95
132
  startAngle,
96
- endAngle: s.lastAngle,
97
- midAngle: (startAngle + s.lastAngle) / 2,
133
+ endAngle: startAngle + clockFactor * angle + gapAngle,
134
+ angle,
135
+ midAngle: (startAngle + endAngle) / 2,
136
+ gap: s.gap,
98
137
  cx: this.cx,
99
138
  cy: this.cy,
100
139
  R: this.R,
@@ -102,106 +141,139 @@ class PieCalculator {
102
141
  }
103
142
  }
104
143
 
105
- function createSvgArc(x, y, r0 = 0, r, startAngleRadian, endAngleRadian, br = 0) {
106
- if (startAngleRadian > endAngleRadian) {
107
- var s = startAngleRadian;
108
- startAngleRadian = endAngleRadian;
109
- endAngleRadian = s;
144
+ function createSvgArc(cx, cy, r0 = 0, r, startAngle, endAngle, br = 0, gap = 0) {
145
+ let gap2 = gap / 2;
146
+
147
+ if (startAngle > endAngle) {
148
+ let s = startAngle;
149
+ startAngle = endAngle;
150
+ endAngle = s;
110
151
  }
111
152
 
112
153
  let path = [];
113
154
  // limit br size based on r and r0
114
155
  if (br > (r - r0) / 2) br = (r - r0) / 2;
115
156
 
116
- let largeArc = endAngleRadian - startAngleRadian > Math.PI ? 1 : 0;
117
-
118
157
  if (br > 0) {
119
158
  if (r0 > 0) {
120
159
  let innerBr = br;
121
- let innerSmallArcAngle = Math.asin(br / (r0 + br));
122
- if (innerSmallArcAngle > (endAngleRadian - startAngleRadian) / 2) {
123
- innerSmallArcAngle = (endAngleRadian - startAngleRadian) / 2;
160
+ let innerSmallArcAngle = Math.asin((br + gap2) / (r0 + br));
161
+
162
+ // adjust br according to the available area
163
+ if (innerSmallArcAngle > (endAngle - startAngle) / 2) {
164
+ innerSmallArcAngle = (endAngle - startAngle) / 2;
124
165
  let sin = Math.sin(innerSmallArcAngle);
125
- // correct br according to newly calculated border radius angle
126
- innerBr = (r0 * sin) / (1 - sin);
166
+ innerBr = (r0 * sin - gap2) / (1 - sin);
127
167
  }
128
- let innerHip = Math.cos(innerSmallArcAngle) * (r0 + innerBr);
129
168
 
130
- let innerSmallArc1XFrom = x + Math.cos(endAngleRadian) * innerHip;
131
- let innerSmallArc1YFrom = y - Math.sin(endAngleRadian) * innerHip;
169
+ let innerHipDiagonal = (r0 + innerBr) * Math.cos(innerSmallArcAngle);
170
+
171
+ let innerSmallArc1XFrom = cx + Math.cos(endAngle) * innerHipDiagonal + Math.cos(endAngle - Math.PI / 2) * gap2;
172
+ let innerSmallArc1YFrom = cy - Math.sin(endAngle) * innerHipDiagonal - Math.sin(endAngle - Math.PI / 2) * gap2;
132
173
 
133
174
  // move from the first small inner arc
134
175
  path.push(move(innerSmallArc1XFrom, innerSmallArc1YFrom));
135
176
 
136
- let innerSmallArc1XTo = x + Math.cos(endAngleRadian - innerSmallArcAngle) * r0;
137
- let innerSmallArc1YTo = y - Math.sin(endAngleRadian - innerSmallArcAngle) * r0;
177
+ let innerSmallArc1XTo = cx + Math.cos(endAngle - innerSmallArcAngle) * r0;
178
+ let innerSmallArc1YTo = cy - Math.sin(endAngle - innerSmallArcAngle) * r0;
138
179
 
139
180
  // add first small inner arc
140
181
  path.push(arc(innerBr, innerBr, 0, 0, 0, innerSmallArc1XTo, innerSmallArc1YTo));
141
182
 
142
- let innerArcXTo = x + Math.cos(startAngleRadian + innerSmallArcAngle) * r0;
143
- let innerArcYTo = y - Math.sin(startAngleRadian + innerSmallArcAngle) * r0;
183
+ // SECOND ARC
144
184
 
185
+ let innerArcXTo = cx + Math.cos(startAngle + innerSmallArcAngle) * r0;
186
+ let innerArcYTo = cy - Math.sin(startAngle + innerSmallArcAngle) * r0;
145
187
  // add large inner arc
146
- path.push(arc(r0, r0, 0, largeArc, 1, innerArcXTo, innerArcYTo));
147
-
148
- let innerSmallArc2XTo = x + Math.cos(startAngleRadian) * innerHip;
149
- let innerSmallArc2YTo = y - Math.sin(startAngleRadian) * innerHip;
188
+ path.push(
189
+ arc(
190
+ r0,
191
+ r0,
192
+ 0,
193
+ largeArcFlag(endAngle - innerSmallArcAngle - startAngle - innerSmallArcAngle),
194
+ 1,
195
+ innerArcXTo,
196
+ innerArcYTo,
197
+ ),
198
+ );
199
+
200
+ let innerSmallArc2XTo =
201
+ cx + Math.cos(startAngle) * innerHipDiagonal + Math.cos(startAngle + Math.PI / 2) * gap2;
202
+ let innerSmallArc2YTo =
203
+ cy - Math.sin(startAngle) * innerHipDiagonal - Math.sin(startAngle + Math.PI / 2) * gap2;
150
204
  // add second small inner arc
151
205
  path.push(arc(innerBr, innerBr, 0, 0, 0, innerSmallArc2XTo, innerSmallArc2YTo));
152
206
  } else {
153
- path.push(move(x, y));
207
+ path.push(move(cx, cy));
154
208
  }
155
209
 
156
210
  let outerBr = br;
157
- let outerSmallArcAngle = Math.asin(br / (r - br));
158
- if (outerSmallArcAngle > (endAngleRadian - startAngleRadian) / 2) {
159
- outerSmallArcAngle = (endAngleRadian - startAngleRadian) / 2;
211
+ let outerSmallArcAngle = Math.asin((br + gap2) / (r - br));
212
+
213
+ // tweak br according to the available area
214
+ if (outerSmallArcAngle > (endAngle - startAngle) / 2) {
215
+ outerSmallArcAngle = (endAngle - startAngle) / 2;
160
216
  let sin = Math.sin(outerSmallArcAngle);
161
- // correct br according to newly calculated border radius angle
162
- outerBr = (r * sin) / (1 + sin);
217
+ outerBr = (r * sin - gap2) / (1 + sin);
163
218
  }
164
- let outerHip = Math.cos(outerSmallArcAngle) * (r - outerBr);
165
219
 
166
- let outerSmallArc1XFrom = x + Math.cos(startAngleRadian) * outerHip;
167
- let outerSmallArc1YFrom = y - Math.sin(startAngleRadian) * outerHip;
220
+ let outerHipDiagonal = Math.cos(outerSmallArcAngle) * (r - outerBr);
168
221
 
169
- let outerSmallArc1XTo = x + Math.cos(startAngleRadian + outerSmallArcAngle) * r;
170
- let outerSmallArc1YTo = y - Math.sin(startAngleRadian + outerSmallArcAngle) * r;
222
+ let outerSmallArc1XFrom =
223
+ cx + Math.cos(startAngle) * outerHipDiagonal + Math.cos(startAngle + Math.PI / 2) * gap2;
224
+ let outerSmallArc1YFrom =
225
+ cy - Math.sin(startAngle) * outerHipDiagonal - Math.sin(startAngle + Math.PI / 2) * gap2;
171
226
 
172
- let outerLargeArcXTo = x + Math.cos(endAngleRadian - outerSmallArcAngle) * r;
173
- let outerLargeArcYTo = y - Math.sin(endAngleRadian - outerSmallArcAngle) * r;
227
+ let outerSmallArc1XTo = cx + Math.cos(startAngle + outerSmallArcAngle) * r;
228
+ let outerSmallArc1YTo = cy - Math.sin(startAngle + outerSmallArcAngle) * r;
174
229
 
175
- let outerSmallArc2XTo = x + Math.cos(endAngleRadian) * outerHip;
176
- let outerSmallArc2YTo = y - Math.sin(endAngleRadian) * outerHip;
230
+ let outerLargeArcXTo = cx + Math.cos(endAngle - outerSmallArcAngle) * r;
231
+ let outerLargeArcYTo = cy - Math.sin(endAngle - outerSmallArcAngle) * r;
232
+
233
+ let outerSmallArc2XTo = cx + Math.cos(endAngle) * outerHipDiagonal + Math.cos(endAngle - Math.PI / 2) * gap2;
234
+ let outerSmallArc2YTo = cy - Math.sin(endAngle) * outerHipDiagonal - Math.sin(endAngle - Math.PI / 2) * gap2;
177
235
 
178
236
  path.push(
179
237
  line(outerSmallArc1XFrom, outerSmallArc1YFrom),
180
238
  arc(outerBr, outerBr, 0, 0, 0, outerSmallArc1XTo, outerSmallArc1YTo),
181
- arc(r, r, 0, largeArc, 0, outerLargeArcXTo, outerLargeArcYTo),
182
- arc(outerBr, outerBr, 0, 0, 0, outerSmallArc2XTo, outerSmallArc2YTo)
239
+ arc(
240
+ r,
241
+ r,
242
+ 0,
243
+ largeArcFlag(endAngle - outerSmallArcAngle - startAngle - outerSmallArcAngle),
244
+ 0,
245
+ outerLargeArcXTo,
246
+ outerLargeArcYTo,
247
+ ),
248
+ arc(outerBr, outerBr, 0, 0, 0, outerSmallArc2XTo, outerSmallArc2YTo),
183
249
  );
184
250
  } else {
185
251
  if (r0 > 0) {
186
- let startX = x + Math.cos(endAngleRadian) * r0;
187
- let startY = y - Math.sin(endAngleRadian) * r0;
252
+ let innerGapAngle = r0 > 0 && gap2 > 0 ? Math.asin(gap2 / r0) : 0;
253
+ let innerStartAngle = startAngle + innerGapAngle;
254
+ let innerEndAngle = endAngle - innerGapAngle;
255
+ let startX = cx + Math.cos(innerEndAngle) * r0;
256
+ let startY = cy - Math.sin(innerEndAngle) * r0;
188
257
  path.push(move(startX, startY));
189
258
 
190
- let innerArcToX = x + Math.cos(startAngleRadian) * r0;
191
- let innerArcToY = y - Math.sin(startAngleRadian) * r0;
259
+ let innerArcToX = cx + Math.cos(innerStartAngle) * r0;
260
+ let innerArcToY = cy - Math.sin(innerStartAngle) * r0;
192
261
 
193
- path.push(arc(r0, r0, 0, largeArc, 1, innerArcToX, innerArcToY));
262
+ path.push(arc(r0, r0, 0, largeArcFlag(innerStartAngle - innerEndAngle), 1, innerArcToX, innerArcToY));
194
263
  } else {
195
- path.push(move(x, y));
264
+ path.push(move(cx, cy));
196
265
  }
197
266
 
198
- let lineToX = x + Math.cos(startAngleRadian) * r;
199
- let lineToY = y - Math.sin(startAngleRadian) * r;
267
+ let outerGapAngle = r > 0 && gap2 > 0 ? Math.asin(gap2 / r) : 0;
268
+ let outerStartAngle = startAngle + outerGapAngle;
269
+ let outerEndAngle = endAngle - outerGapAngle;
270
+ let lineToX = cx + Math.cos(outerStartAngle) * r;
271
+ let lineToY = cy - Math.sin(outerStartAngle) * r;
200
272
  path.push(line(lineToX, lineToY));
201
273
 
202
- let arcToX = x + Math.cos(endAngleRadian) * r;
203
- let arcToY = y - Math.sin(endAngleRadian) * r;
204
- path.push(arc(r, r, 0, largeArc, 0, arcToX, arcToY));
274
+ let arcToX = cx + Math.cos(outerEndAngle) * r;
275
+ let arcToY = cy - Math.sin(outerEndAngle) * r;
276
+ path.push(arc(r, r, 0, largeArcFlag(outerEndAngle - outerStartAngle), 0, arcToX, arcToY));
205
277
  }
206
278
 
207
279
  path.push(z());
@@ -210,6 +282,8 @@ function createSvgArc(x, y, r0 = 0, r, startAngleRadian, endAngleRadian, br = 0)
210
282
 
211
283
  PieChart.prototype.anchors = "0 1 1 0";
212
284
  PieChart.prototype.angle = 360;
285
+ PieChart.prototype.startAngle = 0;
286
+ PieChart.prototype.gap = 0;
213
287
 
214
288
  Widget.alias("pie-slice");
215
289
  export class PieSlice extends Container {
@@ -220,7 +294,7 @@ export class PieSlice extends Container {
220
294
  }
221
295
 
222
296
  declareData() {
223
- var selection = this.selection.configureWidget(this);
297
+ let selection = this.selection.configureWidget(this);
224
298
  super.declareData(...arguments, selection, {
225
299
  active: true,
226
300
  r0: undefined,
@@ -263,7 +337,7 @@ export class PieSlice extends Container {
263
337
  instance.hoverSync = context.hoverSync;
264
338
 
265
339
  if (instance.valid && data.active) {
266
- instance.pie.acknowledge(data.stack, data.value);
340
+ instance.pie.acknowledge(data.stack, data.value, data.r, data.r0, this.percentageRadius);
267
341
  super.explore(context, instance);
268
342
  }
269
343
  }
@@ -277,7 +351,7 @@ export class PieSlice extends Container {
277
351
  }
278
352
 
279
353
  if (instance.valid && data.active) {
280
- let seg = pie.map(data.stack, data.value);
354
+ let seg = pie.map(data.stack, data.value, data.r, data.r0, this.percentageRadius);
281
355
 
282
356
  if (
283
357
  !segment ||
@@ -344,15 +418,15 @@ export class PieSlice extends Container {
344
418
  }
345
419
 
346
420
  onLegendClick(e, instance) {
347
- var allActions = this.legendAction == "auto";
348
- var { data } = instance;
421
+ let allActions = this.legendAction == "auto";
422
+ let { data } = instance;
349
423
  if (allActions || this.legendAction == "toggle") if (instance.set("active", !data.active)) return;
350
424
 
351
425
  if (allActions || this.legendAction == "select") this.handleClick(e, instance);
352
426
  }
353
427
 
354
428
  render(context, instance, key) {
355
- var { segment, data } = instance;
429
+ let { segment, data } = instance;
356
430
  if (!instance.valid || !data.active) return null;
357
431
 
358
432
  return withHoverSync(
@@ -361,7 +435,7 @@ export class PieSlice extends Container {
361
435
  this.hoverChannel,
362
436
  data.hoverId,
363
437
  ({ hover, onMouseMove, onMouseLeave }) => {
364
- var stateMods = {
438
+ let stateMods = {
365
439
  selected: this.selection.isInstanceSelected(instance),
366
440
  disabled: data.disabled,
367
441
  selectable: !this.selection.isDummy,
@@ -376,7 +450,8 @@ export class PieSlice extends Container {
376
450
  data.r * segment.radiusMultiplier,
377
451
  segment.startAngle,
378
452
  segment.endAngle,
379
- data.br
453
+ data.br,
454
+ segment.gap,
380
455
  );
381
456
 
382
457
  return (
@@ -400,7 +475,7 @@ export class PieSlice extends Container {
400
475
  {this.renderChildren(context, instance)}
401
476
  </g>
402
477
  );
403
- }
478
+ },
404
479
  );
405
480
  }
406
481
 
@@ -431,6 +506,10 @@ function arc(rx, ry, xRotation, largeArc, sweep, x, y) {
431
506
  return `A ${rx} ${ry} ${xRotation} ${largeArc} ${sweep} ${x} ${y}`;
432
507
  }
433
508
 
509
+ function largeArcFlag(angle) {
510
+ return angle > Math.PI || angle < -Math.PI ? 1 : 0;
511
+ }
512
+
434
513
  PieSlice.prototype.offset = 0;
435
514
  PieSlice.prototype.r0 = 0;
436
515
  PieSlice.prototype.r = 50;
@@ -443,5 +522,6 @@ PieSlice.prototype.legendAction = "auto";
443
522
  PieSlice.prototype.legendShape = "circle";
444
523
  PieSlice.prototype.hoverChannel = "default";
445
524
  PieSlice.prototype.styled = true;
525
+ PieSlice.prototype.br = 0;
446
526
 
447
527
  Widget.alias("pie-chart", PieChart);
@@ -0,0 +1,35 @@
1
+ import * as Cx from "../core";
2
+
3
+ interface RangeMarkerProps extends Cx.StyledContainerProps {
4
+ /** The `x` value binding or expression. */
5
+ x?: Cx.NumberProp;
6
+
7
+ /** The `y` value binding or expression. */
8
+ y?: Cx.NumberProp;
9
+
10
+ /** The shape of marker, Could be `min`, `max`, `line`. Default to `line`. */
11
+ shape?: Cx.StringProp;
12
+
13
+ /** Switch to vertical mode. */
14
+ vertical?: Cx.BooleanProp;
15
+
16
+ /** Size of the range marker. */
17
+ size?: Cx.NumberProp;
18
+
19
+ /** Style object applied to the range marker. */
20
+ lineStyle?: Cx.StyleProp;
21
+
22
+ /** Class object applied to the range marker. */
23
+ lineClass?: Cx.StyleProp;
24
+
25
+ /** Size of vertical or horizontal caps. */
26
+ capSize?: Cx.NumberProp;
27
+
28
+ /** The laneOffset property adjusts the positioning of lane elements, enhancing their alignment and readability. */
29
+ laneOffset?: Cx.NumberProp;
30
+
31
+ /** Inflate the range marker.*/
32
+ inflate?: Cx.NumberProp;
33
+ }
34
+
35
+ export class RangeMarkerProps extends Cx.Widget<RangeMarkerProps> {}
@@ -0,0 +1,155 @@
1
+ import { BoundedObject } from "../svg/BoundedObject";
2
+ import { Rect } from "../svg/util/Rect";
3
+ import { Widget } from "../ui/Widget";
4
+ import { parseStyle } from "../util/parseStyle";
5
+
6
+ export class RangeMarker extends BoundedObject {
7
+ declareData() {
8
+ super.declareData(...arguments, {
9
+ x: undefined,
10
+ y: undefined,
11
+ shape: undefined,
12
+ vertical: undefined,
13
+ size: undefined,
14
+ laneOffset: undefined,
15
+ lineStyle: { structured: true },
16
+ lineClass: { structured: true },
17
+ capSize: undefined,
18
+ inflate: undefined,
19
+ });
20
+ }
21
+
22
+ init() {
23
+ this.lineStyle = parseStyle(this.lineStyle);
24
+ super.init();
25
+ }
26
+
27
+ prepareData(context, instance) {
28
+ instance.axes = context.axes;
29
+ instance.xAxis = context.axes[this.xAxis];
30
+ instance.yAxis = context.axes[this.yAxis];
31
+ super.prepareData(context, instance);
32
+ }
33
+
34
+ explore(context, instance) {
35
+ let { data, xAxis, yAxis } = instance;
36
+
37
+ if (this.affectsAxes) {
38
+ if (xAxis && data.x != null) xAxis.acknowledge(data.x, 0, 0);
39
+ if (yAxis && data.y != null) yAxis.acknowledge(data.y, 0, 0);
40
+ }
41
+
42
+ super.explore(context, instance);
43
+ }
44
+
45
+ calculateBounds(context, instance) {
46
+ let { data, xAxis, yAxis } = instance;
47
+
48
+ let l, r, t, b;
49
+
50
+ if (data.x == null || data.y == null) {
51
+ return super.calculateBounds(context, instance);
52
+ }
53
+
54
+ if (!this.vertical) {
55
+ l = xAxis.map(data.x, data.laneOffset - data.size / 2) - data.inflate;
56
+ r = xAxis.map(data.x, data.laneOffset + data.size / 2) + data.inflate;
57
+ t = b = yAxis.map(data.y);
58
+ if (data.shape == "max") {
59
+ b += data.capSize;
60
+ } else if (data.shape == "min") {
61
+ t -= data.capSize;
62
+ }
63
+ } else {
64
+ l = r = xAxis.map(data.x);
65
+ t = yAxis.map(data.y, data.laneOffset - data.size / 2) + data.inflate;
66
+ b = yAxis.map(data.y, data.laneOffset + data.size / 2) - data.inflate;
67
+ if (data.shape == "max") {
68
+ l -= data.capSize;
69
+ } else if (data.shape == "min") {
70
+ r += data.capSize;
71
+ }
72
+ }
73
+
74
+ return new Rect({
75
+ l,
76
+ r,
77
+ t,
78
+ b,
79
+ });
80
+ }
81
+
82
+ prepare(context, instance) {
83
+ super.prepare(context, instance);
84
+ }
85
+
86
+ render(context, instance, key) {
87
+ var { data } = instance;
88
+ let { CSS, baseClass } = this;
89
+ let { bounds, shape } = data;
90
+
91
+ let path = "";
92
+ if (this.vertical) {
93
+ switch (shape) {
94
+ default:
95
+ case "line":
96
+ path += `M ${bounds.r} ${bounds.t} `;
97
+ path += `L ${bounds.r} ${bounds.b}`;
98
+ break;
99
+ case "max":
100
+ path += `M ${bounds.l} ${bounds.t} `;
101
+ path += `L ${bounds.r} ${bounds.t}`;
102
+ path += `L ${bounds.r} ${bounds.b}`;
103
+ path += `L ${bounds.l} ${bounds.b}`;
104
+ break;
105
+ case "min":
106
+ path += `M ${bounds.r} ${bounds.t} `;
107
+ path += `L ${bounds.l} ${bounds.t}`;
108
+ path += `L ${bounds.l} ${bounds.b}`;
109
+ path += `L ${bounds.r} ${bounds.b}`;
110
+ break;
111
+ }
112
+ } else {
113
+ switch (shape) {
114
+ default:
115
+ case "line":
116
+ path += `M ${bounds.r} ${bounds.t} `;
117
+ path += `L ${bounds.l} ${bounds.t}`;
118
+ break;
119
+ case "max":
120
+ path += `M ${bounds.l} ${bounds.b} `;
121
+ path += `L ${bounds.l} ${bounds.t}`;
122
+ path += `L ${bounds.r} ${bounds.t}`;
123
+ path += `L ${bounds.r} ${bounds.b}`;
124
+ break;
125
+ case "min":
126
+ path += `M ${bounds.l} ${bounds.t} `;
127
+ path += `L ${bounds.l} ${bounds.b}`;
128
+ path += `L ${bounds.r} ${bounds.b}`;
129
+ path += `L ${bounds.r} ${bounds.t}`;
130
+ break;
131
+ }
132
+ }
133
+
134
+ return (
135
+ <g key={key} class={data.classNames} style={data.style}>
136
+ <path d={path} class={CSS.expand(CSS.element(baseClass, "path"), data.lineClass)} style={data.lineStyle} />
137
+ {this.renderChildren(context, instance)}
138
+ </g>
139
+ );
140
+ }
141
+ }
142
+
143
+ RangeMarker.prototype.baseClass = "rangemarker";
144
+ RangeMarker.prototype.xAxis = "x";
145
+ RangeMarker.prototype.yAxis = "y";
146
+
147
+ RangeMarker.prototype.shape = "line";
148
+ RangeMarker.prototype.vertical = false;
149
+ RangeMarker.prototype.size = 1;
150
+ RangeMarker.prototype.laneOffset = 0;
151
+ RangeMarker.prototype.capSize = 5;
152
+ RangeMarker.prototype.inflate = 0;
153
+ RangeMarker.prototype.affectsAxes = true;
154
+
155
+ Widget.alias("range-marker", RangeMarker);
@@ -0,0 +1,15 @@
1
+ @mixin cx-rangemarker($name: "rangemarker", $besm: $cx-besm, $range-marker-color: $cx-default-range-marker-color) {
2
+ $block: map-get($besm, block);
3
+ $element: map-get($besm, element);
4
+ $state: map-get($besm, state);
5
+
6
+ .#{$element}#{$name}-path {
7
+ stroke: $range-marker-color;
8
+ fill: none;
9
+ stroke-width: 1px;
10
+ }
11
+ }
12
+
13
+ @if (cx-should-include("cx/charts/RangeMarker")) {
14
+ @include cx-rangemarker();
15
+ }