cx 23.5.2 → 23.7.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.
@@ -1,222 +1,252 @@
1
- import { BoundedObject } from '../../svg/BoundedObject'
2
- import { VDOM } from '../../ui/Widget';
3
- import { isUndefined } from '../../util/isUndefined';
4
- import { parseStyle } from '../../util/parseStyle';
5
-
6
- export class Axis extends BoundedObject {
7
-
8
- init() {
9
- if (this.labelAnchor == 'auto')
10
- this.labelAnchor = this.vertical ? this.secondary ? 'start' : 'end' : 'middle';
11
-
12
- if (this.labelDx == 'auto')
13
- this.labelDx = 0;
14
-
15
- if (this.labelDy == 'auto')
16
- this.labelDy = this.vertical ? '0.4em' : this.secondary ? 0 : '0.8em';
17
-
18
- if (isUndefined(this.minLabelDistance))
19
- this.minLabelDistance = this.vertical ? this.minLabelDistanceVertical : this.minLabelDistanceHorizontal;
20
-
21
- if (this.labelLineCountDyFactor == 'auto')
22
- this.labelLineCountDyFactor = this.vertical ? -0.5 : this.secondary ? -1 : 0;
23
-
24
- this.lineStyle = parseStyle(this.lineStyle);
25
- this.tickStyle = parseStyle(this.tickStyle);
26
- this.labelStyle = parseStyle(this.labelStyle);
27
-
28
- super.init();
29
- }
30
-
31
- declareData() {
32
- super.declareData({
33
- anchors: undefined,
34
- hideLabels: undefined,
35
- hideLine: undefined,
36
- hideTicks: undefined,
37
- labelRotation: undefined,
38
- labelAnchor: undefined,
39
- lineStyle: undefined,
40
- lineClass: undefined,
41
- labelStyle: undefined,
42
- labelClass: undefined,
43
- tickStyle: undefined,
44
- tickClass: undefined
45
- }, ...arguments)
46
- }
47
-
48
- report(context, instance) {
49
- return instance.calculator;
50
- }
51
-
52
- renderTicksAndLabels(context, instance, valueFormatter) {
53
-
54
- if (this.hidden)
55
- return false;
56
-
57
- var { data, calculator } = instance;
58
- var { bounds } = data;
59
- let { CSS, baseClass } = this;
60
- var size = calculator.findTickSize(this.minLabelDistance);
61
-
62
- var labelClass = CSS.expand(CSS.element(baseClass, 'label'), data.labelClass);
63
- var offsetClass = CSS.element(baseClass, 'label-offset');
64
-
65
- var x1, y1, x2, y2, tickSize = this.tickSize;
66
-
67
- if (this.vertical) {
68
- x1 = x2 = this.secondary ? bounds.r : bounds.l;
69
- y1 = bounds.b;
70
- y2 = bounds.t;
71
- } else {
72
- x1 = bounds.l;
73
- x2 = bounds.r;
74
- y1 = y2 = this.secondary ? bounds.t : bounds.b;
75
- }
76
-
77
- var res = [null, null];
78
-
79
- if (!data.hideLine) {
80
- res[0] = (
81
- <line
82
- key="line"
83
- className={CSS.expand(CSS.element(baseClass, "line"), data.lineClass)}
84
- style={data.lineStyle}
85
- x1={x1} y1={y1} x2={x2} y2={y2}
86
- />
87
- )
88
- }
89
-
90
- var t = [];
91
- if (size > 0 && !data.hideLabels) {
92
- var ticks = calculator.getTicks([size]);
93
- ticks.forEach((serie, si) => {
94
- serie.forEach((v, i) => {
95
- var s = calculator.map(v);
96
-
97
- if (this.secondary) {
98
- x1 = this.vertical ? bounds.r : s;
99
- y1 = this.vertical ? s : bounds.t;
100
- x2 = this.vertical ? bounds.r + tickSize : s;
101
- y2 = this.vertical ? s : bounds.t - tickSize;
102
- } else {
103
- x1 = this.vertical ? bounds.l : s;
104
- y1 = this.vertical ? s : bounds.b;
105
- x2 = this.vertical ? bounds.l - tickSize : s;
106
- y2 = this.vertical ? s : bounds.b + tickSize;
107
- }
108
-
109
- t.push(`M ${x1} ${y1} L ${x2} ${y2}`);
110
-
111
- var x, y;
112
- if (this.secondary) {
113
- x = this.vertical ? bounds.r + this.labelOffset : s;
114
- y = this.vertical ? s : bounds.t - this.labelOffset;
115
- } else {
116
- x = this.vertical ? bounds.l - this.labelOffset : s;
117
- y = this.vertical ? s : bounds.b + this.labelOffset;
118
- }
119
-
120
- var transform = data.labelRotation ? `rotate(${data.labelRotation} ${x} ${y})` : null;
121
- res.push(
122
- <text key={`label-${si}-${i}`}
123
- className={labelClass}
124
- style={data.labelStyle}
125
- x={x}
126
- y={y}
127
- dx={this.labelDx}
128
- textAnchor={data.labelAnchor}
129
- transform={transform}>
130
- {this.wrapLines(valueFormatter(v), x, this.labelDy, offsetClass)}
131
- </text>
132
- );
133
- });
134
- });
135
- }
136
-
137
- if (!data.hideTicks) {
138
- res[1] = <path key="ticks" className={CSS.expand(CSS.element(baseClass, "ticks"), data.tickClass)} style={data.tickStyle} d={t.join(' ')} />;
139
- }
140
-
141
- return res;
142
- }
143
-
144
- wrapLines(str, x, dy, offsetClass) {
145
- if (!this.labelWrap || typeof str != 'string')
146
- return <tspan x={x} dy={dy}>{str}</tspan>;
147
-
148
- let parts = str.split(' ');
149
- if (parts.length == 0)
150
- return null;
151
-
152
- let lines = [];
153
- let line = null;
154
- for (let i = 0; i < parts.length; i++) {
155
- if (!line)
156
- line = parts[i];
157
- else if (parts[i].length + line.length < this.labelMaxLineLength)
158
- line += ' ' + parts[i];
159
- else {
160
- lines.push(line);
161
- line = parts[i];
162
- }
163
- }
164
- lines.push(line);
165
-
166
- if (lines.length == 1)
167
- return <tspan x={x} dy={dy}>{str}</tspan>;
168
-
169
- let offset = this.labelLineCountDyFactor * (lines.length - 1);
170
- let result = [dy != null && <tspan key={-2} className={offsetClass} dy={dy}>_</tspan>];
171
-
172
- lines.forEach((p, i) => {
173
- result.push(<tspan key={i} dy={`${i == 0 ? offset : 1}em`} x={x}>{p}</tspan>)
174
- });
175
-
176
- return result;
177
- }
178
-
179
- prepare(context, instance) {
180
- super.prepare(context, instance);
181
- var { bounds } = instance.data;
182
- var [a, b] = !this.vertical ? [bounds.l, bounds.r] : [bounds.b, bounds.t];
183
- instance.calculator.measure(a, b);
184
- if (this.onMeasured)
185
- instance.invoke("onMeasured", instance.calculator.hash(), instance);
186
- if (!instance.calculator.isSame(instance.cached.axis))
187
- instance.markShouldUpdate(context);
188
- }
189
-
190
- cleanup(context, instance) {
191
- var { cached, calculator } = instance;
192
- cached.axis = calculator.hash();
193
- }
194
- }
195
-
196
- Axis.prototype.anchors = '0 1 1 0';
197
- Axis.prototype.styled = true;
198
- Axis.prototype.vertical = false;
199
- Axis.prototype.secondary = false;
200
- Axis.prototype.inverted = false;
201
- Axis.prototype.hidden = false;
202
- Axis.prototype.hideLabels = false;
203
- Axis.prototype.hideTicks = false;
204
- Axis.prototype.hideLine = false;
205
-
206
- Axis.prototype.tickSize = 3;
207
- Axis.prototype.minTickDistance = 25;
208
- Axis.prototype.minLabelDistanceVertical = 40;
209
- Axis.prototype.minLabelDistanceHorizontal = 50;
210
- Axis.prototype.labelOffset = 10;
211
- Axis.prototype.labelRotation = 0;
212
- Axis.prototype.labelAnchor = 'auto';
213
- Axis.prototype.labelDx = 'auto';
214
- Axis.prototype.labelDy = 'auto';
215
- Axis.prototype.labelWrap = false;
216
- Axis.prototype.labelLineCountDyFactor = 'auto';
217
- Axis.prototype.labelMaxLineLength = 10;
218
-
219
- Axis.namespace = 'ui.svg.chart.axis';
220
-
221
-
222
-
1
+ import { BoundedObject } from "../../svg/BoundedObject";
2
+ import { VDOM } from "../../ui/Widget";
3
+ import { isUndefined } from "../../util/isUndefined";
4
+ import { parseStyle } from "../../util/parseStyle";
5
+
6
+ export class Axis extends BoundedObject {
7
+ init() {
8
+ if (this.labelAnchor == "auto") this.labelAnchor = this.vertical ? (this.secondary ? "start" : "end") : "middle";
9
+
10
+ if (this.labelDx == "auto") this.labelDx = 0;
11
+
12
+ if (this.labelDy == "auto") this.labelDy = this.vertical ? "0.4em" : this.secondary ? 0 : "0.8em";
13
+
14
+ if (isUndefined(this.minLabelDistance))
15
+ this.minLabelDistance = this.vertical ? this.minLabelDistanceVertical : this.minLabelDistanceHorizontal;
16
+
17
+ if (this.labelLineCountDyFactor == "auto")
18
+ this.labelLineCountDyFactor = this.vertical ? -this.labelLineHeight / 2 : this.secondary ? -1 : 0;
19
+
20
+ this.lineStyle = parseStyle(this.lineStyle);
21
+ this.tickStyle = parseStyle(this.tickStyle);
22
+ this.labelStyle = parseStyle(this.labelStyle);
23
+
24
+ super.init();
25
+ }
26
+
27
+ declareData() {
28
+ super.declareData(
29
+ {
30
+ anchors: undefined,
31
+ hideLabels: undefined,
32
+ hideLine: undefined,
33
+ hideTicks: undefined,
34
+ labelRotation: undefined,
35
+ labelAnchor: undefined,
36
+ lineStyle: undefined,
37
+ lineClass: undefined,
38
+ labelStyle: undefined,
39
+ labelClass: undefined,
40
+ tickStyle: undefined,
41
+ tickClass: undefined,
42
+ },
43
+ ...arguments
44
+ );
45
+ }
46
+
47
+ prepareData(context, instance) {
48
+ super.prepareData(context, instance);
49
+ if (this.onCreateLabelFormatter)
50
+ instance.labelFormatter = instance.invoke("onCreateLabelFormatter", context, instance);
51
+ }
52
+
53
+ report(context, instance) {
54
+ return instance.calculator;
55
+ }
56
+
57
+ renderTicksAndLabels(context, instance, valueFormatter) {
58
+ if (this.hidden) return false;
59
+
60
+ var { data, calculator, labelFormatter } = instance;
61
+ var { bounds } = data;
62
+ let { CSS, baseClass } = this;
63
+ var size = calculator.findTickSize(this.minLabelDistance);
64
+
65
+ var labelClass = CSS.expand(CSS.element(baseClass, "label"), data.labelClass);
66
+ var offsetClass = CSS.element(baseClass, "label-offset");
67
+
68
+ var x1,
69
+ y1,
70
+ x2,
71
+ y2,
72
+ tickSize = this.tickSize;
73
+
74
+ if (this.vertical) {
75
+ x1 = x2 = this.secondary ? bounds.r : bounds.l;
76
+ y1 = bounds.b;
77
+ y2 = bounds.t;
78
+ } else {
79
+ x1 = bounds.l;
80
+ x2 = bounds.r;
81
+ y1 = y2 = this.secondary ? bounds.t : bounds.b;
82
+ }
83
+
84
+ var res = [null, null];
85
+
86
+ if (!data.hideLine) {
87
+ res[0] = (
88
+ <line
89
+ key="line"
90
+ className={CSS.expand(CSS.element(baseClass, "line"), data.lineClass)}
91
+ style={data.lineStyle}
92
+ x1={x1}
93
+ y1={y1}
94
+ x2={x2}
95
+ y2={y2}
96
+ />
97
+ );
98
+ }
99
+
100
+ var t = [];
101
+ if (size > 0 && !data.hideLabels) {
102
+ var ticks = calculator.getTicks([size]);
103
+ ticks.forEach((serie, si) => {
104
+ serie.forEach((v, i) => {
105
+ var s = calculator.map(v);
106
+
107
+ if (this.secondary) {
108
+ x1 = this.vertical ? bounds.r : s;
109
+ y1 = this.vertical ? s : bounds.t;
110
+ x2 = this.vertical ? bounds.r + tickSize : s;
111
+ y2 = this.vertical ? s : bounds.t - tickSize;
112
+ } else {
113
+ x1 = this.vertical ? bounds.l : s;
114
+ y1 = this.vertical ? s : bounds.b;
115
+ x2 = this.vertical ? bounds.l - tickSize : s;
116
+ y2 = this.vertical ? s : bounds.b + tickSize;
117
+ }
118
+
119
+ t.push(`M ${x1} ${y1} L ${x2} ${y2}`);
120
+
121
+ var x, y;
122
+ if (this.secondary) {
123
+ x = this.vertical ? bounds.r + this.labelOffset : s;
124
+ y = this.vertical ? s : bounds.t - this.labelOffset;
125
+ } else {
126
+ x = this.vertical ? bounds.l - this.labelOffset : s;
127
+ y = this.vertical ? s : bounds.b + this.labelOffset;
128
+ }
129
+
130
+ var transform = data.labelRotation ? `rotate(${data.labelRotation} ${x} ${y})` : null;
131
+ var formattedValue = valueFormatter(v);
132
+ var lines = labelFormatter ? labelFormatter(formattedValue, v) : this.wrapLines(formattedValue);
133
+ res.push(
134
+ <text
135
+ key={`label-${si}-${i}`}
136
+ className={labelClass}
137
+ style={data.labelStyle}
138
+ x={x}
139
+ y={y}
140
+ textAnchor={data.labelAnchor}
141
+ transform={transform}
142
+ >
143
+ {this.renderLabels(lines, x, this.labelDy, this.labelDx, offsetClass)}
144
+ </text>
145
+ );
146
+ });
147
+ });
148
+ }
149
+
150
+ if (!data.hideTicks) {
151
+ res[1] = (
152
+ <path
153
+ key="ticks"
154
+ className={CSS.expand(CSS.element(baseClass, "ticks"), data.tickClass)}
155
+ style={data.tickStyle}
156
+ d={t.join(" ")}
157
+ />
158
+ );
159
+ }
160
+
161
+ return res;
162
+ }
163
+
164
+ wrapLines(str) {
165
+ if (!this.labelWrap || typeof str != "string") return [{ text: str }];
166
+
167
+ let parts = str.split(" ");
168
+ if (parts.length == 0) return null;
169
+
170
+ let lines = [];
171
+ let line = null;
172
+ for (let i = 0; i < parts.length; i++) {
173
+ if (!line) line = parts[i];
174
+ else if (parts[i].length + line.length < this.labelMaxLineLength) line += " " + parts[i];
175
+ else {
176
+ lines.push({ text: line });
177
+ line = parts[i];
178
+ }
179
+ }
180
+ lines.push({ text: line });
181
+ return lines;
182
+ }
183
+
184
+ renderLabels(lines, x, dy, dx, offsetClass) {
185
+ let offset = this.labelLineCountDyFactor * (lines.length - 1);
186
+ let result = [];
187
+
188
+ if (lines.length > 1 && dy != null) {
189
+ result.push(
190
+ <tspan key={-2} className={offsetClass} dy={dy}>
191
+ _
192
+ </tspan>
193
+ );
194
+ }
195
+
196
+ lines.forEach((p, i) => {
197
+ result.push(
198
+ <tspan
199
+ key={i}
200
+ dy={lines.length > 1 ? `${i == 0 ? offset : this.labelLineHeight}em` : dy}
201
+ x={x}
202
+ style={p.style}
203
+ className={p.className}
204
+ dx={dx}
205
+ >
206
+ {p.text}
207
+ </tspan>
208
+ );
209
+ });
210
+ return result;
211
+ }
212
+
213
+ prepare(context, instance) {
214
+ super.prepare(context, instance);
215
+ var { bounds } = instance.data;
216
+ var [a, b] = !this.vertical ? [bounds.l, bounds.r] : [bounds.b, bounds.t];
217
+ instance.calculator.measure(a, b);
218
+ if (this.onMeasured) instance.invoke("onMeasured", instance.calculator.hash(), instance);
219
+ if (!instance.calculator.isSame(instance.cached.axis)) instance.markShouldUpdate(context);
220
+ }
221
+
222
+ cleanup(context, instance) {
223
+ var { cached, calculator } = instance;
224
+ cached.axis = calculator.hash();
225
+ }
226
+ }
227
+
228
+ Axis.prototype.anchors = "0 1 1 0";
229
+ Axis.prototype.styled = true;
230
+ Axis.prototype.vertical = false;
231
+ Axis.prototype.secondary = false;
232
+ Axis.prototype.inverted = false;
233
+ Axis.prototype.hidden = false;
234
+ Axis.prototype.hideLabels = false;
235
+ Axis.prototype.hideTicks = false;
236
+ Axis.prototype.hideLine = false;
237
+
238
+ Axis.prototype.tickSize = 3;
239
+ Axis.prototype.minTickDistance = 25;
240
+ Axis.prototype.minLabelDistanceVertical = 40;
241
+ Axis.prototype.minLabelDistanceHorizontal = 50;
242
+ Axis.prototype.labelOffset = 10;
243
+ Axis.prototype.labelRotation = 0;
244
+ Axis.prototype.labelAnchor = "auto";
245
+ Axis.prototype.labelDx = "auto";
246
+ Axis.prototype.labelDy = "auto";
247
+ Axis.prototype.labelWrap = false;
248
+ Axis.prototype.labelLineCountDyFactor = "auto";
249
+ Axis.prototype.labelLineHeight = 1;
250
+ Axis.prototype.labelMaxLineLength = 10;
251
+
252
+ Axis.namespace = "ui.svg.chart.axis";
@@ -1,23 +1,42 @@
1
- var Grouper = require('./Grouper').Grouper;
2
- import assert from 'assert';
1
+ var Grouper = require("./Grouper").Grouper;
2
+ import assert from "assert";
3
3
 
4
- describe('Grouper', function() {
5
- describe('grouping', function () {
6
- it('should work', function () {
7
- var data = [{
8
- key: 1,
9
- value: 1
10
- }, {
11
- key: 2,
12
- value: 2
13
- }];
4
+ describe("Grouper", function () {
5
+ describe("single grouping", function () {
6
+ it("should work", function () {
7
+ var data = [
8
+ { name: "John", age: 12 },
9
+ { name: "Jane", age: 12 },
10
+ ];
14
11
 
15
- var grouper = new Grouper({ key: {bind:'key'}});
12
+ var grouper = new Grouper({ name: { bind: "name" } });
16
13
  grouper.processAll(data);
17
14
 
18
15
  var results = grouper.getResults();
19
- //console.log(results);
16
+ // console.log(results);
20
17
  assert.equal(results.length, 2);
21
18
  });
22
19
  });
23
- });
20
+
21
+ describe("multi grouping", function () {
22
+ it("should work", function () {
23
+ var data = [
24
+ { name: "John", age: 12 },
25
+ { name: "John", age: 12 },
26
+ { name: "John", age: 13 },
27
+ { name: "John", age: 14 },
28
+ { name: "Jane", age: 12 },
29
+ { name: "Jane", age: 13 },
30
+ { name: "Jane", age: 14 },
31
+ ];
32
+
33
+ var grouper = new Grouper({ name: { bind: "name" }, age: { bind: "age" } });
34
+ grouper.processAll(data);
35
+
36
+ var results = grouper.getResults();
37
+ // console.log(results);
38
+ assert.equal(results.length, 6);
39
+ assert.equal(results[0].records.length, 2);
40
+ });
41
+ });
42
+ });
@@ -39,6 +39,13 @@ interface RepeaterProps extends PureContainerProps {
39
39
  /** Callback to create a filter function for given filter params. */
40
40
  onCreateFilter?: (filterParams: any, instance: Instance) => (record: Record) => boolean;
41
41
 
42
+ /**
43
+ * Callback function to track and retrieve displayed records.
44
+ * Accepts new records as a first argument.
45
+ * If onCreateFilter callback is defined, filtered records can be retrieved using this callback.
46
+ */
47
+ onTrackMappedRecords?: string | ((records: Record[], instance: Instance) => void);
48
+
42
49
  /** Options for data sorting. See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Collator */
43
50
  sortOptions?: CollatorOptions;
44
51