]> git.proxmox.com Git - extjs.git/blame - extjs/packages/charts/src/draw/SegmentTree.js
add extjs 6.0.1 sources
[extjs.git] / extjs / packages / charts / src / draw / SegmentTree.js
CommitLineData
6527f429
DM
1/**\r
2 * This class we summarize the data and returns it when required.\r
3 */\r
4Ext.define("Ext.draw.SegmentTree", {\r
5\r
6 config: {\r
7 strategy: "double"\r
8 },\r
9\r
10 /**\r
11 * @private\r
12 * @param {Object} result\r
13 * @param {Number} last\r
14 * @param {Number} dataX\r
15 * @param {Number} dataOpen\r
16 * @param {Number} dataHigh\r
17 * @param {Number} dataLow\r
18 * @param {Number} dataClose\r
19 */\r
20 time: function (result, last, dataX, dataOpen, dataHigh, dataLow, dataClose) {\r
21 var start = 0, lastOffset, lastOffsetEnd,\r
22 minimum = new Date(dataX[result.startIdx[0]]),\r
23 maximum = new Date(dataX[result.endIdx[last - 1]]),\r
24 extDate = Ext.Date,\r
25 units = [\r
26 [extDate.MILLI, 1, 'ms1', null],\r
27 [extDate.MILLI, 2, 'ms2', 'ms1'],\r
28 [extDate.MILLI, 5, 'ms5', 'ms1'],\r
29 [extDate.MILLI, 10, 'ms10', 'ms5'],\r
30 [extDate.MILLI, 50, 'ms50', 'ms10'],\r
31 [extDate.MILLI, 100, 'ms100', 'ms50'],\r
32 [extDate.MILLI, 500, 'ms500', 'ms100'],\r
33 [extDate.SECOND, 1, 's1', 'ms500'],\r
34 [extDate.SECOND, 10, 's10', 's1'],\r
35 [extDate.SECOND, 30, 's30', 's10'],\r
36 [extDate.MINUTE, 1, 'mi1', 's10'],\r
37 [extDate.MINUTE, 5, 'mi5', 'mi1'],\r
38 [extDate.MINUTE, 10, 'mi10', 'mi5'],\r
39 [extDate.MINUTE, 30, 'mi30', 'mi10'],\r
40 [extDate.HOUR, 1, 'h1', 'mi30'],\r
41 [extDate.HOUR, 6, 'h6', 'h1'],\r
42 [extDate.HOUR, 12, 'h12', 'h6'],\r
43 [extDate.DAY, 1, 'd1', 'h12'],\r
44 [extDate.DAY, 7, 'd7', 'd1'],\r
45 [extDate.MONTH, 1, 'mo1', 'd1'],\r
46 [extDate.MONTH, 3, 'mo3', 'mo1'],\r
47 [extDate.MONTH, 6, 'mo6', 'mo3'],\r
48 [extDate.YEAR, 1, 'y1', 'mo3'],\r
49 [extDate.YEAR, 5, 'y5', 'y1'],\r
50 [extDate.YEAR, 10, 'y10', 'y5'],\r
51 [extDate.YEAR, 100, 'y100', 'y10']\r
52 ], unitIdx, currentUnit,\r
53 plainStart = start,\r
54 plainEnd = last,\r
55 first = false,\r
56 startIdxs = result.startIdx,\r
57 endIdxs = result.endIdx,\r
58 minIdxs = result.minIdx,\r
59 maxIdxs = result.maxIdx,\r
60 opens = result.open,\r
61 closes = result.close,\r
62 minXs = result.minX,\r
63 minYs = result.minY,\r
64 maxXs = result.maxX,\r
65 maxYs = result.maxY,\r
66 i, current;\r
67\r
68 for (unitIdx = 0; last > start + 1 && unitIdx < units.length; unitIdx++) {\r
69 minimum = new Date(dataX[startIdxs[0]]);\r
70 currentUnit = units[unitIdx];\r
71 minimum = extDate.align(minimum, currentUnit[0], currentUnit[1]);\r
72 if (extDate.diff(minimum, maximum, currentUnit[0]) > dataX.length * 2 * currentUnit[1]) {\r
73 continue;\r
74 }\r
75 if (currentUnit[3] && result.map['time_' + currentUnit[3]]) {\r
76 lastOffset = result.map['time_' + currentUnit[3]][0];\r
77 lastOffsetEnd = result.map['time_' + currentUnit[3]][1];\r
78 } else {\r
79 lastOffset = plainStart;\r
80 lastOffsetEnd = plainEnd;\r
81 }\r
82\r
83 start = last;\r
84 current = minimum;\r
85 first = true;\r
86\r
87 startIdxs[last] = startIdxs[lastOffset];\r
88 endIdxs[last] = endIdxs[lastOffset];\r
89 minIdxs[last] = minIdxs[lastOffset];\r
90 maxIdxs[last] = maxIdxs[lastOffset];\r
91 opens[last] = opens[lastOffset];\r
92 closes[last] = closes[lastOffset];\r
93 minXs[last] = minXs[lastOffset];\r
94 minYs[last] = minYs[lastOffset];\r
95 maxXs[last] = maxXs[lastOffset];\r
96 maxYs[last] = maxYs[lastOffset];\r
97 current = Ext.Date.add(current, currentUnit[0], currentUnit[1]);\r
98\r
99 for (i = lastOffset + 1; i < lastOffsetEnd; i++) {\r
100 if (dataX[endIdxs[i]] < +current) {\r
101 endIdxs[last] = endIdxs[i];\r
102 closes[last] = closes[i];\r
103 if (maxYs[i] > maxYs[last]) {\r
104 maxYs[last] = maxYs[i];\r
105 maxXs[last] = maxXs[i];\r
106 maxIdxs[last] = maxIdxs[i];\r
107 }\r
108 if (minYs[i] < minYs[last]) {\r
109 minYs[last] = minYs[i];\r
110 minXs[last] = minXs[i];\r
111 minIdxs[last] = minIdxs[i];\r
112 }\r
113 } else {\r
114 last++;\r
115 startIdxs[last] = startIdxs[i];\r
116 endIdxs[last] = endIdxs[i];\r
117 minIdxs[last] = minIdxs[i];\r
118 maxIdxs[last] = maxIdxs[i];\r
119 opens[last] = opens[i];\r
120 closes[last] = closes[i];\r
121 minXs[last] = minXs[i];\r
122 minYs[last] = minYs[i];\r
123 maxXs[last] = maxXs[i];\r
124 maxYs[last] = maxYs[i];\r
125 current = Ext.Date.add(current, currentUnit[0], currentUnit[1]);\r
126 }\r
127 }\r
128 if (last > start) {\r
129 result.map['time_' + currentUnit[2]] = [start, last];\r
130 }\r
131 }\r
132 },\r
133\r
134 /**\r
135 * @private\r
136 * @param {Object} result\r
137 * @param {Number} position\r
138 * @param {Number} dataX\r
139 * @param {Number} dataOpen\r
140 * @param {Number} dataHigh\r
141 * @param {Number} dataLow\r
142 * @param {Number} dataClose\r
143 */\r
144 "double": function (result, position, dataX, dataOpen, dataHigh, dataLow, dataClose) {\r
145 var offset = 0, lastOffset, step = 1,\r
146 i,\r
147 startIdx,\r
148 endIdx,\r
149 minIdx,\r
150 maxIdx,\r
151 open,\r
152 close,\r
153 minX,\r
154 minY,\r
155 maxX,\r
156 maxY;\r
157 while (position > offset + 1) {\r
158 lastOffset = offset;\r
159 offset = position;\r
160 step += step;\r
161 for (i = lastOffset; i < offset; i += 2) {\r
162 if (i === offset - 1) {\r
163 startIdx = result.startIdx[i];\r
164 endIdx = result.endIdx[i];\r
165 minIdx = result.minIdx[i];\r
166 maxIdx = result.maxIdx[i];\r
167 open = result.open[i];\r
168 close = result.close[i];\r
169 minX = result.minX[i];\r
170 minY = result.minY[i];\r
171 maxX = result.maxX[i];\r
172 maxY = result.maxY[i];\r
173 } else {\r
174\r
175 startIdx = result.startIdx[i];\r
176 endIdx = result.endIdx[i + 1];\r
177 open = result.open[i];\r
178 close = result.close[i];\r
179 if (result.minY[i] <= result.minY[i + 1]) {\r
180 minIdx = result.minIdx[i];\r
181 minX = result.minX[i];\r
182 minY = result.minY[i];\r
183 } else {\r
184 minIdx = result.minIdx[i + 1];\r
185 minX = result.minX[i + 1];\r
186 minY = result.minY[i + 1];\r
187 }\r
188 if (result.maxY[i] >= result.maxY[i + 1]) {\r
189 maxIdx = result.maxIdx[i];\r
190 maxX = result.maxX[i];\r
191 maxY = result.maxY[i];\r
192 } else {\r
193 maxIdx = result.maxIdx[i + 1];\r
194 maxX = result.maxX[i + 1];\r
195 maxY = result.maxY[i + 1];\r
196 }\r
197 }\r
198 result.startIdx[position] = startIdx;\r
199 result.endIdx[position] = endIdx;\r
200 result.minIdx[position] = minIdx;\r
201 result.maxIdx[position] = maxIdx;\r
202 result.open[position] = open;\r
203 result.close[position] = close;\r
204 result.minX[position] = minX;\r
205 result.minY[position] = minY;\r
206 result.maxX[position] = maxX;\r
207 result.maxY[position] = maxY;\r
208 position++;\r
209 }\r
210 result.map['double_' + step] = [offset, position];\r
211 }\r
212 },\r
213\r
214 /**\r
215 * @private\r
216 */\r
217 none: Ext.emptyFn,\r
218\r
219 /**\r
220 * @private\r
221 *\r
222 * @param {Number} dataX\r
223 * @param {Number} dataOpen\r
224 * @param {Number} dataHigh\r
225 * @param {Number} dataLow\r
226 * @param {Number} dataClose\r
227 * @return {Object}\r
228 */\r
229 aggregateData: function (dataX, dataOpen, dataHigh, dataLow, dataClose) {\r
230 var length = dataX.length,\r
231 startIdx = [],\r
232 endIdx = [],\r
233 minIdx = [],\r
234 maxIdx = [],\r
235 open = [],\r
236 minX = [],\r
237 minY = [],\r
238 maxX = [],\r
239 maxY = [],\r
240 close = [],\r
241 result = {\r
242 startIdx: startIdx,\r
243 endIdx: endIdx,\r
244 minIdx: minIdx,\r
245 maxIdx: maxIdx,\r
246 open: open,\r
247 minX: minX,\r
248 minY: minY,\r
249 maxX: maxX,\r
250 maxY: maxY,\r
251 close: close\r
252 },\r
253 i;\r
254\r
255 for (i = 0; i < length; i++) {\r
256 startIdx[i] = i;\r
257 endIdx[i] = i;\r
258 minIdx[i] = i;\r
259 maxIdx[i] = i;\r
260 open[i] = dataOpen[i];\r
261 minX[i] = dataX[i];\r
262 minY[i] = dataLow[i];\r
263 maxX[i] = dataX[i];\r
264 maxY[i] = dataHigh[i];\r
265 close[i] = dataClose[i];\r
266 }\r
267\r
268 result.map = {\r
269 original: [0, length]\r
270 };\r
271 if (length) {\r
272 this[this.getStrategy()](result, length, dataX, dataOpen, dataHigh, dataLow, dataClose);\r
273 }\r
274 return result;\r
275 },\r
276\r
277 /**\r
278 * @private\r
279 * @param {Object} items\r
280 * @param {Number} start\r
281 * @param {Number} end\r
282 * @param {Number} key\r
283 * @return {*}\r
284 */\r
285 binarySearchMin: function (items, start, end, key) {\r
286 var dx = this.dataX;\r
287 if (key <= dx[items.startIdx[0]]) {\r
288 return start;\r
289 }\r
290 if (key >= dx[items.startIdx[end - 1]]) {\r
291 return end - 1;\r
292 }\r
293 while (start + 1 < end) {\r
294 var mid = (start + end) >> 1,\r
295 val = dx[items.startIdx[mid]];\r
296 if (val === key) {\r
297 return mid;\r
298 } else if (val < key) {\r
299 start = mid;\r
300 } else {\r
301 end = mid;\r
302 }\r
303 }\r
304 return start;\r
305 },\r
306\r
307 /**\r
308 * @private\r
309 * @param {Object} items\r
310 * @param {Number} start\r
311 * @param {Number} end\r
312 * @param {Number} key\r
313 * @return {*}\r
314 */\r
315 binarySearchMax: function (items, start, end, key) {\r
316 var dx = this.dataX;\r
317 if (key <= dx[items.endIdx[0]]) {\r
318 return start;\r
319 }\r
320 if (key >= dx[items.endIdx[end - 1]]) {\r
321 return end - 1;\r
322 }\r
323 while (start + 1 < end) {\r
324 var mid = (start + end) >> 1,\r
325 val = dx[items.endIdx[mid]];\r
326 if (val === key) {\r
327 return mid;\r
328 } else if (val < key) {\r
329 start = mid;\r
330 } else {\r
331 end = mid;\r
332 }\r
333 }\r
334 return end;\r
335 },\r
336\r
337 constructor: function (config) {\r
338 this.initConfig(config);\r
339 },\r
340\r
341 /**\r
342 * Sets the data of the segment tree.\r
343 * @param {Number} dataX\r
344 * @param {Number} dataOpen\r
345 * @param {Number} dataHigh\r
346 * @param {Number} dataLow\r
347 * @param {Number} dataClose\r
348 */\r
349 setData: function (dataX, dataOpen, dataHigh, dataLow, dataClose) {\r
350 if (!dataHigh) {\r
351 dataClose = dataLow = dataHigh = dataOpen;\r
352 }\r
353 this.dataX = dataX;\r
354 this.dataOpen = dataOpen;\r
355 this.dataHigh = dataHigh;\r
356 this.dataLow = dataLow;\r
357 this.dataClose = dataClose;\r
358 if (dataX.length === dataHigh.length &&\r
359 dataX.length === dataLow.length) {\r
360 this.cache = this.aggregateData(dataX, dataOpen, dataHigh, dataLow, dataClose);\r
361 }\r
362 },\r
363\r
364 /**\r
365 * Returns the minimum range of data that fits the given range and step size.\r
366 *\r
367 * @param {Number} min\r
368 * @param {Number} max\r
369 * @param {Number} estStep\r
370 * @return {Object} The aggregation information.\r
371 * @return {Number} return.start\r
372 * @return {Number} return.end\r
373 * @return {Object} return.data The aggregated data\r
374 */\r
375 getAggregation: function (min, max, estStep) {\r
376 if (!this.cache) {\r
377 return null;\r
378 }\r
379 var minStep = Infinity,\r
380 range = this.dataX[this.dataX.length - 1] - this.dataX[0],\r
381 cacheMap = this.cache.map,\r
382 result = cacheMap.original,\r
383 name, positions, ln, step, minIdx, maxIdx;\r
384\r
385 for (name in cacheMap) {\r
386 positions = cacheMap[name];\r
387 ln = positions[1] - positions[0] - 1;\r
388 step = range / ln;\r
389 if (estStep <= step && step < minStep) {\r
390 result = positions;\r
391 minStep = step;\r
392 }\r
393 }\r
394 minIdx = Math.max(this.binarySearchMin(this.cache, result[0], result[1], min), result[0]);\r
395 maxIdx = Math.min(this.binarySearchMax(this.cache, result[0], result[1], max) + 1, result[1]);\r
396 return {\r
397 data: this.cache,\r
398 start: minIdx,\r
399 end: maxIdx\r
400 };\r
401 }\r
402});\r