@millistream/millistream-widgets 1.0.3 → 1.0.5

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 (2) hide show
  1. package/millistream-widgets.js +1319 -994
  2. package/package.json +1 -1
@@ -1,3 +1,185 @@
1
+ (function(prototype) {
2
+
3
+ var pixelRatio = (function() {
4
+ var canvas = document.createElement('canvas'),
5
+ context = canvas.getContext('2d');
6
+ })(),
7
+
8
+ forEach = function(obj, func) {
9
+ for (var p in obj) {
10
+ if (obj.hasOwnProperty(p)) {
11
+ func(obj[p], p);
12
+ }
13
+ }
14
+ },
15
+
16
+ ratioArgs = {
17
+
18
+
19
+ 'strokeRect': 'all',
20
+ 'moveTo': 'all',
21
+ 'lineTo': 'all',
22
+ 'arc': [0, 1, 2],
23
+ 'arcTo': 'all',
24
+ 'bezierCurveTo': 'all',
25
+ 'isPointinPath': 'all',
26
+ 'isPointinStroke': 'all',
27
+ 'quadraticCurveTo': 'all',
28
+ 'rect': 'all',
29
+ 'translate': 'all',
30
+ 'createRadialGradient': 'all',
31
+
32
+ };
33
+
34
+ if (pixelRatio === 1) return;
35
+
36
+ function getPixelRatio() {
37
+ var backingStore = this.backingStorePixelRatio ||
38
+ this.webkitBackingStorePixelRatio ||
39
+ this.mozBackingStorePixelRatio ||
40
+ this.msBackingStorePixelRatio ||
41
+ this.oBackingStorePixelRatio ||
42
+ this.backingStorePixelRatio || 1;
43
+
44
+ return (window.devicePixelRatio || 1) / backingStore;
45
+
46
+ };
47
+
48
+ forEach(ratioArgs, function(value, key) {
49
+ prototype[key] = (function(_super) {
50
+ return function() {
51
+ var i, len,
52
+ args = Array.prototype.slice.call(arguments);
53
+ if (key == 'lineTo' || key == 'moveTo') {
54
+ args = args.map(function(a) {
55
+ return a;
56
+ });
57
+ } else
58
+ if (value === 'all') {
59
+ args = args.map(function(a) {
60
+ return a * getPixelRatio();
61
+ });
62
+ } else if (Array.isArray(value)) {
63
+ for (i = 0, len = value.length; i < len; i++) {
64
+ args[value[i]] *= getPixelRatio();
65
+ }
66
+ }
67
+
68
+ return _super.apply(this, args);
69
+ };
70
+ })(prototype[key]);
71
+ });
72
+
73
+
74
+ prototype.stroke = (function(_super) {
75
+ return function() {
76
+ this.lineWidth *= getPixelRatio();
77
+ _super.apply(this, arguments);
78
+ this.lineWidth /= getPixelRatio();
79
+ };
80
+ })(prototype.stroke);
81
+
82
+ prototype.measureText = (function(_super) {
83
+ return function() {
84
+ var args = Array.prototype.slice.call(arguments);
85
+
86
+ var tmp = this.font;
87
+ this.font = this.font.replace(
88
+ /(\d+)(px|em|rem|pt)/g,
89
+ function(w, m, u) {
90
+ return Math.floor(m * getPixelRatio()) + u;
91
+ }
92
+ );
93
+ var i = _super.apply(this, args);
94
+
95
+ this.font = tmp;
96
+ return i;
97
+ };
98
+ })(prototype.measureText);
99
+
100
+
101
+ prototype.fillText = (function(_super) {
102
+ return function() {
103
+ var args = Array.prototype.slice.call(arguments);
104
+ var tmp = this.font;
105
+ this.font = this.font.replace(
106
+ /(\d+)(px|em|rem|pt)/g,
107
+ function(w, m, u) {
108
+ return (m * getPixelRatio()) + u;
109
+ }
110
+ );
111
+ _super.apply(this, args);
112
+ this.font = tmp;
113
+ };
114
+ })(prototype.fillText);
115
+
116
+ prototype.strokeText = (function(_super) {
117
+ return function() {
118
+ var args = Array.prototype.slice.call(arguments);
119
+
120
+ args[1] *= getPixelRatio();
121
+ args[2] *= getPixelRatio();
122
+ var tmp = this.font;
123
+ this.font = this.font.replace(
124
+ /(\d+)(px|em|rem|pt)/g,
125
+ function(w, m, u) {
126
+ return (m * getPixelRatio()) + u;
127
+ }
128
+ );
129
+
130
+ _super.apply(this, args);
131
+ this.font = tmp;
132
+ };
133
+ })(prototype.strokeText);
134
+
135
+ })(CanvasRenderingContext2D.prototype);
136
+
137
+ (function(prototype) {
138
+ var context = null;
139
+
140
+ function getPixelRatio() {
141
+ backingStore = context.backingStorePixelRatio ||
142
+ context.webkitBackingStorePixelRatio ||
143
+ context.mozBackingStorePixelRatio ||
144
+ context.msBackingStorePixelRatio ||
145
+ context.oBackingStorePixelRatio ||
146
+ context.backingStorePixelRatio || 1;
147
+
148
+ return (window.devicePixelRatio || 1) / backingStore;
149
+
150
+ }
151
+ prototype.getContext = (function(_super) {
152
+ return function(type) {
153
+
154
+ context = _super.call(this, type);
155
+
156
+ if (type === '2d') {
157
+
158
+
159
+ var ratio = getPixelRatio();
160
+ if (ratio > 1) {
161
+ this.style.height = this.height + 'px';
162
+ this.style.width = this.width + 'px';
163
+ this.width *= ratio;
164
+ this.height *= ratio;
165
+ }
166
+ }
167
+
168
+ return context;
169
+ };
170
+ })(prototype.getContext);
171
+
172
+ prototype.setRect = (function(height, width) {
173
+ if (context == null) return;
174
+ this.style.height = height + 'px';
175
+ this.style.width = width + 'px';
176
+ this.width = width * getPixelRatio();
177
+ this.height = height * getPixelRatio();
178
+ });
179
+
180
+ })(HTMLCanvasElement.prototype);
181
+
182
+
1
183
  function Milli_Chart(settings) {
2
184
  "use strict";
3
185
  var _this = this;
@@ -7,39 +189,52 @@ function Milli_Chart(settings) {
7
189
  _this.scaleinfoY2 = {};
8
190
  _this.instruments = [];
9
191
  _this.movingAverage = [];
192
+ _this.unsubscriptions = {};
193
+
10
194
  _this.settings = {
11
195
  adjusted: true,
196
+ absoluteScaling: false,
197
+ indicators: [],
12
198
  autodraw: true,
13
199
  chartlen: '1d',
200
+ closePriceIndicator: false,
14
201
  compress: 1,
202
+ curveOnTop: true,
15
203
  dateformat: 'd/m',
16
- drawxaxis: true, // TODO: 0 no, 1 yes, 2 yeas with markers (3px lines)
204
+ drawxaxis: true,
17
205
  drawyaxis: true,
18
206
  drawy2axis: false,
19
207
  enablezoom: true,
20
208
  fields: ['name', 'tradecurrency', 'time', 'date', 'tradeprice', 'tradequantity', 'marketopen', 'marketclose'],
21
209
  fillchart: false,
22
- gridVerticalLines: true, // 0 off, 1 draw grid lines ,2 fillrect modulo
210
+ gridVerticalLines: true,
23
211
  gridVerticalLinesStyle: 'line',
24
212
  gridHorizontalLines: true,
25
213
  gridHorizontalLinesStyle: 'dash',
26
214
  hcurve: false,
27
215
  historylen: null,
28
216
  instrument: null,
29
- intradaydates: false,
217
+ intradayDatePos: { x: 'center', y: 'bottom', orientation: 'horizontal', dateformat: 'd mmm' },
30
218
  intradaylen: null,
31
- messagetypes: 4, // not a setting should always be 4 (trades)
219
+ messagetypes: 1030,
32
220
  nochartlabel: 'No data to draw on',
33
221
  onreadyCallback: null,
34
- startdate: null, // no setting, set in request code
35
- //startdateintraday: null,
222
+ previousDayClose: true,
223
+ pricetype: undefined,
36
224
  streaming: false,
37
225
  target: null,
38
226
  timeformat: 'HH:mm',
39
227
  xhr: false,
40
228
  yearLabelsPos: 'bottom',
229
+ priceIndicator: false,
230
+ tooltip: {
231
+ display: 'block'
232
+ },
233
+ xAxisSpacing: 0,
234
+ yAxisSpacing: 4,
235
+ xAxisModulo: 1
41
236
  };
42
- _this.unsubscriptions = {};
237
+ var m_startdate = null;
43
238
  var m_chartspaces = {
44
239
  chart: {
45
240
  percent: 100,
@@ -50,18 +245,15 @@ function Milli_Chart(settings) {
50
245
  height: 0
51
246
  }
52
247
  };
53
- var m_dummyDiv = null; // dummy div For chartclasses
54
- var m_requestid = 0;
248
+ var m_dummyDiv = null;
55
249
  var m_canvas = null;
56
250
  var m_ctx = null;
57
- var m_tradedates = [];
58
- var m_datapoints = []; // for mouseover
251
+ var m_datapoints = [];
59
252
  var m_dataPoints = {
60
253
  arr: [],
61
254
  map: new Map()
62
255
  };
63
- var m_analyzisMethod = new Map();
64
- var m_analyzisIndex = 0;
256
+
65
257
  var m_resizing = {
66
258
  resizing: false,
67
259
  width: 0,
@@ -84,13 +276,12 @@ function Milli_Chart(settings) {
84
276
  isZooming: false
85
277
  };
86
278
  var m_lastDrawnInstrument = -1;
87
- var m_months = ['Jan', 'Feb', 'Mar', 'Apr', 'Maj', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dec'];
279
+ var m_priceIndicator = undefined;
88
280
 
89
281
  MillistreamWidgetApi_AssignObject(MillistreamWidgetSettings, _this.settings);
90
282
  if (settings) {
91
283
  MillistreamWidgetApi_AssignObject(settings, _this.settings);
92
284
  }
93
-
94
285
  var m_chartCss = {
95
286
  backgroundColor: '#fffcf8',
96
287
  marginTop: 0,
@@ -105,7 +296,8 @@ function Milli_Chart(settings) {
105
296
  fontSize: '10px',
106
297
  fontWeight: 'bolder',
107
298
  fontFamily: 'SuecaSans',
108
- color: 'rgba(37, 45, 64, 0.24)'
299
+ color: 'rgba(37, 45, 64, 0.24)',
300
+ paddingTop: 10
109
301
  };
110
302
  if (_this.settings.horizontalLegendStyle) {
111
303
  MillistreamWidgetApi_AssignObject(_this.settings.horizontalLegendStyle, m_xLegendCss);
@@ -122,10 +314,11 @@ function Milli_Chart(settings) {
122
314
  if (_this.settings.verticalLegendStyle) {
123
315
  MillistreamWidgetApi_AssignObject(_this.settings.verticalLegendStyle, m_yLegendCss);
124
316
  }
125
-
126
317
  var m_y2LegendCss = {
127
318
  float: "right",
319
+ textAlign: 'right'
128
320
  };
321
+ MillistreamWidgetApi_AssignObject(_this.settings.verticalLegendStyle, m_y2LegendCss);
129
322
  if (_this.settings.verticalLegend2Style) {
130
323
  MillistreamWidgetApi_AssignObject(_this.settings.verticalLegend2Style, m_y2LegendCss);
131
324
  }
@@ -144,7 +337,7 @@ function Milli_Chart(settings) {
144
337
  }
145
338
  var m_instrumentCss = [{
146
339
  color: '#E2507A',
147
- //backgroundImage: 'linear-gradient(rgba(226, 80, 122, 0.6),rgba(226, 80, 122, 0))',
340
+
148
341
  width: 1
149
342
  }, {
150
343
  color: '#ff0000',
@@ -169,6 +362,9 @@ function Milli_Chart(settings) {
169
362
  MillistreamWidgetApi_AssignObject(_this.settings.compare3Style, m_instrumentCss[3]);
170
363
  }
171
364
 
365
+ function getScaledSetting(setting) {
366
+ return parseInt(setting) * window.devicePixelRatio;
367
+ }
172
368
  _this.get_lang_text = function(string) {
173
369
  return string;
174
370
  };
@@ -190,10 +386,10 @@ function Milli_Chart(settings) {
190
386
  }
191
387
 
192
388
  function dateDiffInDays(a, b) {
193
- // Discard the time and time-zone information.
389
+
194
390
  const utc1 = Date.UTC(a.getFullYear(), a.getMonth(), a.getDate());
195
391
  const utc2 = Date.UTC(b.getFullYear(), b.getMonth(), b.getDate());
196
- return Math.floor((utc2 - utc1) / 86400000); // ms per day
392
+ return Math.floor((utc2 - utc1) / 86400000);
197
393
  }
198
394
 
199
395
  function findFirstWeekDay(date) {
@@ -206,35 +402,8 @@ function Milli_Chart(settings) {
206
402
  return tmp;
207
403
  }
208
404
 
209
- function subtractMonth(date, months) {
210
- var startDate = new Date().getTime();
211
- for (var i = 0; i < months; i++) {
212
- var d = new Date(startDate);
213
- switch (d.getMonth() + 1) {
214
- case 1:
215
- case 3:
216
- case 5:
217
- case 7:
218
- case 8:
219
- case 10:
220
- case 12:
221
- startDate -= 86400000 * 31;
222
- break;
223
- case 4:
224
- case 6:
225
- case 9:
226
- case 11:
227
- startDate -= 86400000 * 30;
228
- break;
229
- case 2:
230
- startDate -= 86400000 * 30; // remember leapyear
231
- break;
232
- }
233
- }
234
- return new Date(startDate);
235
- }
236
-
237
405
  function getFontSize(obj) {
406
+
238
407
  return parseInt(obj.fontSize);
239
408
  }
240
409
 
@@ -273,7 +442,7 @@ function Milli_Chart(settings) {
273
442
  case 'b dd yyyy':
274
443
  return ctx.measureText("MMM 88 8888").width;
275
444
  case 'dd/mm':
276
- return ctx.measureText("dd/mm").width;
445
+ return ctx.measureText("DD/MM").width;
277
446
  default:
278
447
  return ctx.measureText(format).width;
279
448
  }
@@ -291,20 +460,6 @@ function Milli_Chart(settings) {
291
460
 
292
461
  function numDigits(x) {
293
462
  return Math.ceil(Math.log10(Math.abs(x)));
294
-
295
- /* x = Math.abs(x);
296
- return (x < 1 ? 0 :
297
- (x < 10 ? 1 :
298
- (x < 100 ? 2 :
299
- (x < 1000 ? 3 :
300
- (x < 10000 ? 4 :
301
- (x < 100000 ? 5 :
302
- (x < 1000000 ? 6 :
303
- (x < 10000000 ? 7 :
304
- (x < 100000000 ? 8 :
305
- (x < 1000000000 ? 9 :
306
- 10))))))))));
307
- */
308
463
  }
309
464
 
310
465
  function businessDaysSubtraction(date, days) {
@@ -404,26 +559,30 @@ function Milli_Chart(settings) {
404
559
  _this.scaleinfoY2.highValue = null;
405
560
  _this.scaleinfoY.lowLowerChart = null;
406
561
  _this.scaleinfoY.highLowerChart = null;
407
- var firstvalue = null;
408
-
562
+ var data, i;
409
563
  for (var s = 0; s < _this.instruments.length; s++) {
410
564
  if (_this.instruments[s].insref == 0) continue;
411
- var data = _this.instruments[s][_this.scaleinfoY.type];
565
+ _this.instruments[s].startValue = null;
566
+ data = _this.instruments[s][_this.scaleinfoY.type];
412
567
  if (_this.scaleinfoY.type != 'history') {
413
- if (_this.settings.chartlen == '1d' || _this.settings.chartlen == '0d' && !m_zoom.mousedown.timestamp) {
414
- firstvalue = parseFloat(_this.instruments[s].closeprice1d) * _this.instruments[s].factor;
568
+ if ((_this.settings.chartlen == '1d' || _this.settings.chartlen == '0d') && !m_zoom.mousedown.timestamp) {
569
+ _this.instruments[s].startValue = parseFloat(_this.instruments[s].closeprice1d) * _this.instruments[s].factor;
415
570
  }
416
571
  }
417
572
  var quantity = 0;
418
- for (var i = 0; i < data.length; i++) {
419
- // only calc on visible data
573
+
574
+ for (i = 0; i < data.length; i++) {
575
+
420
576
  var price = data[i].price * _this.instruments[s].factor;
421
577
  quantity = 0;
422
578
  if (data[i].quantity !== 'undefined') {
423
579
  quantity = data[i].quantity;
424
580
  }
425
581
  if (data[i].timestamp < _this.scaleinfoX.startTimeStamp) {
426
- if (_this.scaleinfoY.type == 'history') firstvalue = price;
582
+ if (_this.scaleinfoY.type == 'history') _this.instruments[s].startValue = price;
583
+ else if (_this.settings.chartlen != '1d' && _this.settings.chartlen != '0d' && !m_zoom.mousedown.timestamp) {
584
+ _this.instruments[s].startValue = price;
585
+ }
427
586
  continue;
428
587
  }
429
588
  if (data[i].timestamp > _this.scaleinfoX.endTimeStamp) {
@@ -431,36 +590,52 @@ function Milli_Chart(settings) {
431
590
  }
432
591
 
433
592
  if (_this.scaleinfoY.type != 'history' && (data[i].timestamp % 86400000 < _this.instruments[0].opentimestamp || data[i].timestamp % 86400000 > _this.instruments[0].closetimestamp)) {
434
- // stämmer detta kan det bli överlapp vid sommartid/vintertid?
593
+
435
594
  continue;
436
595
  }
437
596
 
438
- if (firstvalue == null) {
597
+ if (_this.instruments[s].startValue == null) {
439
598
  if (_this.scaleinfoY.type == 'history') {
440
- firstvalue = price;
599
+ _this.instruments[s].startValue = price;
441
600
  } else {
442
601
  if (isToday(new Date(data[i].timestamp)) && !m_zoom.mousedown.timestamp) {
443
- firstvalue = parseFloat(_this.instruments[s].closeprice1d) * _this.instruments[s].factor;
444
- } else
445
- firstvalue = price;
602
+ _this.instruments[s].startValue = parseFloat(_this.instruments[s].closeprice1d) * _this.instruments[s].factor;
603
+ } else {
604
+ _this.instruments[s].startValue = price;
605
+ }
446
606
  }
447
607
  }
448
608
  if (_this.scaleinfoY.lowValue == null || _this.scaleinfoY.lowValue > price) _this.scaleinfoY.lowValue = price;
449
609
  if (_this.scaleinfoY.highValue == null || _this.scaleinfoY.highValue < price) _this.scaleinfoY.highValue = price;
450
- var diff = (price - firstvalue) / firstvalue * 100;
610
+ var diff = (price - _this.instruments[s].startValue);
611
+ if (diff != 0) diff = diff / _this.instruments[s].startValue * 100;
612
+ if (_this.instruments[s].startValue == null) diff = 0;
451
613
  data[i].diff = diff;
614
+
452
615
  if (_this.scaleinfoY2.lowValue == null || _this.scaleinfoY2.lowValue > diff) _this.scaleinfoY2.lowValue = diff;
453
616
  if (_this.scaleinfoY2.highValue == null || _this.scaleinfoY2.highValue < diff) _this.scaleinfoY2.highValue = diff;
454
617
  if (_this.scaleinfoY.lowLowerChart == null || _this.scaleinfoY.lowLowerChart > quantity) _this.scaleinfoY.lowLowerChart = quantity;
455
618
  if (_this.scaleinfoY.highLowerChart == null || _this.scaleinfoY.highLowerChart < quantity) _this.scaleinfoY.highLowerChart = quantity;
456
619
  }
457
- if (_this.settings.chartlen == '1d' || _this.settings.chartlen == '0d') { // if closeprice is used calch high/low on it
620
+ if ((_this.settings.chartlen == '1d' || _this.settings.chartlen == '0d') && !m_zoom.mousedown.timestamp) {
458
621
  var cp = parseFloat(_this.instruments[s].closeprice1d) * _this.instruments[s].factor;
459
622
  if (_this.scaleinfoY.lowValue > cp) _this.scaleinfoY.lowValue = cp;
460
623
  else
461
624
  if (_this.scaleinfoY.highValue < cp) _this.scaleinfoY.highValue = cp;
462
625
  }
626
+ if (_this.scaleinfoY.type != 'history') {
627
+ if (_this.scaleinfoY2.lowValue > 0) {
628
+ _this.scaleinfoY2.lowValue = 0;
629
+ } else {
630
+ if (_this.scaleinfoY2.highValue < 0) _this.scaleinfoY2.highValue = 0;
631
+ }
632
+ }
633
+ if (_this.instruments[s].startValue) {
634
+ if (_this.instruments[s].startValue > _this.scaleinfoY.highValue) _this.scaleinfoY.highValue = _this.instruments[s].startValue;
635
+ if (_this.instruments[s].startValue < _this.scaleinfoY.lowValue) _this.scaleinfoY.lowValue = _this.instruments[s].startValue;
636
+ }
463
637
  }
638
+
464
639
  if (_this.scaleinfoY.lowValue == null) {
465
640
  _this.scaleinfoY.lowValue = 0;
466
641
  _this.scaleinfoY.highValue = 100;
@@ -471,28 +646,24 @@ function Milli_Chart(settings) {
471
646
  _this.scaleinfoY.lowValue -= 1;
472
647
  _this.scaleinfoY.highValue += 1;
473
648
  }
474
- // do we have any analyzis we need to take into account
475
-
476
- for (const [key, a] of m_analyzisMethod.entries()) {
477
- var data;
478
- if (_this.scaleinfoY.type == 'history') data = a.history;
479
- else data = a.trades;
480
- for (var i = 0; i < data.length; i++) {
481
- if (data[i].timestamp < _this.scaleinfoX.startTimeStamp) {
649
+
650
+ for (i = 0; i < _this.settings.indicators.length; i++) {
651
+ if (_this.scaleinfoY.type == 'history') data = _this.settings.indicators[i].history;
652
+ else data = _this.settings.indicators[i].trades;
653
+ for (var s = 0; s < data.length; s++) {
654
+ if (data[s].timestamp < _this.scaleinfoX.startTimeStamp) {
482
655
  continue;
483
656
  }
484
- if (data[i].timestamp > _this.scaleinfoX.endTimeStamp) {
657
+ if (data[s].timestamp > _this.scaleinfoX.endTimeStamp) {
485
658
  break;
486
659
  }
487
- if (typeof data[i].datapoints !== 'undefined') {
660
+ if (typeof data[s].datapoints !== 'undefined') {
488
661
  for (var x = 0; x < data[i].datapoints.length; x++) {
489
- if (data[i].datapoints[x] < _this.scaleinfoY.lowValue) _this.scaleinfoY.lowValue = data[i].datapoints[x];
662
+ if (data[s].datapoints[x] < _this.scaleinfoY.lowValue) _this.scaleinfoY.lowValue = data[s].datapoints[x];
490
663
  else
491
- if (data[i].datapoints[x] > _this.scaleinfoY.highValue) _this.scaleinfoY.highValue = data[i].datapoints[x];
664
+ if (data[s].datapoints[x] > _this.scaleinfoY.highValue) _this.scaleinfoY.highValue = data[s].datapoints[x];
492
665
  }
493
666
  }
494
- if (data[i].price < _this.scaleinfoY.lowValue) _this.scaleinfoY.lowValue = data[i].price;
495
- if (data[i].price > _this.scaleinfoY.highValue) _this.scaleinfoY.highValue = data[i].price;
496
667
  }
497
668
  }
498
669
  return 1;
@@ -548,7 +719,7 @@ function Milli_Chart(settings) {
548
719
  var maxValue = _this.scaleinfoY.highLowerChart == 0 ? 100 : _this.scaleinfoY.highLowerChart + (tickSize * 0.2);
549
720
  var valuePerPixel = lineLength / maxValue;
550
721
  if (isNaN(valuePerPixel) || !isFinite(valuePerPixel)) {
551
- console.log('cant draw valuePerPixel' + valuePerPixel);
722
+
552
723
  return false;
553
724
  }
554
725
  var value = 0;
@@ -569,7 +740,7 @@ function Milli_Chart(settings) {
569
740
  m_ctx.closePath();
570
741
  m_ctx.restore();
571
742
  } else
572
- if (_this.settings.drawyaxis == true && markers == true) { // draw legenditem markers for price
743
+ if (_this.settings.drawyaxis == true && markers == true) {
573
744
  m_ctx.beginPath();
574
745
  m_ctx.moveTo(m_chartspaces.lowerChart.left, y + 0.5);
575
746
  m_ctx.lineTo(m_chartspaces.lowerChart.left + 3, y + 0.5);
@@ -581,7 +752,7 @@ function Milli_Chart(settings) {
581
752
  var label = formatLargeNumber(value, 0, _this);
582
753
  var textpos = x - 5;
583
754
  if (m_yLegendCss.verticalAlign == 'top') {
584
- if (y - (getFontSize(m_yLegendCss)) > 0) // dont draw if cropped
755
+ if (y - (getFontSize(m_yLegendCss)) > 0)
585
756
  m_ctx.fillText(label, textpos, y - ((getFontSize(m_yLegendCss) + 2)));
586
757
  } else
587
758
  m_ctx.fillText(label, textpos, y - (getFontSize(m_yLegendCss) / 2));
@@ -599,7 +770,7 @@ function Milli_Chart(settings) {
599
770
  m_ctx.fillStyle = m_yLegendCss.color;
600
771
  var lineLen = m_chartspaces.lowerChart.bottom - m_chartspaces.lowerChart.top;
601
772
  var numticks = lineLen / (getFontSize(m_yLegendCss) * 2);
602
- if (numticks > 8) numticks = 8; // limit to 8 items on Y legend ( this is not an absolut count, since we calculate nice legend numbers
773
+ if (numticks > 8) numticks = 8;
603
774
 
604
775
  m_ctx.beginPath();
605
776
  m_ctx.strokeStyle = m_gridVerticalCss.color;
@@ -607,23 +778,97 @@ function Milli_Chart(settings) {
607
778
  m_ctx.lineTo(m_chartspaces.lowerChart.left + 0.5, m_chartspaces.lowerChart.bottom);
608
779
  m_ctx.stroke();
609
780
  m_ctx.closePath();
610
- //m_ctx.strokeStyle = m_gridHorizontalCss.color;
611
781
  var x = m_chartspaces.lowerChart.left - 3;
612
782
  drawYLegendLower(x, numticks, lineLen, true);
613
783
  m_ctx.restore();
614
784
  }
615
785
 
616
- function drawYLegend(si, x, side, gridHorizontalLines, number) {
786
+ function checkYLegendSpace(y, text) {
787
+
788
+ if (y - (getFontSize(m_yLegendCss)) - m_chartspaces.chart.top < 0) return false;
789
+ if (y > m_chartspaces.chart.bottom) return false;
790
+ return true;
791
+ }
792
+
793
+ function drawY2Legend(x) {
794
+ if (_this.settings.absoluteScaling == true) {
795
+ for (var s = 1; s < _this.instruments.length; s++) {
796
+ if (_this.instruments[s].insref != 0) return;
797
+ }
798
+ }
799
+ if (_this.instruments[0].startValue == null || (_this.scaleinfoY2.highValue == 100 && _this.scaleinfoY2.lowValue == 0)) return false;
800
+ _this.scaleinfoY2.maxValue = _this.scaleinfoY2.highValue + (_this.scaleinfoY2.tickSize * 0.2);
801
+ _this.scaleinfoY2.minValue = _this.scaleinfoY2.lowValue + (_this.scaleinfoY2.tickSize * 0.2);
802
+ m_ctx.font = m_y2LegendCss.fontWeight + ' ' + m_y2LegendCss.fontSize + ' ' + m_y2LegendCss.fontFamily;
803
+ var value;
804
+ if (_this.scaleinfoY2.highValue == _this.scaleinfoY2.lowValue) {
805
+ _this.scaleinfoY2.maxValue += _this.scaleinfoY2.tickSize;
806
+ _this.scaleinfoY2.minValue -= _this.scaleinfoY2.tickSize;
807
+ value = Math.abs(_this.scaleinfoY2.minValue);
808
+ } else {
809
+ if (_this.scaleinfoY2.minValue > 0)
810
+ value = _this.scaleinfoY2.minValue - fmod(Math.abs(_this.scaleinfoY2.minValue), _this.scaleinfoY2.tickSize) + _this.scaleinfoY2.tickSize;
811
+ else {
812
+ value = _this.scaleinfoY2.minValue + fmod(Math.abs(_this.scaleinfoY2.minValue), _this.scaleinfoY2.tickSize) - _this.scaleinfoY2.tickSize;
813
+ }
814
+ }
815
+ var startPrice = _this.instruments[0].startValue;
816
+ if (startPrice == 0) return;
817
+ var textpos = x;
818
+ var count = 0;
819
+ for (;;) {
820
+ if (count++ > 10) {
821
+
822
+ break;
823
+ }
824
+ var v;
825
+ if (startPrice < 0)
826
+ v = startPrice - (startPrice * (value / 100));
827
+ else
828
+ v = startPrice + (startPrice * (value / 100));
829
+ var y = Math.round(m_chartspaces.chart.height - getScaledSetting(m_chartCss.marginBottom) - ((v - _this.scaleinfoY.minValue) * _this.scaleinfoY.valuePerPixel));
830
+
831
+ if (y <= m_chartspaces.chart.top) break;
832
+
833
+ if (y <= m_chartspaces.chart.bottom) {
834
+ if (_this.settings.drawy2axis == true) {
835
+ m_ctx.beginPath();
836
+ m_ctx.moveTo(x, y + 0.5);
837
+ if ((m_y2LegendCss.float == 'left' && m_y2LegendCss.textAlign == 'left') || (m_y2LegendCss.float == 'right' && m_y2LegendCss.textAlign == 'left')) {
838
+ m_ctx.lineTo(x - 3, y + 0.5);
839
+ textpos = x - 4;
840
+ } else {
841
+ m_ctx.lineTo(x + 3, y + 0.5);
842
+ textpos = x + 4;
843
+ }
844
+ m_ctx.stroke();
845
+ m_ctx.closePath();
846
+ }
847
+ var label = formatNiceNumber(value, _this.settings.thousandseparator, _this.settings.decimalseparator, _this.scaleinfoY2.decimals, true) + '%';
848
+ if (m_y2LegendCss.verticalAlign == 'top') {
849
+ if (checkYLegendSpace(y, label))
850
+ m_ctx.fillText(label, textpos, y - ((getFontSize(m_y2LegendCss) + 2)));
851
+ } else {
852
+ if (checkYLegendSpace(y, label)) {
853
+ m_ctx.fillText(label, textpos, y - (getFontSize(m_y2LegendCss) / 2));
854
+ }
855
+ }
856
+ }
857
+ value += _this.scaleinfoY2.tickSize;
858
+ }
859
+ return true;
860
+ }
861
+
862
+ function drawYLegend(si, x, gridHorizontalLines, number, draw) {
617
863
  var value;
618
864
  si.maxValue = si.highValue + (si.tickSize * 0.2);
619
865
  si.minValue = si.lowValue - (si.tickSize * 0.2);
620
866
  m_ctx.font = m_yLegendCss.fontWeight + ' ' + m_yLegendCss.fontSize + ' ' + m_yLegendCss.fontFamily;
621
- if (si.highValue == si.lowValue) { // only have one value so set values for 1 line only
867
+ if (si.highValue == si.lowValue) {
622
868
  si.maxValue = si.maxValue + si.tickSize;
623
869
  si.minValue = si.minValue - si.tickSize;
624
870
  value = Math.abs(si.lowValue);
625
871
  } else {
626
- si.minValue = si.lowValue - (si.tickSize * 0.2);
627
872
  if (si.minValue > 0)
628
873
  value = si.minValue - fmod(Math.abs(si.minValue), si.tickSize) + si.tickSize;
629
874
  else
@@ -631,11 +876,17 @@ function Milli_Chart(settings) {
631
876
  }
632
877
  si.valuePerPixel = si.lineLength / (si.maxValue - si.minValue);
633
878
  if (isNaN(si.valuePerPixel) || !isFinite(si.valuePerPixel)) {
634
- console.log('cant draw valuePerPixel' + si.valuePerPixel);
879
+
635
880
  return false;
636
881
  }
882
+ var textpos;
883
+ var count = 0;
637
884
  for (;;) {
638
- var y = Math.round(m_chartspaces.chart.bottom - ((value - si.minValue) * si.valuePerPixel));
885
+ if (count++ > 10) {
886
+
887
+ break;
888
+ }
889
+ var y = Math.round(m_chartspaces.chart.height - getScaledSetting(m_chartCss.marginBottom) - ((value - si.minValue) * si.valuePerPixel));
639
890
  if (y <= m_chartspaces.chart.top) break;
640
891
  if (y <= m_chartspaces.chart.bottom) {
641
892
  if (gridHorizontalLines == true) {
@@ -649,35 +900,37 @@ function Milli_Chart(settings) {
649
900
  m_ctx.stroke();
650
901
  m_ctx.closePath();
651
902
  m_ctx.restore();
903
+ if ((m_yLegendCss.float == 'left' && m_yLegendCss.textAlign == 'left') || (m_yLegendCss.float == 'right' && m_yLegendCss.textAlign == 'left')) {
904
+ textpos = x - 4;
905
+ } else {
906
+ textpos = x + 4;
907
+ }
908
+
652
909
  } else
653
- if (_this.settings.drawyaxis == true && number == 1) { // draw legenditem markers for price
910
+ if (_this.settings.drawyaxis == true && number == 1 && draw) {
911
+ if (!draw) return;
654
912
  m_ctx.beginPath();
655
913
  m_ctx.moveTo(m_chartspaces.chart.left, y + 0.5);
656
- m_ctx.lineTo(m_chartspaces.chart.left + 3, y + 0.5);
657
- m_ctx.stroke();
658
- m_ctx.closePath();
659
- } else
660
- if (_this.settings.drawy2axis == true && number == 2) { // draw legenditem markers for diff
661
- m_ctx.beginPath();
662
- m_ctx.moveTo(x, y + 0.5);
663
- m_ctx.lineTo(x + 3, y + 0.5);
914
+ if ((m_yLegendCss.float == 'left' && m_yLegendCss.textAlign == 'left') || (m_yLegendCss.float == 'right' && m_yLegendCss.textAlign == 'left')) {
915
+ m_ctx.lineTo(x - 3, y + 0.5);
916
+ textpos = x - 4;
917
+ } else {
918
+ m_ctx.lineTo(x + 3, y + 0.5);
919
+ textpos = x + 4;
920
+ }
664
921
  m_ctx.stroke();
665
922
  m_ctx.closePath();
666
923
  }
667
924
 
668
- if ((number == 1 && _this.settings.drawyaxis == true) || (number == 2 && _this.settings.drawy2axis == true)) {
669
- var label;
670
- if (number == 2)
671
- label = formatNiceNumber(value, _this.settings.thousandseparator, _this.settings.decimalseparator, si.decimals, true) + '%';
672
- else
673
- label = formatNiceNumber(value, _this.settings.thousandseparator, _this.settings.decimalseparator, si.decimals, false);
674
- var textpos = x - 5;
675
- if (side == 'right') textpos = x + 7;
925
+ if (draw && (number == 1 && _this.settings.drawyaxis == true)) {
926
+ var label = formatNiceNumber(value, _this.settings.thousandseparator, _this.settings.decimalseparator, si.decimals, false);
676
927
  if (m_yLegendCss.verticalAlign == 'top') {
677
- if (y - (getFontSize(m_yLegendCss)) > 0) // dont draw if cropped
928
+ if (checkYLegendSpace(y, label))
678
929
  m_ctx.fillText(label, textpos, y - ((getFontSize(m_yLegendCss) + 2)));
679
- } else
680
- m_ctx.fillText(label, textpos, y - (getFontSize(m_yLegendCss) / 2));
930
+ } else {
931
+ if (checkYLegendSpace(y, label))
932
+ m_ctx.fillText(label, textpos, y - (getFontSize(m_yLegendCss) / 2));
933
+ }
681
934
  }
682
935
  }
683
936
  value += si.tickSize;
@@ -690,44 +943,50 @@ function Milli_Chart(settings) {
690
943
  m_ctx.strokeStyle = m_gridHorizontalCss.color;
691
944
  m_ctx.font = m_yLegendCss.fontWeight + ' ' + m_yLegendCss.fontSize + ' ' + m_yLegendCss.fontFamily;
692
945
  m_ctx.fillStyle = m_yLegendCss.color;
693
- //if (_this.settings.chartlen == '1d' || _this.settings.chartlen == '0d') firstvalue = _this.instruments[0].closeprice1d;
694
-
695
946
  if (0 == calcHighLow()) {
947
+ m_ctx.restore();
948
+
696
949
  return;
697
950
  }
698
951
  _this.scaleinfoY.lineLength = m_chartspaces.chart.bottom - m_chartspaces.chart.top;
699
952
  _this.scaleinfoY2.lineLength = _this.scaleinfoY.lineLength;
700
- var numticks = _this.scaleinfoY.lineLength / (getFontSize(m_yLegendCss) * 4);
701
- if (numticks > 8) numticks = 8; // limit to 8 items on Y legend ( this is not an absolut count, since we calculate nice legend numbers
953
+
954
+ var numticks = _this.scaleinfoY.lineLength / (getFontSize(m_yLegendCss) * _this.settings.yAxisSpacing);
955
+ if (numticks > 8) numticks = 8;
702
956
  _this.scaleinfoY.tickSize = getTickValue(_this.scaleinfoY.lowValue, _this.scaleinfoY.highValue, numticks);
703
- _this.scaleinfoY.decimals = _this.scaleinfoY.tickSize.countDecimals(); // räkna på diffen mellan high low kanske?
957
+ _this.scaleinfoY.decimals = _this.scaleinfoY.tickSize.countDecimals();
704
958
  _this.scaleinfoY.decimals = _this.scaleinfoY.decimals > 4 ? 4 : _this.scaleinfoY.decimals;
705
959
  _this.scaleinfoY.decimals = _this.scaleinfoY.decimals < 2 ? 2 : _this.scaleinfoY.decimals;
706
960
  var label = formatNiceNumber(_this.scaleinfoY.highValue, _this.settings.thousandseparator, _this.settings.decimalseparator, _this.scaleinfoY.decimals);
707
- if (m_yLegendCss.float != 'right') {
708
- m_chartspaces.chart.left = 10 + Math.round(m_ctx.measureText(label).width); // + 'px'; // räkna fram hur hur mycket plats Y värdena tar och sätt margin till det, skall vi göra så?
709
- m_chartspaces.lowerChart.left = m_chartspaces.chart.left;
710
- } else {
711
- if (m_yLegendCss.textAlign == 'right') {
712
- m_chartspaces.chart.right = m_canvas.width - (10 + Math.round(m_ctx.measureText(label).width)); // + 'px'; // räkna fram hur hur mycket plats Y värdena tar och sätt margin till det, skall vi göra så?
713
- m_chartspaces.lowerChart.right = m_chartspaces.chart.right;
961
+ if (_this.settings.drawyaxis) {
962
+ if (m_yLegendCss.float != 'right') {
963
+ m_chartspaces.chart.left = 10 + Math.round(m_ctx.measureText(label).width);
964
+ m_chartspaces.lowerChart.left = m_chartspaces.chart.left;
965
+ } else {
966
+ if (m_yLegendCss.textAlign == 'right') {
967
+ m_chartspaces.chart.right = m_canvas.width - (10 + Math.round(m_ctx.measureText(label).width));
968
+ m_chartspaces.lowerChart.right = m_chartspaces.chart.right;
969
+ }
714
970
  }
715
- // TODO: kolla setting om den skall vara "i diagrammet"
716
971
  }
717
- if (_this.settings.drawy2axis) { // calc space for y2
972
+ if (_this.settings.drawy2axis) {
973
+
718
974
  _this.scaleinfoY2.tickSize = getTickValue(_this.scaleinfoY2.lowValue, _this.scaleinfoY2.highValue, numticks);
719
975
 
720
- _this.scaleinfoY2.decimals = _this.scaleinfoY2.tickSize.countDecimals(); // räkna på diffen mellan high low kanske?
976
+ _this.scaleinfoY2.decimals = _this.scaleinfoY2.tickSize.countDecimals();
721
977
  _this.scaleinfoY2.decimals = _this.scaleinfoY2.decimals > 4 ? 4 : _this.scaleinfoY2.decimals;
722
978
  _this.scaleinfoY2.decimals = _this.scaleinfoY2.decimals < 0 ? 0 : _this.scaleinfoY2.decimals;
723
979
 
724
- label = formatNiceNumber(_this.scaleinfoY2.highValue, _this.settings.thousandseparator, _this.settings.decimalseparator, _this.scaleinfoY2.decimals) + ' %';
980
+ var widestDiff = '-' + Math.max(Math.abs(_this.scaleinfoY2.highValue), Math.abs(_this.scaleinfoY2.lowValue));
981
+ label = formatNiceNumber(widestDiff, _this.settings.thousandseparator, _this.settings.decimalseparator, _this.scaleinfoY2.decimals) + ' %';
725
982
  if (m_y2LegendCss.float != 'right') {
726
- m_chartspaces.chart.left = 10 + Math.round(m_ctx.measureText(label).width); // + 'px'; // räkna fram hur hur mycket plats Y värdena tar och sätt margin till det, skall vi göra så?
983
+ if (m_y2LegendCss.textAlign == 'left')
984
+ m_chartspaces.chart.left = 10 + Math.round(m_ctx.measureText(label).width);
727
985
  m_chartspaces.lowerChart.left = m_chartspaces.chart.left;
728
986
  } else {
729
- // kolla setting om den skall vara "i diagrammet"
730
- m_chartspaces.chart.right = m_canvas.width - (10 + Math.round(m_ctx.measureText(label).width)); // + 'px'; // räkna fram hur hur mycket plats Y värdena tar och sätt margin till det, skall vi göra så?
987
+
988
+ if (m_y2LegendCss.textAlign == 'right')
989
+ m_chartspaces.chart.right = m_canvas.width - (10 + Math.round(m_ctx.measureText(label).width));
731
990
  m_chartspaces.lowerChart.right = m_chartspaces.chart.right;
732
991
  }
733
992
  }
@@ -740,41 +999,42 @@ function Milli_Chart(settings) {
740
999
  m_ctx.strokeStyle = m_gridVerticalCss.color;
741
1000
  m_ctx.beginPath();
742
1001
  m_ctx.moveTo(m_chartspaces.chart.left + 0.5, m_chartspaces.chart.top);
743
- m_ctx.lineTo(m_chartspaces.chart.left + 0.5, m_chartspaces.chart.height - m_chartCss.marginBottom);
1002
+ m_ctx.lineTo(m_chartspaces.chart.left + 0.5, m_chartspaces.chart.height - getScaledSetting(m_chartCss.marginBottom));
744
1003
  m_ctx.stroke();
745
1004
  m_ctx.closePath();
746
1005
  m_ctx.strokeStyle = m_gridHorizontalCss.color;
747
-
748
1006
  var x;
749
- if (m_yLegendCss.float == 'right') {
750
- if (m_yLegendCss.textAlign == 'right')
751
- x = m_chartspaces.chart.right;
752
- else
753
- x = m_chartspaces.chart.right + 3;
754
- } else {
755
- x = m_chartspaces.chart.left - 3;
756
- }
757
-
758
- m_ctx.textAlign = 'right';
1007
+ if (m_yLegendCss.float == 'right')
1008
+ x = m_chartspaces.chart.right;
1009
+ else
1010
+ x = m_chartspaces.chart.left;
759
1011
  if (m_yLegendCss.textAlign == 'right') {
760
1012
  m_ctx.textAlign = 'left';
761
- drawYLegend(_this.scaleinfoY, x, 'right', _this.settings.gridHorizontalLines, 1);
762
- } else
763
- drawYLegend(_this.scaleinfoY, x, 'left', _this.settings.gridHorizontalLines, 1);
764
-
1013
+ drawYLegend(_this.scaleinfoY, x, _this.settings.gridHorizontalLines, 1, _this.settings.drawyaxis);
1014
+ } else {
1015
+ m_ctx.textAlign = 'right';
1016
+ drawYLegend(_this.scaleinfoY, x, _this.settings.gridHorizontalLines, 1, _this.settings.drawyaxis);
1017
+ }
765
1018
  if (_this.settings.drawy2axis) {
766
- x = 0;
767
1019
  if (m_y2LegendCss.float == 'right') {
768
- x = m_chartspaces.chart.right - 3;
1020
+ x = m_chartspaces.chart.right;
1021
+ } else {
1022
+ x = m_chartspaces.chart.left;
1023
+ }
1024
+ if (m_y2LegendCss.textAlign == 'right') {
769
1025
  m_ctx.textAlign = 'left';
1026
+ drawY2Legend(x);
1027
+
1028
+ } else {
1029
+ m_ctx.textAlign = 'right';
1030
+ drawY2Legend(x);
770
1031
  }
771
- drawYLegend(_this.scaleinfoY2, x, 'right', _this.settings.gridHorizontalLines2, 2);
772
1032
  }
773
1033
  m_ctx.restore();
774
1034
  }
775
1035
 
776
1036
  function drawXAxisGridlines(p, newday) {
777
- // draws the vertical grid or dots
1037
+
778
1038
  m_ctx.save();
779
1039
  m_ctx.strokeStyle = m_gridVerticalCss.color;
780
1040
  if (_this.settings.gridVerticalLines) {
@@ -797,7 +1057,7 @@ function Milli_Chart(settings) {
797
1057
  m_ctx.closePath();
798
1058
  }
799
1059
  } else
800
- if (_this.settings.drawxaxis != 0) { // if no grid but drawxaxis , add markers for date/time
1060
+ if (_this.settings.drawxaxis != 0) {
801
1061
  m_ctx.beginPath();
802
1062
  m_ctx.moveTo(p.x + 0.5, p.y);
803
1063
  m_ctx.lineTo(p.x + 0.5, p.y + 3);
@@ -808,13 +1068,13 @@ function Milli_Chart(settings) {
808
1068
  }
809
1069
 
810
1070
  function calcXScale(starttime, endtime) {
811
- // vad är detta?
1071
+
812
1072
  _this.scaleinfoX.startDate = new Date(starttime);
813
1073
  _this.scaleinfoX.endDate = new Date(endtime);
814
1074
  _this.scaleinfoX.days = getNumberOfDays(starttime, endtime);
815
1075
  _this.scaleinfoX.lineLength = m_chartspaces.chart.right - m_chartspaces.chart.left;
816
- var datesize = new Date('2888-12-28'); // bredaste datum jag kan komma på
817
- _this.scaleinfoX.itemwidth = getStringWidth(m_ctx, formatDate(datesize, _this.settings.dateformat)) * 2; // kolla rätt format en 8a för varje tecken
1076
+ var datesize = new Date('2888-12-28');
1077
+ _this.scaleinfoX.itemwidth = getStringWidth(m_ctx, formatDate(datesize, _this.settings.dateformat, _this)) * 2;
818
1078
 
819
1079
  var maxLegendItems = _this.scaleinfoX.lineLength / (_this.scaleinfoX.itemwidth * 2);
820
1080
 
@@ -836,46 +1096,46 @@ function Milli_Chart(settings) {
836
1096
  var tmp = 60;
837
1097
  while (tmp < x) {
838
1098
  tmp += 60;
839
- if (x - tmp < 20) break; // if less than 20 mins to next hour breakout
1099
+ if (x - tmp < 20) break;
840
1100
  }
841
1101
  _this.scaleinfoX.ticksize = tmp * 60000;
842
1102
  }
843
1103
  return;
844
1104
  }
845
1105
 
846
- function getDatePosition(x) {
847
- var timestamp = _this.scaleinfoX.startDate.getTime();
848
- for (var i = 0; i < 1000; i++) {
849
- var xx = getXPosition(new Date(timestamp));
850
- if (xx >= x) return timestamp;
851
- timestamp += 86400000;
852
- }
853
- return 0;
854
- }
855
-
856
1106
  function getXPosition(timestamp) {
857
- var offset = (timestamp.getTime() - _this.scaleinfoX.startDate.getTime()) / (86400000 * 7); // veckor
1107
+ var offset = (timestamp.getTime() - _this.scaleinfoX.startDate.getTime()) / (86400000 * 7);
858
1108
  offset = offset * 86400000 * 2 / _this.scaleinfoX.timePerPixel;
859
1109
  return Math.round(m_chartspaces.chart.left + ((timestamp.getTime() - _this.scaleinfoX.startDate.getTime()) / _this.scaleinfoX.timePerPixel) - offset);
860
1110
  }
861
1111
 
1112
+ function checkXLegendSides(x, text) {
1113
+
1114
+ if (_this.scaleinfoX.lineLength + m_chartspaces.chart.left < x + (m_ctx.measureText(text).width / 2)) return false;
1115
+
1116
+ if (m_chartspaces.chart.left > x - (m_ctx.measureText(text).width / 2)) return false;
1117
+ return true;
1118
+
1119
+ }
1120
+
862
1121
  function drawXAxisYears(starttime, endtime) {
863
- if (getNumberOfDays(starttime, endtime) < 366) return drawXAxisMonth(starttime, endtime);
1122
+ if (getNumberOfDays(starttime, endtime) < 250) return drawXAxisMonth(starttime, endtime);
864
1123
  m_ctx.save();
865
1124
  m_ctx.font = m_xLegendCss.fontWeight + ' ' + m_xLegendCss.fontSize + ' ' + m_xLegendCss.fontFamily;
866
- m_ctx.strokeStyle = m_gridVerticalCss.color;
1125
+ m_ctx.strokeStyle = m_gridHorizontalCss.color;
867
1126
  m_ctx.fillStyle = m_xLegendCss.color;
868
1127
  m_ctx.textAlign = "left";
869
1128
  calcXScale(starttime, endtime);
870
1129
  if (_this.settings.drawxaxis != 0) {
871
1130
  m_ctx.beginPath();
872
- m_ctx.moveTo(m_chartspaces.chart.left, m_chartspaces.chart.height - m_chartCss.marginBottom + 0.5);
873
- m_ctx.lineTo(m_chartspaces.chart.right, m_chartspaces.chart.height - m_chartCss.marginBottom + 0.5);
1131
+ m_ctx.moveTo(m_chartspaces.chart.left, m_chartspaces.chart.height - getScaledSetting(m_chartCss.marginBottom) + 0.5);
1132
+ m_ctx.lineTo(m_chartspaces.chart.right, m_chartspaces.chart.height - getScaledSetting(m_chartCss.marginBottom) + 0.5);
874
1133
  m_ctx.stroke();
875
1134
  m_ctx.closePath();
876
1135
  }
1136
+ m_ctx.strokeStyle = m_gridVerticalCss.color;
877
1137
  var legendItems = [];
878
- // draw Years
1138
+
879
1139
  var year = _this.scaleinfoX.startDate.getFullYear() + 1;
880
1140
  var numItems = 0,
881
1141
  x, draw, i, text;
@@ -888,11 +1148,11 @@ function Milli_Chart(settings) {
888
1148
  }
889
1149
  }
890
1150
  if (draw) {
891
- drawXAxisGridlines({ 'x': x, y: m_chartspaces.chart.height - m_chartCss.marginBottom });
1151
+ drawXAxisGridlines({ 'x': x, y: m_chartspaces.chart.height - getScaledSetting(m_chartCss.marginBottom) });
892
1152
  text = year;
893
- if (_this.scaleinfoX.lineLength + m_chartspaces.chart.left > x - m_ctx.measureText(text).width) { // not to far right?
1153
+ if (checkXLegendSides(x, text)) {
894
1154
  if (_this.settings.yearLabelsPos == 'top') {
895
- m_ctx.save(); // flip and write new years on top
1155
+ m_ctx.save();
896
1156
  var fontMetrix = m_ctx.measureText(text);
897
1157
  x = x + fontMetrix.actualBoundingBoxAscent + fontMetrix.actualBoundingBoxDescent + 2;
898
1158
  var y = m_chartspaces.chart.top;
@@ -901,7 +1161,7 @@ function Milli_Chart(settings) {
901
1161
  m_ctx.fillText(text, 0, 0);
902
1162
  m_ctx.restore();
903
1163
  } else {
904
- m_ctx.fillText(text, x - (m_ctx.measureText(text).width / 2), m_chartspaces.chart.height - m_chartCss.marginBottom + 10);
1164
+ m_ctx.fillText(text, x - (m_ctx.measureText(text).width / 2), m_chartspaces.chart.height - getScaledSetting(m_chartCss.marginBottom) + getScaledSetting(m_xLegendCss.paddingTop));
905
1165
  }
906
1166
  }
907
1167
  numItems++;
@@ -909,14 +1169,14 @@ function Milli_Chart(settings) {
909
1169
  }
910
1170
  year++;
911
1171
  }
912
- if (numItems * m_ctx.measureText('8888').width / _this.scaleinfoX.lineLength > 0.3) numItems = 11; // keep it clean
913
- // draw half year
914
- if (numItems < 10) { // max 10 items här för att skriva halvår
1172
+ if (numItems * m_ctx.measureText('8888').width / _this.scaleinfoX.lineLength > 0.3) numItems = 11;
1173
+
1174
+ if (numItems < 10) {
915
1175
  year = new Date(_this.scaleinfoX.startDate.getFullYear() + '-07-01T00:00:00Z');
916
1176
  if (year.getTime() < _this.scaleinfoX.startDate.getTime())
917
1177
  year = new Date(_this.scaleinfoX.startDate.getFullYear() + 1 + '-07-01T00:00:00Z');
918
1178
  while (year < _this.scaleinfoX.endDate) {
919
- x = getXPosition(new Date(year.getFullYear() + '-07-01T00:00:00Z')); // 7
1179
+ x = getXPosition(new Date(year.getFullYear() + '-07-01T00:00:00Z'));
920
1180
  draw = true;
921
1181
  for (i = 0; i < legendItems.length; i++) {
922
1182
  if (Math.abs(legendItems[i].x - x) < getMaxDateWidth()) {
@@ -924,23 +1184,24 @@ function Milli_Chart(settings) {
924
1184
  }
925
1185
  }
926
1186
  if (draw) {
927
- drawXAxisGridlines({ 'x': x, y: m_chartspaces.chart.height - m_chartCss.marginBottom });
928
- text = formatDate(year.getFullYear() + '-07-01', _this.settings.dateformat);
929
- // ingen if som year???
930
- m_ctx.fillText(text, x - (m_ctx.measureText(text).width / 2), m_chartspaces.chart.height - m_chartCss.marginBottom + 10);
1187
+ drawXAxisGridlines({ 'x': x, y: m_chartspaces.chart.height - getScaledSetting(m_chartCss.marginBottom) });
1188
+ text = formatDate(year.getFullYear() + '-07-01', _this.settings.dateformat, _this);
1189
+ if (checkXLegendSides(x, text)) {
1190
+ m_ctx.fillText(text, x - (m_ctx.measureText(text).width / 2), m_chartspaces.chart.height - getScaledSetting(m_chartCss.marginBottom) + getScaledSetting(m_xLegendCss.paddingTop));
1191
+ }
931
1192
  numItems++;
932
1193
  legendItems.push({ 'text': text, timestamp: new Date(year + '-07-01T00:00:00Z'), 'x': x });
933
1194
  }
934
1195
  year = new Date((year.getFullYear() + 1) + '-07-01T00:00:00Z');
935
1196
  }
936
1197
  }
937
- // draw Quarter
938
- if (numItems * m_ctx.measureText('8888').width / _this.scaleinfoX.lineLength > 0.3) numItems = 11; // keep it clean
939
- if (numItems < 10) { // max 10 items här för att skriva kvartal
1198
+
1199
+ if (numItems * m_ctx.measureText('8888').width / _this.scaleinfoX.lineLength > 0.3) numItems = 11;
1200
+ if (numItems < 10) {
940
1201
  year = new Date(_this.scaleinfoX.startDate.getFullYear() + '-04-01T00:00:00Z');
941
1202
  if (year.getTime() < _this.scaleinfoX.startDate.getTime())
942
1203
  year = new Date(_this.scaleinfoX.startDate.getFullYear() + 1 + '-04-01T00:00:00Z');
943
- var dontPrint = false; // if no space for first quarter dont print second either
1204
+ var dontPrint = false;
944
1205
  while (year < _this.scaleinfoX.endDate) {
945
1206
  x = getXPosition(new Date(year.getFullYear() + '-04-01T00:00:00Z'));
946
1207
  draw = true;
@@ -952,14 +1213,16 @@ function Milli_Chart(settings) {
952
1213
  }
953
1214
  if (dontPrint) break;
954
1215
  if (draw) {
955
- drawXAxisGridlines({ 'x': x, y: m_chartspaces.chart.height - m_chartCss.marginBottom });
956
- text = formatDate(year.getFullYear() + '-' + (year.getMonth() + 1) + '-01', _this.settings.dateformat);
957
- m_ctx.fillText(text, x - (m_ctx.measureText(text).width / 2), m_chartspaces.chart.height - m_chartCss.marginBottom + 10);
1216
+ drawXAxisGridlines({ 'x': x, y: m_chartspaces.chart.height - getScaledSetting(m_chartCss.marginBottom) });
1217
+ text = formatDate(year.getFullYear() + '-' + (year.getMonth() + 1) + '-01', _this.settings.dateformat, _this);
1218
+ if (checkXLegendSides(x, text)) {
1219
+ m_ctx.fillText(text, x - (m_ctx.measureText(text).width / 2), m_chartspaces.chart.height - getScaledSetting(m_chartCss.marginBottom) + getScaledSetting(m_xLegendCss.paddingTop));
1220
+ }
958
1221
  }
959
1222
  legendItems.push({ 'text': text, timestamp: new Date(year + '-04-01T00:00:00Z'), 'x': x });
960
1223
  year = new Date((year.getFullYear() + 1) + '-04-01T00:00:00Z');
961
1224
  }
962
- // Draw Quarter 2
1225
+
963
1226
  if (dontPrint == false) {
964
1227
  year = new Date(_this.scaleinfoX.startDate.getFullYear() + '-10-01T00:00:00Z');
965
1228
  if (year.getTime() < _this.scaleinfoX.startDate.getTime())
@@ -973,9 +1236,11 @@ function Milli_Chart(settings) {
973
1236
  }
974
1237
  }
975
1238
  if (draw) {
976
- drawXAxisGridlines({ 'x': x, y: m_chartspaces.chart.height - m_chartCss.marginBottom });
977
- text = formatDate(year.getFullYear() + '-' + (year.getMonth() + 1) + '-01', _this.settings.dateformat);
978
- m_ctx.fillText(text, x - (m_ctx.measureText(text).width / 2), m_chartspaces.chart.height - m_chartCss.marginBottom + 10);
1239
+ drawXAxisGridlines({ 'x': x, y: m_chartspaces.chart.height - getScaledSetting(m_chartCss.marginBottom) });
1240
+ text = formatDate(year.getFullYear() + '-' + (year.getMonth() + 1) + '-01', _this.settings.dateformat, _this);
1241
+ if (checkXLegendSides(x, text)) {
1242
+ m_ctx.fillText(text, x - (m_ctx.measureText(text).width / 2), m_chartspaces.chart.height - getScaledSetting(m_chartCss.marginBottom) + getScaledSetting(m_xLegendCss.paddingTop));
1243
+ }
979
1244
  }
980
1245
  legendItems.push({ 'text': text, timestamp: new Date(year + '-10-01T00:00:00Z'), 'x': x });
981
1246
  year = new Date((year.getFullYear() + 1) + '-10-01T00:00:00Z');
@@ -991,30 +1256,32 @@ function Milli_Chart(settings) {
991
1256
  endtime -= starttime % 8640000;
992
1257
  m_ctx.save();
993
1258
  m_ctx.font = m_xLegendCss.fontWeight + ' ' + m_xLegendCss.fontSize + ' ' + m_xLegendCss.fontFamily;
994
- m_ctx.strokeStyle = m_gridVerticalCss.color;
1259
+ m_ctx.strokeStyle = m_gridHorizontalCss.color;
995
1260
  m_ctx.fillStyle = m_xLegendCss.color;
996
1261
  calcXScale(starttime, endtime);
997
- if (_this.settings.drawxaxis != 0) { // draw line
1262
+ if (_this.settings.drawxaxis != 0) {
998
1263
  m_ctx.beginPath();
999
- m_ctx.moveTo(m_chartspaces.chart.left, m_chartspaces.chart.height - m_chartCss.marginBottom + 0.5);
1000
- m_ctx.lineTo(m_chartspaces.chart.right, m_chartspaces.chart.height - m_chartCss.marginBottom + 0.5);
1264
+ m_ctx.moveTo(m_chartspaces.chart.left, m_chartspaces.chart.height - getScaledSetting(m_chartCss.marginBottom) + 0.5);
1265
+ m_ctx.lineTo(m_chartspaces.chart.right, m_chartspaces.chart.height - getScaledSetting(m_chartCss.marginBottom) + 0.5);
1001
1266
  m_ctx.stroke();
1002
1267
  m_ctx.closePath();
1003
1268
  }
1269
+ m_ctx.strokeStyle = m_gridVerticalCss.color;
1004
1270
  m_ctx.textAlign = "left";
1005
1271
  var currentDate = new Date(starttime);
1006
1272
  var x;
1007
1273
  var lastx = 0;
1008
1274
  var draw = true;
1009
1275
  var offset = 0;
1010
- while (currentDate.getTime() < _this.scaleinfoX.endTimeStamp) { // oklart om det skall vara så här 2021-06-01
1276
+ var count = 0;
1277
+ while (currentDate.getTime() < _this.scaleinfoX.endTimeStamp) {
1011
1278
  draw = true;
1012
- while (currentDate.getDay() == 0 || currentDate.getDay() == 6) { // move past weekends , maybe skip this if date is available in data
1279
+ while (currentDate.getDay() == 0 || currentDate.getDay() == 6) {
1013
1280
  currentDate = new Date(currentDate.getTime() + 86400000);
1014
1281
  offset += 86400000 / _this.scaleinfoX.timePerPixel;
1015
1282
  }
1016
1283
  x = Math.round(m_chartspaces.chart.left + ((currentDate.getTime() - _this.scaleinfoX.startDate.getTime()) / _this.scaleinfoX.timePerPixel) - offset);
1017
- if (lastx == 0 && m_chartspaces.chart.left > (x - (getMaxDateWidth() / 2))) { // do not print left of y legend
1284
+ if (lastx == 0 && m_chartspaces.chart.left > (x - (getMaxDateWidth() / 2))) {
1018
1285
  currentDate = new Date(currentDate.getTime() + 86400000);
1019
1286
  continue;
1020
1287
  }
@@ -1023,15 +1290,16 @@ function Milli_Chart(settings) {
1023
1290
  }
1024
1291
  if (draw) {
1025
1292
  lastx = x;
1026
- var text = formatDate(currentDate.toISOString().substring(0, 10), _this.settings.dateformat);
1027
- if (_this.scaleinfoX.lineLength + m_chartspaces.chart.left > x - getMaxDateWidth()) { // not to far right?
1028
- m_ctx.fillText(text, x - (m_ctx.measureText(text).width / 2), m_chartspaces.chart.bottom + 10);
1293
+ var text = formatDate(currentDate.toISOString().substring(0, 10), _this.settings.dateformat, _this);
1294
+ if (checkXLegendSides(x, text)) {
1295
+ if (typeof _this.settings.xAxisModulo === 'undefined' || (count++ % _this.settings.xAxisModulo) == 0)
1296
+ m_ctx.fillText(text, x - (m_ctx.measureText(text).width / 2), m_chartspaces.chart.bottom + getScaledSetting(m_xLegendCss.paddingTop));
1029
1297
  }
1030
1298
  drawXAxisGridlines({ 'x': x, y: m_chartspaces.chart.bottom });
1031
1299
  }
1032
1300
  currentDate = new Date(currentDate.getTime() + 86400000);
1033
1301
  }
1034
- // vad är detta?
1302
+
1035
1303
  if (typeof m_chartCss.boxShadow !== 'undefined' && typeof m_chartCss.boxShadow.rightWidth !== 'undefined') {
1036
1304
  if (m_chartCss.boxShadow.rightWidth == 0) drawXAxisGridlines({ 'x': x, y: m_chartspaces.chart.bottom }, false);
1037
1305
  } else {
@@ -1043,9 +1311,9 @@ function Milli_Chart(settings) {
1043
1311
  function calcXScaleTick(starttime, endtime) {
1044
1312
  _this.scaleinfoX.startDate = new Date(starttime);
1045
1313
  _this.scaleinfoX.endDate = new Date(endtime);
1046
- _this.scaleinfoX.days = getNumberOfDays(starttime, endtime); // kan vi nog skita i
1047
- _this.scaleinfoX.lineLength = m_chartspaces.chart.right - m_chartspaces.chart.left; // daybreaks can have 88/88
1048
- _this.scaleinfoX.itemwidth = getStringWidth(m_ctx, '88:88') * 2; // kolla rätt format en 8a för varje tecken
1314
+ _this.scaleinfoX.days = getNumberOfDays(starttime, endtime);
1315
+ _this.scaleinfoX.lineLength = m_chartspaces.chart.right - m_chartspaces.chart.left;
1316
+ _this.scaleinfoX.itemwidth = getStringWidth(m_ctx, '88:88') * 2;
1049
1317
  var maxLegendItems = Math.floor(_this.scaleinfoX.lineLength / (_this.scaleinfoX.itemwidth * 2));
1050
1318
 
1051
1319
  if (_this.scaleinfoY.type != 'history') {
@@ -1082,28 +1350,28 @@ function Milli_Chart(settings) {
1082
1350
 
1083
1351
  var factor = 60;
1084
1352
  if (numticks < 1)
1085
- _this.scaleinfoX.ticksize = 86400000; // öhh?
1353
+ _this.scaleinfoX.ticksize = 86400000;
1086
1354
  else {
1087
1355
  if (numticks < 2) numticks = 2;
1088
1356
  x = _this.scaleinfoX.milliPerDay / numticks / 60000;
1089
- if (totalmilli > 4 * 3600000) factor = 60; // 4 timmar
1357
+ if (totalmilli > 4 * 3600000) factor = 60;
1090
1358
  else
1091
- if (totalmilli > 2 * 3600000) factor = 30; // 2 timmar
1359
+ if (totalmilli > 2 * 3600000) factor = 30;
1092
1360
  else
1093
- if (totalmilli > 3600000) factor = 20; // 1 timma
1361
+ if (totalmilli > 3600000) factor = 20;
1094
1362
  else
1095
- if (totalmilli > 3600000 / 2) factor = 10; // 30 min
1363
+ if (totalmilli > 3600000 / 2) factor = 10;
1096
1364
  else
1097
- if (totalmilli > 3600000 / 4) factor = 5; // 15 min
1365
+ if (totalmilli > 3600000 / 4) factor = 5;
1098
1366
  else factor = 1;
1099
- _this.scaleinfoX.ticksize = factor * 60000; // time to add to next legenditem
1367
+ _this.scaleinfoX.ticksize = factor * 60000;
1100
1368
  }
1101
1369
  return;
1102
1370
  }
1103
1371
  }
1104
1372
 
1105
1373
  function formatChartTime(value, format) {
1106
- // internal
1374
+
1107
1375
  if (typeof value !== 'string') return "";
1108
1376
  var datetime = new Date();
1109
1377
  datetime.setHours(parseInt(value));
@@ -1158,17 +1426,18 @@ function Milli_Chart(settings) {
1158
1426
  m_ctx.save();
1159
1427
  m_ctx.font = m_xLegendCss.fontWeight + ' ' + m_xLegendCss.fontSize + ' ' + m_xLegendCss.fontFamily;
1160
1428
 
1161
- m_ctx.strokeStyle = m_gridVerticalCss.color;
1429
+ m_ctx.strokeStyle = m_gridHorizontalCss.color;
1162
1430
  m_ctx.fillStyle = m_xLegendCss.color;
1163
1431
  m_ctx.textAlign = "left";
1164
1432
  calcXScaleTick(starttime, endtime);
1165
- if (_this.settings.drawxaxis != 0) { // draw line for legend
1433
+ if (_this.settings.drawxaxis != 0) {
1166
1434
  m_ctx.beginPath();
1167
1435
  m_ctx.moveTo(m_chartspaces.chart.left, m_chartspaces.chart.bottom + 0.5);
1168
1436
  m_ctx.lineTo(m_chartspaces.chart.right, m_chartspaces.chart.bottom + 0.5);
1169
1437
  m_ctx.stroke();
1170
1438
  m_ctx.closePath();
1171
1439
  }
1440
+ m_ctx.strokeStyle = m_gridVerticalCss.color;
1172
1441
  var dayLightChange = (new Date(starttime).getTimezoneOffset() - new Date().getTimezoneOffset()) * 60000;
1173
1442
  var currentDate = new Date(starttime);
1174
1443
  var x;
@@ -1177,20 +1446,30 @@ function Milli_Chart(settings) {
1177
1446
  var offset = 0;
1178
1447
  var legendItems = [];
1179
1448
  var openhour = new Date(new Date(currentDate.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketopen + 'Z')).getTime() % 86400000;
1180
- // add daysstarts
1181
- if (currentDate.getTime() % 3600000 != 0) // if not full hour, move up to next full hour
1182
- currentDate = new Date(currentDate.getTime() - currentDate.getTime() % 3600000 + 3600000); // START om full hour (if modulo == 0 then + 3600000 kanske)
1449
+ var closehour = new Date(new Date(currentDate.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketclose + 'Z')).getTime() % 86400000;
1450
+
1451
+ var middleOfDay = new Date(currentDate.getTime() - (currentDate.getTime() % 86400000) + ((openhour + closehour) / 2));
1452
+ if (_this.settings.intradayDatePos.x == 'left' && (_this.settings.intradayDatePos.y == 'scale' || _this.settings.intradayDatePos.y == 'top')) {
1453
+ middleOfDay = new Date(currentDate.getTime());
1454
+ }
1455
+ if (currentDate.getTime() % 3600000 != 0)
1456
+ currentDate = new Date(currentDate.getTime() - currentDate.getTime() % 3600000 + 3600000);
1183
1457
 
1184
1458
  var firstDate = new Date(currentDate);
1185
1459
  var days = calcTimeSpanInDays(starttime, endtime);
1186
1460
  if (m_zoom.mouseup.timestamp == null || (m_zoom.mouseup.timestamp != null && days > 1)) {
1187
1461
  while (currentDate.getTime() < _this.scaleinfoX.endTimeStamp) {
1188
1462
  draw = true;
1189
- while (currentDate.getDay() == 0 || currentDate.getDay() == 6) { // move past weekends , maybe skip this if date is available in data
1463
+ while (currentDate.getDay() == 0 || currentDate.getDay() == 6) {
1190
1464
  currentDate = new Date(currentDate.getTime() + 86400000);
1465
+ if (_this.settings.intradayDatePos.x == 'left' && (_this.settings.intradayDatePos.y == 'scale' || _this.settings.intradayDatePos.y == 'top')) {
1466
+ middleOfDay = new Date(currentDate.getTime());
1467
+ } else
1468
+ middleOfDay = new Date(currentDate.getTime() - (currentDate.getTime() % 86400000) + ((openhour + closehour) / 2));
1191
1469
  offset += 86400000 / _this.scaleinfoX.timePerPixel;
1192
1470
  }
1193
1471
  x = Math.round(m_chartspaces.chart.left + ((currentDate.getTime() - _this.scaleinfoX.startDate.getTime()) / _this.scaleinfoX.timePerPixel) - offset);
1472
+ var middleX = Math.round(m_chartspaces.chart.left + ((middleOfDay.getTime() - _this.scaleinfoX.startDate.getTime()) / _this.scaleinfoX.timePerPixel) - offset);
1194
1473
  if (lastx != 0 && lastx + (getMaxTimeWidth() / 2) > (x - getMaxTimeWidth())) {
1195
1474
  draw = false;
1196
1475
  } else
@@ -1199,50 +1478,77 @@ function Milli_Chart(settings) {
1199
1478
  if (draw) {
1200
1479
  lastx = x + 0.5;
1201
1480
  var text = formatChartTime(currentDate.toTimeString().substring(0, 8), _this.settings.timeformat);
1202
- // if day change and setting print on top as well
1203
- if (_this.scaleinfoX.lineLength + m_chartspaces.chart.left > x - getMaxTimeWidth()) { // not to far right?
1204
- m_ctx.fillText(text, x - (m_ctx.measureText(text).width / 2), m_chartspaces.chart.bottom + 10);
1205
- legendItems.push({ x: x, type: 0, text: text });
1206
- if (_this.settings.intradaydates) { // draw dates on top
1207
- m_ctx.save();
1208
- var date = currentDate.getDate() + '/' + (currentDate.getMonth() + 1);
1209
- var fontMetrix = m_ctx.measureText(date);
1210
- var dx = x + fontMetrix.actualBoundingBoxAscent + fontMetrix.actualBoundingBoxDescent + 3;
1211
- var dy = m_chartCss.marginTop; // + m_ctx.measureText(datum).width;
1212
- m_ctx.translate(dx, dy);
1213
- m_ctx.rotate(90 * Math.PI / 180);
1214
- m_ctx.fillText(date, 0, 0);
1215
- m_ctx.restore();
1481
+ var date = formatDate(currentDate, _this.settings.intradayDatePos.dateformat, _this);
1482
+ if (_this.scaleinfoX.lineLength + m_chartspaces.chart.left > x - getMaxTimeWidth()) {
1483
+ if (_this.settings.intradayDatePos.y == 'scale' && _this.settings.chartlen != '0d' && _this.settings.chartlen != '1d') {
1484
+
1485
+ m_ctx.fillText(date, middleX - (m_ctx.measureText(date).width / 2), m_chartspaces.chart.bottom + getScaledSetting(m_xLegendCss.paddingTop));
1486
+ legendItems.push({ x: middleX, type: 0, text: date, width: m_ctx.measureText(date) });
1487
+ } else if (_this.settings.intradayDatePos.y == 'bottom' && _this.settings.chartlen != '0d' && _this.settings.chartlen != '1d') {
1488
+ m_ctx.fillText(date, middleX - (m_ctx.measureText(date).width / 2), m_chartspaces.chart.bottom + getScaledSetting(m_xLegendCss.paddingTop) + parseInt(m_xLegendCss.fontSize) * window.devicePixelRatio);
1489
+
1490
+ m_ctx.fillText(text, x - (m_ctx.measureText(text).width / 2), m_chartspaces.chart.bottom + getScaledSetting(m_xLegendCss.paddingTop));
1491
+ legendItems.push({ x: x, type: 0, text: text });
1492
+ } else {
1493
+ m_ctx.fillText(text, x - (m_ctx.measureText(text).width / 2), m_chartspaces.chart.bottom + getScaledSetting(m_xLegendCss.paddingTop));
1494
+ legendItems.push({ x: x, type: 0, text: text });
1495
+ if (_this.settings.intradayDatePos.y == 'top' && _this.settings.chartlen != '0d' && _this.settings.chartlen != '1d') {
1496
+ if (_this.settings.intradayDatePos.orientation == 'vertical' && _this.settings.intradayDatePos.x != 'center') {
1497
+ m_ctx.save();
1498
+ var fontMetrix = m_ctx.measureText(date);
1499
+ var dx = (x + fontMetrix.actualBoundingBoxAscent + fontMetrix.actualBoundingBoxDescent + 3) / window.devicePixelRatio;
1500
+ var dy = m_chartCss.marginTop;
1501
+ m_ctx.translate(dx, dy);
1502
+ m_ctx.rotate(90 * Math.PI / 180);
1503
+ m_ctx.fillText(date, 0, 0);
1504
+ m_ctx.restore();
1505
+ } else {
1506
+ if (_this.settings.intradayDatePos.x == 'center') {
1507
+ m_ctx.fillText(date, middleX - (m_ctx.measureText(date).width / 2), getScaledSetting(m_chartCss.marginTop));
1508
+ } else {
1509
+
1510
+ m_ctx.fillText(date, middleX + 1, getScaledSetting(m_chartCss.marginTop));
1511
+ }
1512
+ }
1513
+
1514
+ }
1216
1515
  }
1217
1516
  }
1218
- if (x != m_chartspaces.chart.left + 0.5) { // do not draw the first line, it is already drawn
1219
- if (openhour == currentDate.getTime() % 86400000) {
1220
- drawXAxisGridlines({ 'x': x, y: m_chartspaces.chart.bottom }, true); // dash?
1221
- } else {
1222
- drawXAxisGridlines({ 'x': x, y: m_chartspaces.chart.bottom }, false); // dash?
1517
+ if (x != m_chartspaces.chart.left + 0.5) {
1518
+ if (_this.settings.intradayDatePos.y != 'bottom') {
1519
+ if (openhour == currentDate.getTime() % 86400000) {
1520
+ drawXAxisGridlines({ 'x': x, y: m_chartspaces.chart.bottom }, true);
1521
+ } else {
1522
+ drawXAxisGridlines({ 'x': x, y: m_chartspaces.chart.bottom }, false);
1523
+ }
1223
1524
  }
1224
1525
  }
1225
1526
  }
1226
- // Move to next day and set starting hour correct if we have open at half hour
1527
+
1227
1528
  currentDate = new Date(currentDate.getTime() + 86400000);
1228
1529
  currentDate = new Date(currentDate.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketopen + 'Z');
1229
- if (currentDate.getTime() % 3600000 != 0) // if not full hour, move up to next full hour
1230
- currentDate = new Date(currentDate.getTime() - currentDate.getTime() % 3600000 + 3600000); // START om full hour (if modulo == 0 then + 3600000 kanske)
1530
+ middleOfDay = new Date(currentDate.getTime() - (currentDate.getTime() % 86400000) + ((openhour + closehour) / 2));
1531
+ if (_this.settings.intradayDatePos.x == 'left' && (_this.settings.intradayDatePos.y == 'scale' || _this.settings.intradayDatePos.y == 'top')) {
1532
+ middleOfDay = new Date(currentDate);
1533
+ }
1534
+
1535
+ if (currentDate.getTime() % 3600000 != 0)
1536
+ currentDate = new Date(currentDate.getTime() - currentDate.getTime() % 3600000 + 3600000);
1537
+
1231
1538
  offset += (86400000 - _this.scaleinfoX.milliPerDay) / _this.scaleinfoX.timePerPixel;
1232
1539
  }
1233
1540
  }
1234
- // add timestamps
1541
+
1235
1542
  currentDate = new Date(starttime);
1236
- if (currentDate.getTime() % 3600000 != 0) // if not full hour, move up to next full hour
1237
- currentDate = new Date(currentDate.getTime() - currentDate.getTime() % 3600000 + 3600000); // START om full hour (if modulo == 0 then + 3600000 kanske)
1543
+ if (currentDate.getTime() % 3600000 != 0)
1544
+ currentDate = new Date(currentDate.getTime() - currentDate.getTime() % 3600000 + 3600000);
1238
1545
 
1239
1546
  var maxHourLegends;
1240
1547
  if (legendItems.length == 0)
1241
- maxHourLegends = Math.floor((_this.scaleinfoX.lineLength - m_chartspaces.chart.left - getMaxTimeWidth()) / (getMaxTimeWidth() * 3)); // varför tar vi bort margin???
1242
- else
1243
- if (legendItems.length == 1) {
1548
+ maxHourLegends = Math.floor((_this.scaleinfoX.lineLength - m_chartspaces.chart.left - getMaxTimeWidth()) / (getMaxTimeWidth() * 3));
1549
+ else if (legendItems.length == 1) {
1244
1550
  if (m_zoom.mouseup.timestamp && days == 2) {
1245
- // ta den största delen av linjen och mät på
1551
+
1246
1552
  if (_this.scaleinfoX.lineLength / 2 < legendItems[0].x + m_chartspaces.chart.left)
1247
1553
  maxHourLegends = Math.floor((_this.scaleinfoX.lineLength - (_this.scaleinfoX.lineLength - legendItems[0].x) - getMaxTimeWidth()) / (getMaxTimeWidth() * 3));
1248
1554
  else
@@ -1250,15 +1556,15 @@ function Milli_Chart(settings) {
1250
1556
  } else
1251
1557
  maxHourLegends = Math.floor((_this.scaleinfoX.lineLength - legendItems[0].x - getMaxTimeWidth()) / (getMaxTimeWidth() * 3));
1252
1558
  } else {
1253
- maxHourLegends = Math.floor((legendItems[legendItems.length - 1].x - legendItems[legendItems.length - 2].x - getMaxTimeWidth()) / (getMaxTimeWidth() * 3)); // calculate with the last days length
1559
+ maxHourLegends = Math.floor((legendItems[legendItems.length - 1].x - legendItems[legendItems.length - 2].x - getMaxTimeWidth()) / (getMaxTimeWidth() * 3));
1254
1560
  }
1255
1561
 
1256
- var tickSize; // per day
1562
+ var tickSize;
1257
1563
  if (days == 1) {
1258
- // use start and endtime as ticksize
1564
+
1259
1565
  tickSize = new Date(endtime - starttime);
1260
- } else if (m_zoom.mouseup.timestamp && days == 2) { // zoom with 2 days
1261
- // use the day with most time as tickSize
1566
+ } else if (m_zoom.mouseup.timestamp && days == 2) {
1567
+
1262
1568
  var tmpDate = new Date(starttime);
1263
1569
  tickSize = new Date(new Date(tmpDate.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketclose + 'Z') - new Date(starttime)).getTime();
1264
1570
  var firstDay = tickSize;
@@ -1267,13 +1573,13 @@ function Milli_Chart(settings) {
1267
1573
  tickSize += new Date(endtime - new Date(tmpDate.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketopen + 'Z').getTime()).getTime();
1268
1574
  tickSize = new Date(Math.max(firstDay, secondDay));
1269
1575
  } else {
1270
- // use full day as tickSize
1576
+
1271
1577
  tickSize = new Date(new Date(currentDate.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketclose + 'Z') - new Date(currentDate.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketopen + 'Z'));
1272
1578
  }
1273
1579
  var interval;
1274
1580
  var modularvalue = 3600000;
1275
1581
 
1276
- // calc the ticksize to add to time(interval) when drawing and the modulu value
1582
+
1277
1583
  if (tickSize.getTime() < 1800000) {
1278
1584
  tickSize = tickSize.getTime() / 60000;
1279
1585
  interval = Math.floor(tickSize / (maxHourLegends + 1)) * 60000;
@@ -1292,14 +1598,14 @@ function Milli_Chart(settings) {
1292
1598
  interval = Math.floor(tickSize / (maxHourLegends + 1)) * 3600000;
1293
1599
  }
1294
1600
  if (interval == 0) {
1295
- // default 1h
1601
+
1296
1602
  interval = 3600000;
1297
1603
  modularvalue = 3600000;
1298
1604
  }
1299
1605
  if (interval % 60000 != 0) {
1300
- interval = (interval - interval % 60000) + 60000; // remove sekunder
1606
+ interval = (interval - interval % 60000) + 60000;
1301
1607
  }
1302
- // print other times
1608
+
1303
1609
  offset = 0;
1304
1610
  lastx = 0;
1305
1611
  var closeTime = new Date(currentDate.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketclose + 'Z');
@@ -1308,38 +1614,38 @@ function Milli_Chart(settings) {
1308
1614
 
1309
1615
  var workDate = new Date(currentDate);
1310
1616
  currentDate = new Date(starttime);
1311
- if (currentDate.getTime() % modularvalue != 0) // if not full hour, move up to next full hour
1312
- currentDate = new Date(currentDate.getTime() - currentDate.getTime() % modularvalue + modularvalue); // START om full hour (if modulo == 0 then + 3600000 kanske)
1617
+ if (currentDate.getTime() % modularvalue != 0)
1618
+ currentDate = new Date(currentDate.getTime() - currentDate.getTime() % modularvalue + modularvalue);
1313
1619
 
1314
1620
  var count = 0;
1315
1621
  while (currentDate.getTime() <= _this.scaleinfoX.endTimeStamp) {
1316
1622
  dayLightChange = (closeTime.getTimezoneOffset() - new Date().getTimezoneOffset()) * 60000;
1317
1623
  if (count++ > 100) {
1318
- break; // just make sure we dont do an infinity loop
1624
+ break;
1319
1625
 
1320
1626
  }
1321
1627
  draw = true;
1322
- while (currentDate.getDay() == 0 || currentDate.getDay() == 6) { // move past weekends , maybe skip this if date is available in data
1323
- //closeTime = new Date(closeTime.getTime() + 86400000);
1628
+ while (currentDate.getDay() == 0 || currentDate.getDay() == 6) {
1629
+
1324
1630
  currentDate = new Date(currentDate.getTime() + 86400000);
1325
1631
  closeTime = new Date(currentDate.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketclose + 'Z');
1326
- if (currentDate.getTime() % modularvalue != 0) // if not full hour, move up to next full hour
1327
- currentDate = new Date(currentDate.getTime() - currentDate.getTime() % modularvalue + modularvalue); // START om full hour (if modulo == 0 then + 3600000 kanske)
1632
+ if (currentDate.getTime() % modularvalue != 0)
1633
+ currentDate = new Date(currentDate.getTime() - currentDate.getTime() % modularvalue + modularvalue);
1328
1634
  workDate = new Date(workDate.getTime() + 86400000);
1329
1635
  offset += 86400000 / _this.scaleinfoX.timePerPixel;
1330
1636
  }
1331
1637
  if (currentDate.getTime() > closeTime.getTime()) {
1332
- // draw DayEnd(start) dash line
1638
+
1333
1639
  var dayStart = new Date(workDate.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketclose + 'Z');
1334
1640
  x = Math.round(m_chartspaces.chart.left + ((dayStart.getTime() - _this.scaleinfoX.startDate.getTime()) / _this.scaleinfoX.timePerPixel) - offset);
1335
- drawXAxisGridlines({ 'x': x, y: m_chartspaces.chart.bottom }, true); // dash?
1641
+ drawXAxisGridlines({ 'x': x, y: m_chartspaces.chart.bottom }, true);
1336
1642
 
1337
1643
  closeTime = new Date(closeTime.getTime() + 86400000);
1338
1644
  workDate = new Date(workDate.getTime() + 86400000);
1339
1645
  currentDate = new Date(workDate.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketopen + 'Z');
1340
1646
 
1341
- if (currentDate.getTime() % modularvalue != 0) // if not full hour, move up to next full hour
1342
- currentDate = new Date(currentDate.getTime() - currentDate.getTime() % modularvalue + modularvalue); // START om full hour (if modulo == 0 then + 3600000 kanske)
1647
+ if (currentDate.getTime() % modularvalue != 0)
1648
+ currentDate = new Date(currentDate.getTime() - currentDate.getTime() % modularvalue + modularvalue);
1343
1649
  offset += (86400000 - _this.scaleinfoX.milliPerDay) / _this.scaleinfoX.timePerPixel;
1344
1650
  continue;
1345
1651
  }
@@ -1359,14 +1665,15 @@ function Milli_Chart(settings) {
1359
1665
  }
1360
1666
  }
1361
1667
  if (lastx + (getMaxTimeWidth() / 2) > (x - getMaxTimeWidth())) {
1362
- //draw = false;
1668
+
1363
1669
  }
1364
1670
  if (draw) {
1365
1671
  lastx = x;
1366
- // if day change and setting print on top as well
1367
- if (_this.scaleinfoX.lineLength + m_chartspaces.chart.left > x - getMaxTimeWidth()) { // not to far right?
1672
+
1673
+ if (_this.scaleinfoX.lineLength + m_chartspaces.chart.left > x - getMaxTimeWidth()) {
1368
1674
  var label = formatChartTime(currentDate.toTimeString().substring(0, 8), _this.settings.timeformat);
1369
- m_ctx.fillText(label, x - (m_ctx.measureText(label).width / 2), m_chartspaces.chart.bottom + 10);
1675
+ x = Math.round(x);
1676
+ m_ctx.fillText(label, x - (m_ctx.measureText(label).width / 2), m_chartspaces.chart.bottom + getScaledSetting(m_xLegendCss.paddingTop));
1370
1677
  legendItems.push({ x: x, type: 0 });
1371
1678
  }
1372
1679
  drawXAxisGridlines({ 'x': x, y: m_chartspaces.chart.bottom }, false);
@@ -1374,7 +1681,7 @@ function Milli_Chart(settings) {
1374
1681
  currentDate = new Date(currentDate.getTime() + interval);
1375
1682
  }
1376
1683
 
1377
- // vad är detta?
1684
+
1378
1685
  if (typeof m_chartCss.boxShadow !== 'undefined' && typeof m_chartCss.boxShadow.rightWidth !== 'undefined') {
1379
1686
  if (m_chartCss.boxShadow.rightWidth == 0) drawXAxisGridlines({ 'x': x, y: m_chartspaces.chart.bottom }, false);
1380
1687
 
@@ -1384,15 +1691,63 @@ function Milli_Chart(settings) {
1384
1691
  m_ctx.restore();
1385
1692
  }
1386
1693
 
1694
+ function drawClosePriceIndicator() {
1695
+ if (_this.settings.closePriceIndicator == false || _this.scaleinfoY.type == 'history') return;
1696
+ if (isNaN(_this.instruments[0].startValue) || !_this.instruments[0].startValue) return;
1697
+ var y = Math.round(m_chartspaces.chart.height - getScaledSetting(m_chartCss.marginBottom) - ((_this.instruments[0].startValue - _this.scaleinfoY.minValue) * _this.scaleinfoY.valuePerPixel)) + 0.5;
1698
+ m_ctx.save();
1699
+ m_ctx.strokeStyle = _this.settings.closePriceIndicator;
1700
+ m_ctx.setLineDash([3, 3]);
1701
+ m_ctx.beginPath();
1702
+ m_ctx.moveTo(m_chartspaces.chart.left, y);
1703
+ m_ctx.lineTo(m_chartspaces.chart.right - 0.5, y);
1704
+ m_ctx.stroke();
1705
+ m_ctx.closePath();
1706
+ m_ctx.restore();
1707
+ }
1708
+
1709
+ function drawPriceIndicator() {
1710
+ if (_this.settings.priceIndicator == false) return;
1711
+ var obj = m_dataPoints.map.get(m_dataPoints.arr[m_dataPoints.arr.length - 1]);
1712
+ if (obj == null) {
1713
+ return;
1714
+ }
1715
+ var oldValue = undefined;
1716
+ var newValue = undefined;
1717
+ var offsetWidth = 0;
1718
+ if (_this.settings.drawyaxis && m_yLegendCss.float == 'right') {
1719
+ newValue = formatNiceNumber(obj.instruments[0].price, _this.settings.thousandseparator, _this.settings.decimalseparator, _this.settings.num_decimals, false);
1720
+ if (m_yLegendCss.textAlign == 'left') offsetWidth = 1;
1721
+ } else if (_this.settings.drawy2axis && m_y2LegendCss.float == 'right') {
1722
+ newValue = formatNiceNumber(obj.instruments[0].diff, _this.settings.thousandseparator, _this.settings.decimalseparator, 2, false) + '%';
1723
+ if (m_y2LegendCss.textAlign == 'left') offsetWidth = 1;
1724
+ } else return;
1725
+ if (typeof m_priceIndicator !== 'undefined') {
1726
+ oldValue = MillistreamWidgetApi_getElementNumber(_this, m_priceIndicator);
1727
+ } else {
1728
+ m_priceIndicator = document.createElement('div');
1729
+ m_canvas.parentNode.appendChild(m_priceIndicator);
1730
+ m_priceIndicator.setAttribute('class', 'millistream-chart-price-indicator');
1731
+ }
1732
+ m_priceIndicator.innerHTML = newValue;
1733
+ m_priceIndicator.style.left = (m_chartspaces.chart.right / window.devicePixelRatio) - (offsetWidth == 0 ? -1 : m_priceIndicator.offsetWidth) + 'px';
1734
+ m_priceIndicator.style.top = obj.instruments[0].y - (m_priceIndicator.offsetHeight / 2) + 'px';
1735
+ newValue = MillistreamWidgetApi_getElementNumber(_this, m_priceIndicator);
1736
+ MillistreamWidgetApi_flashElement(_this, m_priceIndicator, newValue, oldValue);
1737
+ }
1738
+
1387
1739
  function onMouseOut(evt) {
1740
+ if (typeof _this.settings.tooltip === 'object' && _this.settings.tooltip.preventOut) return;
1388
1741
  for (var i = 0; i < _this.instruments.length; i++) {
1389
1742
  if (_this.instruments[i].insref != 0 && typeof _this.instruments[i].toolTip !== 'undefined') {
1743
+ if (i == 0 && typeof _this.settings.tooltip == 'object' && typeof _this.settings.tooltip.mouseOut == 'function') _this.settings.tooltip.mouseOut.call();
1390
1744
  _this.instruments[i].toolTip.parentNode.removeChild(_this.instruments[i].toolTip);
1391
1745
  _this.instruments[i].toolTipPointer.parentNode.removeChild(_this.instruments[i].toolTipPointer);
1392
1746
  _this.instruments[i].toolTip = undefined;
1393
1747
  _this.instruments[i].toolTipPointer = undefined;
1394
1748
  }
1395
1749
  }
1750
+
1396
1751
  }
1397
1752
 
1398
1753
  function clearZoom() {
@@ -1409,8 +1764,8 @@ function Milli_Chart(settings) {
1409
1764
  function onMouseMove(pos) {
1410
1765
  if (m_dataPoints.arr.length == 0) return;
1411
1766
  var rect = m_canvas.getBoundingClientRect();
1412
- var x = pos.clientX - rect.left - 1;
1413
- var y = pos.clientY - rect.top;
1767
+ var x = getScaledSetting(pos.clientX) - getScaledSetting(rect.left) - 1;
1768
+ var y = getScaledSetting(pos.clientY) - getScaledSetting(rect.top);
1414
1769
  if (m_zoom.isZooming == true) {
1415
1770
  if (m_zoom.div == null) {
1416
1771
  m_zoom.div = document.createElement('div');
@@ -1420,14 +1775,14 @@ function Milli_Chart(settings) {
1420
1775
  m_zoom.div.style.position = 'absolute';
1421
1776
  }
1422
1777
  if (x < m_chartspaces.chart.left) x = m_chartspaces.chart.left;
1423
- m_zoom.div.style.top = m_chartspaces.chart.top + 'px';
1424
- m_zoom.div.style.left = (m_zoom.mousedown.pos > x ? x : m_zoom.mousedown.pos) + 'px';
1778
+ m_zoom.div.style.top = m_chartspaces.chart.top / window.devicePixelRatio + 'px';
1779
+ m_zoom.div.style.left = (m_zoom.mousedown.pos > x / window.devicePixelRatio ? x / window.devicePixelRatio : m_zoom.mousedown.pos) + 'px';
1425
1780
  if (x > m_chartspaces.chart.right) x = m_chartspaces.chart.right;
1426
- m_zoom.div.style.height = m_chartspaces.chart.height - m_chartCss.marginBottom - m_chartspaces.chart.top + 'px';
1427
- m_zoom.div.style.width = (m_zoom.mousedown.pos > x ? m_zoom.mousedown.pos - x : x - m_zoom.mousedown.pos) + 'px';
1781
+ m_zoom.div.style.height = (m_chartspaces.chart.height / window.devicePixelRatio) - (m_chartCss.marginBottom / window.devicePixelRatio) - m_chartspaces.chart.top + 'px';
1782
+ m_zoom.div.style.width = (m_zoom.mousedown.pos > (x / window.devicePixelRatio) ? m_zoom.mousedown.pos - (x / window.devicePixelRatio) : (x / window.devicePixelRatio) - m_zoom.mousedown.pos) + 'px';
1428
1783
  }
1429
1784
  if (typeof _this.settings.tooltip != 'object' || typeof _this.settings.tooltip.formatter != 'function') return;
1430
- if (x < m_chartspaces.chart.left || x > m_chartspaces.chart.right || y < m_chartspaces.chart.top || y > m_chartspaces.chart.height - m_chartCss.marginBottom) {
1785
+ if (x < m_chartspaces.chart.left || x > m_chartspaces.chart.right || y < m_chartspaces.chart.top || y > m_chartspaces.chart.height - getScaledSetting(m_chartCss.marginBottom)) {
1431
1786
  onMouseOut();
1432
1787
  return;
1433
1788
  }
@@ -1461,44 +1816,42 @@ function Milli_Chart(settings) {
1461
1816
  MillistreamWidgetApi_AssignObject(obj.instruments[x], instr.data);
1462
1817
  instr.data.price = formatNiceNumber(instr.data.price, _this.settings.thousandseparator, _this.settings.decimalseparator, _this.settings.num_decimals, false);
1463
1818
 
1464
- var ttip = _this.settings.tooltip.formatter.call(instr);
1465
1819
  if (typeof _this.instruments[x].toolTip === 'undefined') {
1466
- // add textdiv
1820
+
1467
1821
  _this.instruments[x].toolTip = document.createElement('div');
1468
- _this.instruments[x].toolTip.style.display = 'block';
1469
- _this.instruments[x].toolTip.setAttribute('class', 'millistream-chart-tooltip'); // set class so we can measure it might change below depending on position
1822
+ _this.instruments[x].toolTip.style.display = _this.settings.tooltip.display;
1823
+ _this.instruments[x].toolTip.setAttribute('class', 'millistream-chart-tooltip');
1470
1824
  _this.instruments[x].toolTip.position = 'absolute';
1471
1825
  m_canvas.parentNode.appendChild(_this.instruments[x].toolTip);
1472
- // add pointer div
1826
+
1473
1827
  _this.instruments[x].toolTipPointer = document.createElement('div');
1474
1828
  m_canvas.parentNode.appendChild(_this.instruments[x].toolTipPointer);
1475
1829
  _this.instruments[x].toolTipPointer.setAttribute('class', 'millistream-chart-pointer');
1476
1830
  _this.instruments[x].toolTipPointer.style.left = (m_dataPoints.arr[i] - (_this.instruments[x].toolTipPointer.clientWidth / 2)) + 'px';
1477
1831
  _this.instruments[x].toolTipPointer.style.top = (obj.instruments[x].y - (_this.instruments[x].toolTipPointer.clientHeight / 2)) + 'px';
1478
1832
  _this.instruments[x].toolTipPointer.style.position = 'absolute';
1479
- _this.instruments[x].toolTipPointer.style.backgroundColor = m_instrumentCss[x].color;
1833
+ _this.instruments[x].toolTipPointer.style.backgroundColor = typeof m_instrumentCss[x].pointerColor === 'string' ? m_instrumentCss[x].pointerColor : m_instrumentCss[x].color;
1480
1834
  _this.instruments[x].toolTipPointer.style.pointerEvents = 'none';
1481
1835
 
1482
1836
  }
1483
1837
  var pointerStyle = getComputedStyle(_this.instruments[x].toolTipPointer);
1484
1838
  var pointerWidth = _this.instruments[x].toolTipPointer.offsetWidth + parseInt(pointerStyle.marginLeft) + parseInt(pointerStyle.marginRight);
1485
1839
  var pointerHeight = _this.instruments[x].toolTipPointer.offsetHeight + parseInt(pointerStyle.marginTop) + parseInt(pointerStyle.marginBottom);
1486
- _this.instruments[x].toolTip.innerHTML = ttip;
1487
1840
  var posy = obj.instruments[x].y - (_this.instruments[x].toolTip.offsetHeight / 2);
1488
- if (m_dataPoints.arr[i] + (_this.instruments[x].toolTip.offsetWidth * 1.5) > m_canvas.width || m_dataPoints.arr[i] + (_this.instruments[x].toolTip.offsetWidth * 1.5) > m_canvas.width) { // TODO +10 should be calculated better
1489
- // draw the hover to the left
1490
- _this.instruments[x].toolTip.style.left = (m_dataPoints.arr[i] - _this.instruments[x].toolTip.offsetWidth - (pointerWidth / 2)) + 1 + 'px';
1841
+ if (m_dataPoints.arr[i] + (_this.instruments[x].toolTip.offsetWidth * 1.5) > m_canvas.width) {
1842
+
1843
+ _this.instruments[x].toolTip.style.left = (obj.instruments[x].x - _this.instruments[x].toolTip.offsetWidth - (pointerWidth / 2)) + 1 + 'px';
1491
1844
  } else {
1492
- // draw hover to the right
1845
+
1493
1846
  _this.instruments[x].toolTip.style.left = (obj.instruments[x].x + (pointerWidth / 2)) + 'px';
1494
1847
  }
1495
1848
  _this.instruments[x].toolTip.style.top = posy + 'px';
1496
1849
  toolArray.push({ top: (obj.instruments[x].y - (pointerHeight / 2)), instrument: x });
1497
- _this.instruments[x].toolTipPointer.style.left = (obj.instruments[x].x - (pointerWidth / 2)) + 1 + 'px'; // hmm plus 1??
1850
+ _this.instruments[x].toolTipPointer.style.left = (obj.instruments[x].x - (pointerWidth / 2)) + 1 + 'px';
1498
1851
  _this.instruments[x].toolTipPointer.style.top = (obj.instruments[x].y - (pointerHeight / 2)) + 'px';
1499
1852
  if (posy > highy) highy = posy;
1500
1853
  if (posy < lowy) lowy = posy;
1501
-
1854
+ _this.instruments[x].toolTip.innerHTML = _this.settings.tooltip.formatter.call(instr, m_chartspaces, obj.instruments[x].x);
1502
1855
  } else {
1503
1856
  if (_this.instruments[x].toolTip) {
1504
1857
  _this.instruments[x].toolTip.parentNode.removeChild(_this.instruments[x].toolTip);
@@ -1511,10 +1864,9 @@ function Milli_Chart(settings) {
1511
1864
  toolArray.sort((a, b) => a.top - b.top);
1512
1865
  var lastTop = 0;
1513
1866
  for (x = 0; x < toolArray.length; x++) {
1514
- if (x != 0) {
1515
- //console.log(lastTop,_this.instruments[x-1].toolTip.offsetHeight , toolArray[x].top);
1867
+ if (x != 0 && typeof _this.instruments[x - 1].toolTip !== 'undefined') {
1516
1868
  if (lastTop + _this.instruments[x - 1].toolTip.offsetHeight > toolArray[x].top) {
1517
- toolArray[x].top = lastTop + _this.instruments[x - 1].toolTip.offsetHeight;
1869
+ toolArray[x].top = (lastTop + _this.instruments[x - 1].toolTip.offsetHeight);
1518
1870
  }
1519
1871
  }
1520
1872
  _this.instruments[toolArray[x].instrument].toolTip.style.top = toolArray[x].top + 'px';
@@ -1533,12 +1885,28 @@ function Milli_Chart(settings) {
1533
1885
  _this.settings.timespanelement.innerHTML = startdate.toISOString().substring(0, 10) + ' - ' + enddate.toISOString().substring(0, 10);
1534
1886
  }
1535
1887
  }
1888
+ _this.getDateInterval = function() {
1889
+ return {
1890
+ startdate: new Date(_this.scaleinfoX.startTimeStamp).toISOString().substring(0, 10),
1891
+ enddate: new Date(_this.scaleinfoX.endTimeStamp).toISOString().substring(0, 10)
1892
+ };
1893
+
1894
+ }
1536
1895
 
1537
1896
  _this.setDateInterval = function(startdate, enddate) {
1538
1897
  startdate = startdate.replaceAll('\/', '-');
1539
1898
  enddate = enddate.replaceAll('\/', '-');
1540
- m_zoom.mousedown.timestamp = new Date(startdate + 'T00:00:00Z');
1899
+ m_zoom.mousedown.timestamp = findFirstWeekDay(new Date(startdate + 'T00:00:00Z'));
1900
+
1901
+
1541
1902
  m_zoom.mouseup.timestamp = new Date(enddate + 'T00:00:00Z');
1903
+
1904
+ if (m_zoom.mouseup.timestamp > new Date()) {
1905
+ m_zoom.mouseup.timestamp = new Date().toISOString().split('T')[0];
1906
+ m_zoom.mouseup.timestamp = new Date(m_zoom.mouseup.timestamp + 'T00:00:00Z');
1907
+ }
1908
+ _this.settings.chartlen = 'max';
1909
+ _this.scaleinfoY.type == 'history';
1542
1910
  _this.drawChart();
1543
1911
  };
1544
1912
 
@@ -1546,20 +1914,18 @@ function Milli_Chart(settings) {
1546
1914
  var i, s;
1547
1915
  var instrumentprice;
1548
1916
 
1549
- if (_this.instruments.length > 1) {
1550
- for (s = 1; s < _this.instruments.length; s++) {
1551
- if (_this.instruments[s].insref != 0) {
1552
- for (i = 0; i < _this.instruments[s].history.length; i++) {
1553
- if (_this.instruments[s].history[i].timestamp >= _this.scaleinfoX.startTimeStamp) {
1554
- for (var x = 0; x < _this.instruments[0].history.length; x++) {
1555
- if (_this.instruments[0].history[x].timestamp >= _this.instruments[s].history[i].timestamp) {
1556
- instrumentprice = _this.instruments[0].history[x].price;
1557
- break;
1558
- }
1917
+ for (s = 1; s < _this.instruments.length; s++) {
1918
+ if (_this.instruments[s].insref != 0) {
1919
+ for (i = 0; i < _this.instruments[s].history.length; i++) {
1920
+ if (_this.instruments[s].history[i].timestamp >= _this.scaleinfoX.startTimeStamp) {
1921
+ for (var x = 0; x < _this.instruments[0].history.length; x++) {
1922
+ if (_this.instruments[0].history[x].timestamp >= _this.instruments[s].history[i].timestamp) {
1923
+ instrumentprice = _this.instruments[0].history[x].price;
1924
+ break;
1559
1925
  }
1560
- _this.instruments[s].factor = instrumentprice / _this.instruments[s].history[i].price;
1561
- break;
1562
1926
  }
1927
+ _this.instruments[s].factor = instrumentprice / _this.instruments[s].history[i].price;
1928
+ break;
1563
1929
  }
1564
1930
  }
1565
1931
  }
@@ -1575,9 +1941,9 @@ function Milli_Chart(settings) {
1575
1941
  }
1576
1942
  }
1577
1943
  }
1578
- console.log('NO data to draw on');
1579
- var y = m_chartspaces.chart.bottom - m_chartspaces.chart.top / 2 + m_chartspaces.chart.top;
1580
- var x = m_chartspaces.chart.right - m_chartspaces.chart.left / 2 + m_chartspaces.chart.left;
1944
+ if (_this.scaleinfoY.type == 'trades' && count > 0 && _this.instruments[0].closeprice1d) return true;
1945
+ var y = (m_chartspaces.chart.bottom - m_chartspaces.chart.top) / 2 + m_chartspaces.chart.top;
1946
+ var x = (m_chartspaces.chart.right - m_chartspaces.chart.left) / 2 + m_chartspaces.chart.left;
1581
1947
  m_ctx.save();
1582
1948
  m_ctx.font = 'bold ' + m_xLegendCss.fontSize + ' ' + m_xLegendCss.fontFamily;
1583
1949
  m_ctx.font = 'bold 12px ' + m_xLegendCss.fontFamily;
@@ -1592,20 +1958,48 @@ function Milli_Chart(settings) {
1592
1958
 
1593
1959
  function calcChartSpaces() {
1594
1960
  m_chartspaces.chart.height = Math.round(m_canvas.height * (m_chartspaces.chart.percent / 100));
1595
- m_chartspaces.chart.top = m_chartCss.marginTop;
1596
- m_chartspaces.chart.left = m_chartCss.marginLeft;
1597
- m_chartspaces.chart.right = m_canvas.width - m_chartCss.marginRight;
1598
- m_chartspaces.chart.bottom = m_chartspaces.chart.height - m_chartCss.marginBottom;
1961
+ m_chartspaces.chart.top = getScaledSetting(m_chartCss.marginTop);
1962
+ m_chartspaces.chart.left = getScaledSetting(m_chartCss.marginLeft);
1963
+ m_chartspaces.chart.right = m_canvas.width - getScaledSetting(m_chartCss.marginRight);
1964
+ m_chartspaces.chart.bottom = m_chartspaces.chart.height - getScaledSetting(m_chartCss.marginBottom);
1599
1965
  m_chartspaces.chart.width = m_canvas.width;
1600
1966
  m_chartspaces.lowerChart.height = m_canvas.height * (m_chartspaces.lowerChart.percent / 100);
1601
- m_chartspaces.lowerChart.top = Math.round(m_chartspaces.chart.bottom + m_chartCss.marginBottom + m_chartspaces.chart.top);
1967
+ m_chartspaces.lowerChart.top = Math.round(m_chartspaces.chart.bottom + getScaledSetting(m_chartCss.marginBottom) + m_chartspaces.chart.top);
1602
1968
  m_chartspaces.lowerChart.left = m_chartspaces.chart.left;
1603
1969
  m_chartspaces.lowerChart.right = m_chartspaces.chart.right;
1604
- m_chartspaces.lowerChart.bottom = m_canvas.height - m_chartCss.marginBottom;
1970
+ m_chartspaces.lowerChart.bottom = m_canvas.height - getScaledSetting(m_chartCss.marginBottom);
1605
1971
  m_chartspaces.lowerChart.width = m_canvas.width;
1606
1972
  }
1607
1973
 
1608
1974
  _this.drawChart = function() {
1975
+ if (m_zoom.isZooming) {
1976
+ return;
1977
+ }
1978
+
1979
+ for (var i = 0; i < _this.settings.indicators.length; i++) {
1980
+ switch (_this.settings.indicators[i].method) {
1981
+ case 'sma':
1982
+ {
1983
+ _this.settings.indicators[i].history = simpleMovingAverage(_this.instruments[0].history, _this.settings.indicators[i].method_length);
1984
+ _this.settings.indicators[i].trades = simpleMovingAverage(_this.instruments[0].trades, _this.settings.indicators[i].method_length);
1985
+ }
1986
+ break;
1987
+ case 'ema':
1988
+ {
1989
+ _this.settings.indicators[i].history = exponentialMovingAverage(_this.instruments[0].history, _this.settings.indicators[i].method_length);
1990
+ _this.settings.indicators[i].trades = exponentialMovingAverage(_this.instruments[0].trades, _this.settings.indicators[i].method_length);
1991
+ break;
1992
+ }
1993
+ case 'bb':
1994
+ {
1995
+ _this.settings.indicators[i].history = bollingerBands(_this.instruments[0].history, _this.settings.indicators[i].method_length, _this.settings.indicators[i].stddev | 2);
1996
+ _this.settings.indicators[i].trades = bollingerBands(_this.instruments[0].trades, _this.settings.indicators[i].method_length, _this.settings.indicators[i].stddev | 2);
1997
+ break;
1998
+ }
1999
+ default:
2000
+ break;
2001
+ }
2002
+ }
1609
2003
  if (m_lastDrawnInstrument != _this.instruments[0].insref) {
1610
2004
  m_zoom.mousedown.pos = 0;
1611
2005
  m_zoom.mousedown.i = 0;
@@ -1614,31 +2008,6 @@ function Milli_Chart(settings) {
1614
2008
  if (m_zoom.div) m_canvas.parentNode.removeChild(m_zoom.div);
1615
2009
  m_zoom.div = null;
1616
2010
  m_zoom.isZooming = false;
1617
- for (const [key, a] of m_analyzisMethod.entries()) {
1618
- switch (a.method) {
1619
- case 'sma':
1620
- {
1621
- a.history = simpleMovingAverage(_this.instruments[0].history, a.length);
1622
- a.trades = simpleMovingAverage(_this.instruments[0].trades, a.length);
1623
- }
1624
- break;
1625
- case 'ema':
1626
- {
1627
- a.history = exponentialMovingAverage(_this.instruments[0].history, a.length);
1628
- a.trades = exponentialMovingAverage(_this.instruments[0].trades, a.length);
1629
- break;
1630
- }
1631
- case 'bollinger':
1632
- {
1633
- a.history = bollingerBands(_this.instruments[0].history, a.length, a.stddev | 2);
1634
- a = bollingerBands(_this.instruments[0].trades, a.length, a.stddev | 2);
1635
- break;
1636
- }
1637
- default:
1638
- break;
1639
- }
1640
- }
1641
-
1642
2011
  }
1643
2012
  m_lastDrawnInstrument = _this.instruments[0].insref;
1644
2013
  if (m_ctx == null) return;
@@ -1647,7 +2016,7 @@ function Milli_Chart(settings) {
1647
2016
  m_dataPoints.map = new Map();
1648
2017
  m_dataPoints.arr = [];
1649
2018
  if (_this.instruments.length < 0) {
1650
- console.log('no chartdata');
2019
+
1651
2020
  return;
1652
2021
  }
1653
2022
  calcChartSpaces();
@@ -1655,53 +2024,52 @@ function Milli_Chart(settings) {
1655
2024
  var period = _this.settings.chartlen.substring(_this.settings.chartlen.length - 1);
1656
2025
  var len = parseInt(_this.settings.chartlen.substring(0, _this.settings.chartlen.length - 1));
1657
2026
  m_ctx.clearRect(0, 0, m_canvas.width, m_canvas.height);
1658
- m_ctx.fillStyle = m_chartCss.backgroundColor;
1659
- m_ctx.fillRect(0, 0, m_canvas.width, m_canvas.height);
1660
- m_ctx.lineWidth = 1;
1661
- m_ctx.textBaseline = 'top'; // important!
2027
+ m_ctx.lineWidth = 1 / window.devicePixelRatio;
2028
+ m_ctx.textBaseline = 'top';
1662
2029
  var i;
1663
- if (period == 'd' && _this.instruments[0].trades.length != 0 && _this.settings.chartlen != 'ytd') {
2030
+ if (period == 'd' && _this.settings.chartlen != 'ytd') {
1664
2031
  if (m_zoom.mousedown.timestamp) {
1665
2032
  _this.scaleinfoX.endTimeStamp = m_zoom.mouseup.timestamp > m_zoom.mousedown.timestamp ? m_zoom.mouseup.timestamp : m_zoom.mousedown.timestamp;
1666
2033
  _this.scaleinfoX.startTimeStamp = m_zoom.mouseup.timestamp < m_zoom.mousedown.timestamp ? m_zoom.mouseup.timestamp : m_zoom.mousedown.timestamp;
1667
2034
  } else {
1668
- _this.scaleinfoX.startTimeStamp = getTickStartDate(len); // calc not to start with weekends
1669
- // back up x days from quotedate if needed
1670
- // TODO if startTimeStamp < quotedate -len borde det vara
2035
+ _this.scaleinfoX.startTimeStamp = getTickStartDate(len);
2036
+
2037
+
1671
2038
  var quoteDate = businessDaysSubtraction(_this.instruments[0].quotedate, len);
1672
- if (_this.scaleinfoX.startTimeStamp - _this.scaleinfoX.startTimeStamp % 86400000 > quoteDate) { // if startdate > quotedate back startdate
2039
+ if (_this.scaleinfoX.startTimeStamp - _this.scaleinfoX.startTimeStamp % 86400000 > quoteDate) {
1673
2040
  _this.scaleinfoX.startTimeStamp -= _this.scaleinfoX.startTimeStamp - _this.scaleinfoX.startTimeStamp % 86400000;
1674
2041
  _this.scaleinfoX.startTimeStamp += quoteDate;
1675
- //_this.scaleinfoX.startTimeStamp += _this.instruments[0].quotedate;
1676
- //if (len > 1) _this.scaleinfoX.startTimeStamp -= (86400000 * (len - 1));
1677
2042
  }
1678
- _this.scaleinfoX.endTimeStamp = new Date(); // om helg TODO
2043
+ _this.scaleinfoX.endTimeStamp = new Date();
1679
2044
  if (len > 1)
1680
2045
  _this.scaleinfoX.endTimeStamp = new Date(_this.scaleinfoX.endTimeStamp.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketclose + 'Z').getTime();
1681
2046
  else if (len == 1) {
1682
- // check if startdate is not today (due to exchange is closed f ex DJ)
2047
+
1683
2048
  if (_this.scaleinfoX.startTimeStamp % 86400000 != new Date().getTime() % 86400) {
1684
2049
  _this.scaleinfoX.endTimeStamp = new Date(new Date(_this.scaleinfoX.startTimeStamp).toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketclose + 'Z').getTime();
1685
2050
  } else
1686
2051
  _this.scaleinfoX.endTimeStamp = new Date(_this.scaleinfoX.endTimeStamp.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketclose + 'Z').getTime();
1687
2052
  } else {
1688
- // check that the last trade is not later than closetime
2053
+
1689
2054
  var tradetimestamp = new Date(_this.instruments[0].trades[_this.instruments[0].trades.length - 1].timestamp).getTime();
1690
2055
  var closetimestamp = new Date(new Date(_this.instruments[0].trades[_this.instruments[0].trades.length - 1].timestamp).toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketclose + 'Z').getTime();
1691
2056
  if (closetimestamp < tradetimestamp)
1692
- _this.scaleinfoX.endTimeStamp = new Date(closetimestamp); // borde inte rita med closeprice1d då heller eller spelar det ingen roll?
2057
+ _this.scaleinfoX.endTimeStamp = new Date(closetimestamp);
1693
2058
  else
1694
2059
  _this.scaleinfoX.endTimeStamp = new Date(tradetimestamp);
1695
2060
  }
1696
2061
  if (_this.scaleinfoX.endTimeStamp - (_this.scaleinfoX.endTimeStamp % 86400000) > _this.instruments[0].quotedate) {
1697
2062
  _this.scaleinfoX.endTimeStamp -= _this.scaleinfoX.endTimeStamp - _this.scaleinfoX.endTimeStamp % 86400000;
1698
- _this.scaleinfoX.endTimeStamp += _this.instruments[0].quotedate; // set enddate = last Quotedate
2063
+ _this.scaleinfoX.endTimeStamp += _this.instruments[0].quotedate;
1699
2064
  }
1700
2065
  }
1701
2066
  setTimeSpanData();
1702
2067
  _this.scaleinfoY.type = 'trades';
2068
+ if (_this.settings.absoluteScaling == true) {
2069
+ for (var s = 1; s < _this.instruments.length; s++) _this.instruments[s].factor = 1;
2070
+ } else
1703
2071
  if (_this.instruments.length > 1) {
1704
- // calc factors
2072
+
1705
2073
  var instrumentprice;
1706
2074
  for (i = 0; i < _this.instruments[0].trades.length; i++) {
1707
2075
  if (_this.instruments[0].trades[i].timestamp >= _this.scaleinfoX.startTimeStamp) {
@@ -1722,51 +2090,59 @@ function Milli_Chart(settings) {
1722
2090
  }
1723
2091
  }
1724
2092
  _this.instruments[0].factor = 1;
2093
+ if (false == checkChartData(_this.instruments[0].trades)) return;
1725
2094
  drawYAxis();
1726
2095
  drawXAxisTick(_this.scaleinfoX.startTimeStamp, _this.scaleinfoX.endTimeStamp);
1727
- if (false == checkChartData(_this.instruments[0].trades)) return;
1728
2096
  for (i = 0; i < _this.instruments.length; i++) {
1729
2097
  if (_this.instruments[i].insref != 0)
1730
2098
  plotData(_this.instruments[i].trades, i);
1731
2099
  }
1732
2100
 
1733
- for (const [key, a] of m_analyzisMethod.entries()) {
1734
- if (a.method == 'bollinger') plotBollingerBand(a, 'trades');
1735
- else plotMovingAverage(a, 'trades');
2101
+ for (i = 0; i < _this.settings.indicators.length; i++) {
2102
+ if (_this.settings.indicators[i].method == 'bb') plotBollingerBand(_this.settings.indicators[i], 'trades');
2103
+ else plotMovingAverage(_this.settings.indicators[i], 'trades');
2104
+
1736
2105
  }
1737
2106
 
1738
2107
  } else
1739
2108
  if (period == 'm') {
2109
+
2110
+
1740
2111
  if (m_zoom.mousedown.timestamp) {
1741
2112
  _this.scaleinfoX.startTimeStamp = m_zoom.mousedown.timestamp > m_zoom.mouseup.timestamp ? m_zoom.mouseup.timestamp : m_zoom.mousedown.timestamp;
1742
2113
  _this.scaleinfoX.endTimeStamp = m_zoom.mousedown.timestamp > m_zoom.mouseup.timestamp ? m_zoom.mousedown.timestamp : m_zoom.mouseup.timestamp;
1743
2114
  _this.scaleinfoX.endTimeStamp -= (_this.scaleinfoX.endTimeStamp % 3600000);
1744
2115
  } else {
1745
- var startdate = new Date().getTime() - (86400000 * 365 * (isNaN(len) ? 1 : len));
1746
-
1747
- _this.scaleinfoX.startTimeStamp = subtractMonth(new Date(), len);
1748
- _this.scaleinfoX.startTimeStamp = new Date(_this.scaleinfoX.startTimeStamp.toISOString().substring(0, 10) + 'T' + '00:00:00Z').getTime();
1749
- _this.scaleinfoX.startTimeStamp = findFirstWeekDay(_this.scaleinfoX.startTimeStamp).getTime();
2116
+ var startdate = new Date();
2117
+ startdate.setMonth(startdate.getMonth() - len);
2118
+ startdate = startdate.getTime() - (startdate.getTime() % 86400000);
2119
+ startdate = findFirstWeekDay(startdate).getTime();
2120
+ _this.scaleinfoX.startTimeStamp = startdate;
1750
2121
  if (_this.instruments[0].history.length > 1 && _this.scaleinfoX.startTimeStamp < _this.instruments[0].history[0].timestamp) _this.scaleinfoX.startTimeStamp = _this.instruments[0].history[0].timestamp;
1751
- _this.scaleinfoX.endTimeStamp = new Date();
1752
- _this.scaleinfoX.endTimeStamp = new Date(_this.scaleinfoX.endTimeStamp.toISOString().substring(0, 10) + 'T' + '00:00:00Z').getTime();
2122
+
2123
+ _this.scaleinfoX.endTimeStamp = new Date().getTime();
2124
+ _this.scaleinfoX.endTimeStamp = _this.scaleinfoX.endTimeStamp - (_this.scaleinfoX.endTimeStamp % 86400000);
1753
2125
  }
1754
2126
  setTimeSpanData();
1755
2127
  _this.scaleinfoY.type = 'history';
1756
- calcCompareFactors('history');
2128
+ if (_this.settings.absoluteScaling == true) {
2129
+ for (var s = 1; s < _this.instruments.length; s++) _this.instruments[s].factor = 1;
2130
+ } else calcCompareFactors('history');
1757
2131
  _this.instruments[0].factor = 1;
1758
2132
 
2133
+ if (false == checkChartData(_this.instruments[0].history)) return;
1759
2134
  drawYAxis();
1760
2135
  drawXAxisMonth(_this.scaleinfoX.startTimeStamp, _this.scaleinfoX.endTimeStamp);
1761
- if (false == checkChartData(_this.instruments[0].history)) return;
1762
2136
 
1763
2137
  for (i = 0; i < _this.instruments.length; i++) {
1764
2138
  if (_this.instruments[i].insref != 0)
1765
2139
  plotData(_this.instruments[i].history, i);
1766
2140
  }
1767
- for (const [key, a] of m_analyzisMethod.entries()) {
1768
- if (a.method == 'bollinger') plotBollingerBand(a, 'history');
1769
- else plotMovingAverage(a, 'history');
2141
+
2142
+ for (i = 0; i < _this.settings.indicators.length; i++) {
2143
+ if (_this.settings.indicators[i].method == 'bb') plotBollingerBand(_this.settings.indicators[i], 'history');
2144
+ else plotMovingAverage(_this.settings.indicators[i], 'history');
2145
+
1770
2146
  }
1771
2147
  } else
1772
2148
  if ((period == 'y' || _this.settings.chartlen == 'ytd' || _this.settings.chartlen == 'max')) {
@@ -1776,49 +2152,58 @@ function Milli_Chart(settings) {
1776
2152
  _this.scaleinfoX.endTimeStamp = m_zoom.mousedown.timestamp > m_zoom.mouseup.timestamp ? m_zoom.mousedown.timestamp : m_zoom.mouseup.timestamp;
1777
2153
  _this.scaleinfoX.endTimeStamp -= (_this.scaleinfoX.endTimeStamp % 3600000);
1778
2154
  } else {
1779
- var startdateM;
1780
2155
  if (_this.settings.chartlen == 'max' && _this.instruments[0].history.length > 1) {
1781
- startdateM = _this.instruments[0].history[0].timestamp;
2156
+ _this.scaleinfoX.startTimeStamp = _this.instruments[0].history[0].timestamp;
1782
2157
  } else
1783
2158
  if (_this.settings.chartlen == 'ytd') {
1784
- //startdateM = new Date(new Date().getFullYear() - 1 + '-12-30').getTime(); // TODO, hur skall vi göra här om det inte finns data runt här?
1785
- startdateM = new Date(new Date().getFullYear() + '-01-01').getTime(); // TODO, hur skall vi göra här om det inte finns data runt här?
2159
+ _this.scaleinfoX.startTimeStamp = new Date(new Date().getFullYear() + '-01-01').getTime();
1786
2160
  } else {
1787
- startdateM = new Date().getTime() - (86400000 * 365 * (isNaN(len) ? 1 : len));
2161
+ _this.scaleinfoX.startTimeStamp = new Date().getTime() - (86400000 * 365 * (isNaN(len) ? 1 : len));
1788
2162
  }
1789
- if (_this.instruments[0].history.length > 1 && startdateM < _this.instruments[0].history[0].timestamp) startdateM = _this.instruments[0].history[0].timestamp;
1790
- _this.scaleinfoX.startTimeStamp = startdateM;
2163
+ if (_this.instruments[0].history.length > 1 && _this.scaleinfoX.startTimeStamp < _this.instruments[0].history[0].timestamp) _this.scaleinfoX.startTimeStamp = _this.instruments[0].history[0].timestamp;
1791
2164
  _this.scaleinfoX.startTimeStamp = findFirstWeekDay(_this.scaleinfoX.startTimeStamp).getTime();
1792
- _this.scaleinfoX.endTimeStamp = new Date();
1793
- _this.scaleinfoX.endTimeStamp = new Date(_this.scaleinfoX.endTimeStamp.toISOString().substring(0, 10) + 'T' + '00:00:00Z').getTime();
2165
+
2166
+ _this.scaleinfoX.endTimeStamp = new Date().getTime();
2167
+ _this.scaleinfoX.endTimeStamp = _this.scaleinfoX.endTimeStamp - (_this.scaleinfoX.endTimeStamp % 86400000);
1794
2168
  }
1795
2169
  setTimeSpanData();
1796
2170
  _this.scaleinfoY.type = 'history';
1797
- calcCompareFactors('history');
2171
+ if (_this.settings.absoluteScaling == true) {
2172
+ for (var s = 1; s < _this.instruments.length; s++) _this.instruments[s].factor = 1;
2173
+ } else calcCompareFactors('history');
1798
2174
 
1799
2175
  _this.instruments[0].factor = 1;
2176
+ if (false == checkChartData(_this.instruments[0].history)) return;
1800
2177
  drawYAxis();
1801
2178
  drawXAxisYears(_this.scaleinfoX.startTimeStamp, _this.scaleinfoX.endTimeStamp);
1802
- if (false == checkChartData(_this.instruments[0].history)) return;
1803
-
1804
2179
  for (i = 0; i < _this.instruments.length; i++)
1805
2180
  if (_this.instruments[i].insref != 0)
1806
2181
  plotData(_this.instruments[i].history, i);
1807
2182
 
1808
- for (const [key, a] of m_analyzisMethod.entries()) {
1809
- if (a.method == 'bollinger') plotBollingerBand(a, 'history');
1810
- else plotMovingAverage(a, 'history');
1811
- }
2183
+ for (i = 0; i < _this.settings.indicators.length; i++) {
2184
+ if (_this.settings.indicators[i].method == 'bb') plotBollingerBand(_this.settings.indicators[i], 'history');
2185
+ else plotMovingAverage(_this.settings.indicators[i], 'history');
1812
2186
 
2187
+ }
1813
2188
 
1814
- }
2189
+ }
1815
2190
  drawBoxShadow(m_chartspaces.chart);
2191
+
1816
2192
  if (m_chartspaces.chart.percent != 100) {
1817
2193
  drawXAxisTickLowerChart();
1818
2194
  drawYAxisLower();
1819
2195
  drawBoxShadow(m_chartspaces.lowerChart);
1820
2196
  }
1821
- //onMouseOut();
2197
+ if (typeof m_chartCss.backgroundColor !== 'undefined') {
2198
+ m_ctx.save();
2199
+ if (_this.settings.curveOnTop == false)
2200
+ m_ctx.globalCompositeOperation = 'destination-over'
2201
+ m_ctx.fillStyle = m_chartCss.backgroundColor;
2202
+
2203
+ m_ctx.fillRect(0, 0, m_canvas.width, m_canvas.height);
2204
+ m_ctx.restore();
2205
+ }
2206
+
1822
2207
  };
1823
2208
 
1824
2209
  function drawBoxShadow(space) {
@@ -1847,14 +2232,16 @@ function Milli_Chart(settings) {
1847
2232
  return item.insref == data.insref;
1848
2233
  });
1849
2234
  if (instr == null) return;
1850
- /*var last = 0;*/
2235
+
1851
2236
  if (typeof data.name !== 'undefined') instr.name = data.name;
2237
+ if (typeof data.pricetype !== 'undefined') instr.pricetype = data.pricetype;
2238
+ else instr.pricetype = 'price';
1852
2239
  if (typeof data.symbol !== 'undefined') instr.symbol = data.symbol;
1853
2240
  if (typeof data.ticksize !== 'undefined') _this.settings.num_decimals = data.ticksize;
1854
2241
 
1855
2242
  if (typeof data.tradecurrency !== 'undefined') instr.tradecurrency = data.tradecurrency;
1856
2243
  if (data.marketopen && data.marketclose) {
1857
- if (new Date('2020-01-01T' + data.marketopen + 'Z') > new Date('2020-01-01T' + data.marketclose + 'Z')) { // om close är tidiagre än open så sätter vi nedan tider
2244
+ if (new Date('2020-01-01T' + data.marketopen + 'Z') > new Date('2020-01-01T' + data.marketclose + 'Z')) {
1858
2245
  data.marketopen = '00:00:00';
1859
2246
  data.marketclose = '22:00:00';
1860
2247
  }
@@ -1883,17 +2270,15 @@ function Milli_Chart(settings) {
1883
2270
  }
1884
2271
  var i, item;
1885
2272
  if (typeof data.trades !== 'undefined') {
2273
+ instr.trades = [];
2274
+ instr.hashmap.clear();
1886
2275
  for (i = 0; i < data.trades.length; i++) {
1887
- if (data.trades[i].tradecode & 16) { // canceltrade
2276
+ if (data.trades[i].tradecode & 16) {
1888
2277
  continue;
1889
2278
  }
1890
- var date = new Date(data.trades[i].timestamp).toISOString().split('T')[0];
1891
- if (!m_tradedates.includes(date)) m_tradedates.push(date);
1892
2279
  item = [];
1893
2280
  item.timestamp = data.trades[i].timestamp - (data.trades[i].timestamp % 60000);
1894
2281
 
1895
- /*if (last > item.timestamp)
1896
- last = item.timestamp;*/
1897
2282
  if (typeof data.trades[i].tradeprice !== 'undefined') item.price = parseFloat(data.trades[i].tradeprice) * factor;
1898
2283
  if (typeof data.trades[i].tradequantity !== 'undefined' && data.trades[i].tradequantity != null) {
1899
2284
  item.quantity = parseInt(data.trades[i].tradequantity);
@@ -1905,15 +2290,20 @@ function Milli_Chart(settings) {
1905
2290
  }
1906
2291
  instr.trades.push(item);
1907
2292
  instr.hashmap.set(item.timestamp, item);
2293
+
2294
+ instr.trades.sort(function(a, b) {
2295
+ return a.timestamp - b.timestamp;
2296
+ });
1908
2297
  }
1909
2298
  }
1910
2299
  if (typeof data.closeprice1d !== 'undefined') {
1911
2300
  instr.closeprice1d = data.closeprice1d;
1912
2301
  }
1913
2302
  if (typeof data.history !== 'undefined') {
2303
+ instr.history = [];
1914
2304
  for (i = 0; i < data.history.length; i++) {
1915
2305
  item = [];
1916
- if (typeof data.history[i].date !== 'undefined' && data.history[i].closeprice != null) { // inget pris eller datum = onintressant, borde kanske skippas vid selecten i pitten också
2306
+ if (typeof data.history[i].date !== 'undefined' && data.history[i].closeprice != null) {
1917
2307
  var timestamp = new Date(data.history[i].date + 'T00:00:00Z').getTime();
1918
2308
  item.timestamp = timestamp;
1919
2309
  } else continue;
@@ -1923,15 +2313,14 @@ function Milli_Chart(settings) {
1923
2313
  if (typeof data.history[i].dividend !== 'undefined') item.dividend = data.history[i].dividend;
1924
2314
  instr.history.push(item);
1925
2315
  }
1926
- if (_this.settings.hcurve && instr.history.length > 0) { // varför på all historik, och inte bara på hcurve
2316
+ if (_this.settings.hcurve && instr.history.length > 0) {
1927
2317
  if (!isToday(new Date(instr.history[instr.history.length - 1].timestamp))) {
1928
2318
  var addItem = {};
1929
2319
  MillistreamWidgetApi_AssignObject(instr.history[instr.history.length - 1], addItem);
1930
- addItem.timestamp = new Date(formatDate(new Date(), 'yyyy-mm-dd') + 'T00:00:00Z').getTime();
2320
+ addItem.timestamp = new Date(formatDate(new Date(), 'yyyy-mm-dd', _this) + 'T00:00:00Z').getTime();
1931
2321
  instr.history.push(addItem);
1932
2322
  }
1933
2323
  }
1934
- //console.log(instr.history);
1935
2324
  }
1936
2325
  }
1937
2326
 
@@ -1948,41 +2337,8 @@ function Milli_Chart(settings) {
1948
2337
  _this.drawChart();
1949
2338
  };
1950
2339
 
1951
- _this.resizeStart = function(e, ui) {
1952
- m_resizing.width = m_canvas.width;
1953
- m_resizing.height = m_canvas.height;
1954
- };
1955
-
1956
- _this.resize = function(e, ui) {
1957
- var diff = (m_resizing.height - m_canvas.height) / m_canvas.height * 100;
1958
- if (Math.abs(diff) > 1) {
1959
- setChartSize();
1960
- m_resizing.width = m_canvas.width;
1961
- m_resizing.height = m_canvas.height;
1962
- _this.drawChart();
1963
- } else {
1964
- diff = (m_resizing.width - m_canvas.width) / m_canvas.width * 100;
1965
- if (Math.abs(diff) > 1) {
1966
- setChartSize();
1967
- m_canvas.height = _this.settings.target.offsetHeight;
1968
- m_canvas.width = _this.settings.target.offsetWidth;
1969
- m_resizing.width = m_canvas.width;
1970
- m_resizing.height = m_canvas.height;
1971
- _this.drawChart();
1972
- }
1973
- }
1974
- var cache = m_ctx.getImageData(0, 0, m_canvas.width, m_canvas.height);
1975
- setChartSize();
1976
- m_ctx.putImageData(cache, 0, 0);
1977
- };
1978
-
1979
- _this.resizeEnd = function(e, ui) {
1980
- setChartSize();
1981
- _this.drawChart();
1982
- };
1983
-
1984
2340
  function plotExternalHistoricalData(data) {
1985
- // används för dividend osv
2341
+
1986
2342
  m_ctx.save();
1987
2343
  var startpoint = { x: 0, y: 0 };
1988
2344
  var endpoint = { x: 0, y: 0 };
@@ -2006,26 +2362,26 @@ function Milli_Chart(settings) {
2006
2362
  currentDate.setMinutes(lastdate.getMinutes());
2007
2363
  currentDate.setSeconds(lastdate.getSeconds());
2008
2364
 
2009
- if (lastdate.toISOString().substring(0, 10) != currentDate.toISOString().substring(0, 10)) { // new date
2365
+ if (lastdate.toISOString().substring(0, 10) != currentDate.toISOString().substring(0, 10)) {
2010
2366
  var tmp = new Date(lastdate.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketclose + 'Z');
2011
2367
  var nextDate = new Date(data[i].timestamp);
2012
- tmp = tmp.getTime() + 86400000 - _this.scaleinfoX.milliPerDay; // increase to next days starttime
2368
+ tmp = tmp.getTime() + 86400000 - _this.scaleinfoX.milliPerDay;
2013
2369
  currentDate = new Date(tmp);
2014
2370
  while (dateDiffInDays(currentDate, nextDate) > 0) {
2015
2371
  if (currentDate.getDay() == 0 || currentDate.getDay() == 6)
2016
2372
  offset += 86400000 / _this.scaleinfoX.timePerPixel;
2017
2373
  else
2018
- offset += ((86400000 - _this.scaleinfoX.milliPerDay) / _this.scaleinfoX.timePerPixel); // * dateDiffInDays(lastdate, currentDate);
2374
+ offset += ((86400000 - _this.scaleinfoX.milliPerDay) / _this.scaleinfoX.timePerPixel);
2019
2375
  currentDate = new Date(currentDate.getTime() + 86400000);
2020
2376
  }
2021
- offset += ((86400000 - _this.scaleinfoX.milliPerDay) / _this.scaleinfoX.timePerPixel); // * dateDiffInDays(lastdate, currentDate);
2377
+ offset += ((86400000 - _this.scaleinfoX.milliPerDay) / _this.scaleinfoX.timePerPixel);
2022
2378
  lastdate = currentDate;
2023
2379
  startpoint.x = Math.round(m_chartspaces.chart.left + ((data[i].timestamp - startDate) / _this.scaleinfoX.timePerPixel)) + 0.5 - offset;
2024
- // TODO: här blir det fel när det är från 00:00: 23:59 men göms av tmpx < startpoint.x
2380
+
2025
2381
 
2026
2382
  }
2027
- //startpoint.y = Math.round(m_canvas.height - m_chartCss.marginBottom - (((data[i].price * factor) - _this.scaleinfoY.minValue) * _this.scaleinfoY.valuePerPixel)) + 0.5;
2028
- startpoint.y = Math.round(m_chartspaces.chart.height - m_chartCss.marginBottom - (((data[i].price * factor) - _this.scaleinfoY.minValue) * _this.scaleinfoY.valuePerPixel)) + 0.5;
2383
+
2384
+ startpoint.y = Math.round(m_chartspaces.chart.height - getScaledSetting(m_chartCss.marginBottom) - (((data[i].price * factor) - _this.scaleinfoY.minValue) * _this.scaleinfoY.valuePerPixel)) + 0.5;
2029
2385
  maxy = maxy > startpoint.y ? maxy : startpoint.y;
2030
2386
 
2031
2387
  startpoint.x = Math.round(m_chartspaces.chart.left + ((data[i].timestamp - _this.scaleinfoX.startDate.getTime()) / _this.scaleinfoX.timePerPixel)) + 0.5;
@@ -2066,19 +2422,19 @@ function Milli_Chart(settings) {
2066
2422
  var endtimeToday = new Date(data[i].timestamp);
2067
2423
  if (endtimeToday.getDay() == 0 || endtimeToday.getDay() == 6) continue;
2068
2424
  if (_this.scaleinfoY.type != 'history') {
2069
- endtimeToday = new Date(endtimeToday.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketclose + 'Z'); // borde räcka att göra 1 gång när det blir nytt datum
2425
+ endtimeToday = new Date(endtimeToday.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketclose + 'Z');
2070
2426
  }
2071
2427
  if (data[i].timestamp > endtimeToday.getTime()) {
2072
- continue; // dataticks efter stängning ritas inte
2428
+ continue;
2073
2429
  }
2074
2430
  currentDate = new Date(data[i].timestamp);
2075
2431
  currentDate.setHours(lastdate.getHours());
2076
2432
  currentDate.setMinutes(lastdate.getMinutes());
2077
2433
  currentDate.setSeconds(lastdate.getSeconds());
2078
- if (lastdate.toISOString().substring(0, 10) != currentDate.toISOString().substring(0, 10)) { // new date
2434
+ if (lastdate.toISOString().substring(0, 10) != currentDate.toISOString().substring(0, 10)) {
2079
2435
  tmp = new Date(lastdate.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketclose + 'Z');
2080
2436
  var nextDate = new Date(data[i].timestamp);
2081
- tmp = tmp.getTime() + 86400000 - _this.scaleinfoX.milliPerDay; // increase to next days starttime
2437
+ tmp = tmp.getTime() + 86400000 - _this.scaleinfoX.milliPerDay;
2082
2438
 
2083
2439
  currentDate = new Date(tmp);
2084
2440
  while (dateDiffInDays(currentDate, nextDate) > 0) {
@@ -2088,16 +2444,16 @@ function Milli_Chart(settings) {
2088
2444
  offset += ((86400000 - _this.scaleinfoX.milliPerDay) / _this.scaleinfoX.timePerPixel);
2089
2445
  currentDate = new Date(currentDate.getTime() + 86400000);
2090
2446
  }
2091
- offset += ((86400000 - _this.scaleinfoX.milliPerDay) / _this.scaleinfoX.timePerPixel); // * dateDiffInDays(lastdate, currentDate);
2447
+ offset += ((86400000 - _this.scaleinfoX.milliPerDay) / _this.scaleinfoX.timePerPixel);
2092
2448
  lastdate = currentDate;
2093
2449
  startpoint.x = Math.round(m_chartspaces.chart.left + ((data[i].timestamp - startDate) / _this.scaleinfoX.timePerPixel)) + 0.5 - offset;
2094
2450
 
2095
- // TODO: här blir det fel när det är från 00:00: 23:59 men göms av tmpx < startpoint.x
2451
+
2096
2452
  if (_this.scaleinfoY.type == 'trades' && tmpx < startpoint.x) {
2097
2453
  ret.push(startpoint.x, startpoint.y);
2098
2454
  }
2099
2455
  }
2100
- startpoint.y = Math.round(m_chartspaces.chart.height - m_chartCss.marginBottom - ((data[i].datapoints[pricecol] - _this.scaleinfoY.minValue) * _this.scaleinfoY.valuePerPixel)) + 0.5;
2456
+ startpoint.y = Math.round(m_chartspaces.chart.height - getScaledSetting(m_chartCss.marginBottom) - ((data[i].datapoints[pricecol] - _this.scaleinfoY.minValue) * _this.scaleinfoY.valuePerPixel)) + 0.5;
2101
2457
  maxy = maxy > startpoint.y ? maxy : startpoint.y;
2102
2458
 
2103
2459
  startpoint.x = Math.round(m_chartspaces.chart.left + ((data[i].timestamp - _this.scaleinfoX.startDate.getTime()) / _this.scaleinfoX.timePerPixel)) + 0.5;
@@ -2128,7 +2484,7 @@ function Milli_Chart(settings) {
2128
2484
  if (line.length == 0) return;
2129
2485
  m_ctx.save();
2130
2486
  m_ctx.beginPath();
2131
- m_ctx.closePath(); // clear path
2487
+ m_ctx.closePath();
2132
2488
  m_ctx.moveTo(line[0].x, line[0].y);
2133
2489
  for (var i = 1; i < line.length; i++) {
2134
2490
  m_ctx.lineTo(line[i].x, line[i].y);
@@ -2146,11 +2502,11 @@ function Milli_Chart(settings) {
2146
2502
  m_ctx.lineWidth = method.lineWidth | 1;
2147
2503
  m_ctx.save();
2148
2504
  m_ctx.beginPath();
2149
- var upper = calcAnalyzisLine(data, 0, null);
2150
- var lower = calcAnalyzisLine(data, 1, null);
2505
+ upper = calcAnalyzisLine(data, 0, null);
2506
+ lower = calcAnalyzisLine(data, 1, null);
2151
2507
  for (var i = 0; i < upper.length; i++) m_ctx.lineTo(upper[i].x, upper[i].y);
2152
2508
  m_ctx.lineTo(lower[lower.length - 1].x, lower[lower.length - 1].y);
2153
- for (var i = lower.length - 1; i >= 0; i--) m_ctx.lineTo(lower[i].x, lower[i].y);
2509
+ for (i = lower.length - 1; i >= 0; i--) m_ctx.lineTo(lower[i].x, lower[i].y);
2154
2510
  if (method.border) m_ctx.stroke();
2155
2511
  m_ctx.closePath();
2156
2512
  if (method.fill) {
@@ -2159,9 +2515,9 @@ function Milli_Chart(settings) {
2159
2515
  }
2160
2516
  var sma = calcAnalyzisLine(data, 2);
2161
2517
  m_ctx.beginPath();
2162
- m_ctx.closePath(); // clear path
2518
+ m_ctx.closePath();
2163
2519
  m_ctx.moveTo(sma[0].x, sma[0].y);
2164
- for (var i = 0; i < sma.length; i++) m_ctx.lineTo(sma[i].x, sma[i].y);
2520
+ for (i = 0; i < sma.length; i++) m_ctx.lineTo(sma[i].x, sma[i].y);
2165
2521
  m_ctx.stroke();
2166
2522
  m_ctx.restore();
2167
2523
  return;
@@ -2169,13 +2525,15 @@ function Milli_Chart(settings) {
2169
2525
 
2170
2526
  function plotData(data, instrument) {
2171
2527
  m_ctx.save();
2528
+ if (_this.settings.curveOnTop == false)
2529
+ m_ctx.globalCompositeOperation = 'destination-over';
2172
2530
  m_ctx.strokeStyle = m_instrumentCss[instrument].color;
2173
2531
  var factor = _this.instruments[instrument].factor;
2174
2532
  var startpoint = { x: 0, y: 0 };
2175
2533
  var endpoint = { x: 0, y: 0 };
2176
2534
  var startDate = _this.scaleinfoX.startTimeStamp;
2177
2535
  var len = data.length;
2178
- m_ctx.lineWidth = m_instrumentCss[instrument].width;
2536
+ m_ctx.lineWidth = m_instrumentCss[instrument].width / window.devicePixelRatio;
2179
2537
  m_ctx.beginPath();
2180
2538
 
2181
2539
  var startx = 0;
@@ -2186,9 +2544,10 @@ function Milli_Chart(settings) {
2186
2544
  var maxy = 0;
2187
2545
  var hCurveLastPoint = null;
2188
2546
  var quantity = 0;
2547
+
2189
2548
  for (var i = 0; i < len; i++) {
2190
2549
  var currentDate;
2191
- var lastItem = data[i];
2550
+
2192
2551
  var tmpx = startpoint.x;
2193
2552
  var tmp;
2194
2553
  if (data[i].timestamp < _this.scaleinfoX.startTimeStamp) {
@@ -2196,37 +2555,38 @@ function Milli_Chart(settings) {
2196
2555
  continue;
2197
2556
  }
2198
2557
  if (data[i].timestamp > _this.scaleinfoX.endTimeStamp) {
2199
- break; // continue?
2558
+ break;
2200
2559
  }
2560
+ if (data[i].timestamp > new Date().getTime())
2561
+ break;
2201
2562
 
2202
2563
  if (_this.scaleinfoY.type != 'history' && (data[i].timestamp % 86400000 < _this.instruments[0].opentimestamp || data[i].timestamp % 86400000 > _this.instruments[0].closetimestamp)) {
2203
- // stämmer detta kan det bli överlapp vid sommartid/vintertid?
2564
+
2204
2565
  continue;
2205
2566
  }
2206
2567
  var endtimeToday = new Date(data[i].timestamp);
2207
- if (endtimeToday.getDay() == 0 || endtimeToday.getDay() == 6) continue; // do not draw weekends TODO: if main instrument has weekenddata draw it, but need to fix that in all drawfunctions
2568
+ if (endtimeToday.getDay() == 0 || endtimeToday.getDay() == 6) continue;
2208
2569
  if (_this.scaleinfoY.type != 'history') {
2209
- endtimeToday = new Date(endtimeToday.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketclose + 'Z'); // borde räcka att göra 1 gång när det blir nytt datum
2570
+ endtimeToday = new Date(endtimeToday.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketclose + 'Z');
2210
2571
  }
2211
2572
  if (data[i].timestamp > endtimeToday.getTime()) {
2212
- continue; // dataticks efter stängning ritas inte
2573
+ continue;
2213
2574
  }
2214
2575
 
2215
2576
  if (_this.scaleinfoY.type == 'history') {
2216
- //var point = { price: data[i].price, open: null, x: endpoint.x - 0.5, y: endpoint.y - 0.5, timestamp: data[i].timestamp };
2217
- //m_datapoints.push(point);
2577
+
2578
+
2218
2579
  } else
2219
- if (addedcloseprice1d == false && m_zoom.mouseup.timestamp == null && (_this.settings.chartlen == '1d' || _this.settings.chartlen == '0d')) { // only draw closeprice1d on today charts
2580
+ if (_this.settings.previousDayClose && addedcloseprice1d == false && m_zoom.mouseup.timestamp == null) {
2220
2581
  currentDate = new Date(data[i].timestamp);
2221
2582
  offset = ((86400000 - _this.scaleinfoX.milliPerDay) / _this.scaleinfoX.timePerPixel) * dateDiffInDays(new Date(startDate), currentDate);
2222
2583
  tmp = new Date(currentDate.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketopen + 'Z');
2223
2584
  endpoint.x = Math.round(m_chartspaces.chart.left + ((tmp.getTime() - startDate) / _this.scaleinfoX.timePerPixel)) + 0.5 - offset;
2224
- if (_this.settings.chartlen == '1d' || _this.settings.chartlen == '0d') { // plot the closeprice1d
2225
- endpoint.y = Math.round(m_chartspaces.chart.height - m_chartCss.marginBottom - (((parseFloat(_this.instruments[instrument].closeprice1d) * factor) - _this.scaleinfoY.minValue) * _this.scaleinfoY.valuePerPixel)) + 0.5;
2226
- } else {
2227
- endpoint.y = Math.round(m_chartspaces.chart.height - m_chartCss.marginBottom - (((parseFloat(lastItem.price) * factor) - _this.scaleinfoY.minValue) * _this.scaleinfoY.valuePerPixel)) + 0.5;
2228
- }
2229
- m_ctx.moveTo(endpoint.x, endpoint.y);
2585
+
2586
+
2587
+ endpoint.y = Math.round(m_chartspaces.chart.height - getScaledSetting(m_chartCss.marginBottom) - (((parseFloat(_this.instruments[instrument].startValue)) - _this.scaleinfoY.minValue) * _this.scaleinfoY.valuePerPixel)) + 0.5;
2588
+
2589
+ m_ctx.moveTo(endpoint.x, endpoint.y);
2230
2590
  lastdate = new Date(data[i].timestamp);
2231
2591
  addedcloseprice1d = true;
2232
2592
  startx = endpoint.x;
@@ -2236,30 +2596,30 @@ function Milli_Chart(settings) {
2236
2596
  currentDate.setHours(lastdate.getHours());
2237
2597
  currentDate.setMinutes(lastdate.getMinutes());
2238
2598
  currentDate.setSeconds(lastdate.getSeconds());
2239
- if (lastdate.toISOString().substring(0, 10) != currentDate.toISOString().substring(0, 10)) { // new date
2599
+ if (lastdate.toISOString().substring(0, 10) != currentDate.toISOString().substring(0, 10)) {
2240
2600
  tmp = new Date(lastdate.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketclose + 'Z');
2241
- // draw Day separator?
2601
+
2242
2602
  var nextDate = new Date(data[i].timestamp);
2243
- tmp = tmp.getTime() + 86400000 - _this.scaleinfoX.milliPerDay; // increase to next days starttime
2603
+ tmp = tmp.getTime() + 86400000 - _this.scaleinfoX.milliPerDay;
2244
2604
 
2245
2605
  currentDate = new Date(tmp);
2246
2606
  while (dateDiffInDays(currentDate, nextDate) > 0) {
2247
2607
  if (currentDate.getDay() == 0 || currentDate.getDay() == 6)
2248
2608
  offset += 86400000 / _this.scaleinfoX.timePerPixel;
2249
2609
  else
2250
- offset += ((86400000 - _this.scaleinfoX.milliPerDay) / _this.scaleinfoX.timePerPixel); // * dateDiffInDays(lastdate, currentDate);
2610
+ offset += ((86400000 - _this.scaleinfoX.milliPerDay) / _this.scaleinfoX.timePerPixel);
2251
2611
  currentDate = new Date(currentDate.getTime() + 86400000);
2252
2612
  }
2253
- offset += ((86400000 - _this.scaleinfoX.milliPerDay) / _this.scaleinfoX.timePerPixel); // * dateDiffInDays(lastdate, currentDate);
2613
+ offset += ((86400000 - _this.scaleinfoX.milliPerDay) / _this.scaleinfoX.timePerPixel);
2254
2614
  lastdate = currentDate;
2255
2615
  startpoint.x = Math.round(m_chartspaces.chart.left + ((data[i].timestamp - startDate) / _this.scaleinfoX.timePerPixel)) + 0.5 - offset;
2256
2616
 
2257
- // TODO: här blir det fel när det är från 00:00: 23:59 men göms av tmpx < startpoint.x
2617
+
2258
2618
  if (_this.scaleinfoY.type == 'trades' && tmpx < startpoint.x) {
2259
2619
  m_ctx.lineTo(startpoint.x, startpoint.y);
2260
2620
  }
2261
2621
  }
2262
- startpoint.y = Math.round(m_chartspaces.chart.height - m_chartCss.marginBottom - (((data[i].price * factor) - _this.scaleinfoY.minValue) * _this.scaleinfoY.valuePerPixel)) + 0.5;
2622
+ startpoint.y = Math.round(m_chartspaces.chart.height - getScaledSetting(m_chartCss.marginBottom) - (((data[i].price * factor) - _this.scaleinfoY.minValue) * _this.scaleinfoY.valuePerPixel)) + 0.5;
2263
2623
  maxy = maxy > startpoint.y ? maxy : startpoint.y;
2264
2624
 
2265
2625
  startpoint.x = Math.round(m_chartspaces.chart.left + ((data[i].timestamp - _this.scaleinfoX.startDate.getTime()) / _this.scaleinfoX.timePerPixel)) + 0.5;
@@ -2277,16 +2637,16 @@ function Milli_Chart(settings) {
2277
2637
  obj.instruments = [];
2278
2638
  m_dataPoints.map.set(x, obj);
2279
2639
  }
2280
- obj.instruments[instrument] = { price: data[i].price, open: data[i].openprice, x: startpoint.x - 0.5, y: startpoint.y - 0.5, timestamp: data[i].timestamp, date: new Date(data[i].timestamp), insref: _this.instruments[instrument].insref, diff: data[i].diff };
2640
+ obj.instruments[instrument] = { price: data[i].price, open: data[i].openprice, x: startpoint.x / window.devicePixelRatio - 0.5, y: startpoint.y / window.devicePixelRatio - 0.5, timestamp: data[i].timestamp, date: new Date(data[i].timestamp), insref: _this.instruments[instrument].insref, diff: data[i].diff };
2281
2641
  var point;
2282
2642
  if (endpoint.x != 0) {
2283
2643
  if (tmpx < startpoint.x) {
2284
2644
  if (_this.settings.hcurve) m_ctx.lineTo(startpoint.x, endpoint.y);
2285
2645
  m_ctx.lineTo(startpoint.x, startpoint.y);
2286
- //m_ctx.bezierCurveTo(startpoint.x, startpoint.y, endpoint.x - 1, endpoint.y - 1, endpoint.x, endpoint.y); // läs på om detta för "runda linjer"
2646
+
2287
2647
 
2288
2648
  if (instrument == 0) {
2289
- point = { price: data[i].price, open: data[i].openprice, x: startpoint.x - 0.5, y: startpoint.y - 0.5, timestamp: data[i].timestamp, date: new Date(data[i].timestamp), quantity: quantity };
2649
+ point = { price: data[i].price, open: data[i].openprice, x: startpoint.x / window.devicePixelRatio - 0.5, y: startpoint.y / window.devicePixelRatio - 0.5, timestamp: data[i].timestamp, date: new Date(data[i].timestamp), quantity: quantity };
2290
2650
  if (typeof data[i].dividend !== 'undefined') point.dividend = data[i].dividend;
2291
2651
  if (typeof data[i].diff !== 'undefined') point.diff = data[i].diff;
2292
2652
  point.quantity = quantity;
@@ -2296,26 +2656,22 @@ function Milli_Chart(settings) {
2296
2656
  }
2297
2657
  } else {
2298
2658
  if (instrument == 0) {
2299
- point = { price: data[i].price, open: data[i].openprice, x: startpoint.x - 0.5, y: startpoint.y - 0.5, timestamp: data[i].timestamp, date: new Date(data[i].timestamp), insref: _this.instruments[instrument].insref, diff: data[i].diff, quantity: quantity };
2659
+ point = { price: data[i].price, open: data[i].openprice, x: startpoint.x / window.devicePixelRatio - 0.5, y: startpoint.y / window.devicePixelRatio - 0.5, timestamp: data[i].timestamp, date: new Date(data[i].timestamp), insref: _this.instruments[instrument].insref, diff: data[i].diff, quantity: quantity };
2300
2660
  m_datapoints.push(point);
2301
2661
  if (_this.settings.hcurve && _this.scaleinfoY.type == 'history') {
2302
2662
  if (isToday(currentDate)) {
2303
- // only 1 point in hcurve chart, draw line from start of chart to end date
2663
+
2304
2664
  m_ctx.moveTo(m_chartspaces.chart.left, startpoint.y);
2305
- m_ctx.lineTo(startpoint.x, startpoint.y);
2306
- point = { price: data[i].price, open: data[i].openprice, x: m_chartspaces.chart.left - 0.5, y: startpoint.y - 0.5, timestamp: data[i].timestamp, date: new Date(data[i].timestamp), insref: _this.instruments[instrument].insref, diff: data[i].diff, quantity: quantity };
2665
+ point = { price: data[i].price, open: data[i].openprice, x: m_chartspaces.chart.left / window.devicePixelRatio - 0.5, y: startpoint.y / window.devicePixelRatio - 0.5, timestamp: data[i].timestamp, date: new Date(data[i].timestamp), insref: _this.instruments[instrument].insref, diff: data[i].diff, quantity: quantity };
2307
2666
  m_datapoints.push(point);
2308
- point = { price: data[i].price, open: data[i].openprice, x: startpoint.x - 0.5, y: startpoint.y - 0.5, timestamp: data[i].timestamp, date: new Date(data[i].timestamp), insref: _this.instruments[instrument].insref, diff: data[i].diff, quantity: quantity };
2667
+ point = { price: data[i].price, open: data[i].openprice, x: startpoint.x / window.devicePixelRatio - 0.5, y: startpoint.y / window.devicePixelRatio - 0.5, timestamp: data[i].timestamp, date: new Date(data[i].timestamp), insref: _this.instruments[instrument].insref, diff: data[i].diff, quantity: quantity };
2309
2668
  m_datapoints.push(point);
2310
2669
  startx = m_chartspaces.chart.left;
2311
2670
  starty = startpoint.y;
2312
- // last point so break out and store startx and starty from fake point
2671
+
2313
2672
  break;
2314
2673
  } else if (hCurveLastPoint) {
2315
- /* var y = Math.round(m_canvas.height - m_chartCss.marginBottom - (((hCurveLastPoint.price * factor) - _this.scaleinfoY.minValue) * _this.scaleinfoY.valuePerPixel)) + 0.5;
2316
- m_ctx.moveTo(m_chartspaces.chart.left, y);
2317
- m_ctx.lineTo(startpoint.x, y);*/
2318
- }
2674
+ }
2319
2675
  }
2320
2676
  quantity = 0;
2321
2677
  }
@@ -2327,7 +2683,7 @@ function Milli_Chart(settings) {
2327
2683
  endpoint.y = startpoint.y;
2328
2684
  }
2329
2685
  if (data[i].dividend) {
2330
- //console.log('div', data[i]);
2686
+
2331
2687
  }
2332
2688
  }
2333
2689
  m_dataPoints.arr.sort(function(a, b) {
@@ -2335,12 +2691,12 @@ function Milli_Chart(settings) {
2335
2691
  });
2336
2692
  m_ctx.stroke();
2337
2693
  if (_this.settings.fillchart == true && instrument == 0) {
2338
- m_ctx.lineTo(startpoint.x, m_chartspaces.chart.height - m_chartCss.marginBottom + 0.5);
2339
- m_ctx.lineTo(startx, m_chartspaces.chart.height - m_chartCss.marginBottom + 0.5);
2694
+ m_ctx.lineTo(startpoint.x, m_chartspaces.chart.height - getScaledSetting(m_chartCss.marginBottom) + 0.5);
2695
+ m_ctx.lineTo(startx, m_chartspaces.chart.height - getScaledSetting(m_chartCss.marginBottom) + 0.5);
2340
2696
  m_ctx.lineTo(startx, starty);
2341
2697
  m_ctx.closePath();
2342
2698
  if (typeof m_instrumentCss[0].backgroundLinearGradient !== 'undefined' && typeof m_instrumentCss[0].backgroundLinearGradient.topColor !== 'undefined' && typeof m_instrumentCss[0].backgroundLinearGradient.bottomColor !== 'undefined') {
2343
- var grd = m_ctx.createLinearGradient(0, 0, 0, m_chartspaces.chart.height - m_chartspaces.chart.top - m_chartCss.marginBottom);
2699
+ var grd = m_ctx.createLinearGradient(0, 0, 0, m_chartspaces.chart.height - m_chartspaces.chart.top - getScaledSetting(m_chartCss.marginBottom));
2344
2700
  grd.addColorStop(0, m_instrumentCss[0].backgroundLinearGradient.topColor);
2345
2701
  grd.addColorStop(1, m_instrumentCss[0].backgroundLinearGradient.bottomColor);
2346
2702
  m_ctx.fillStyle = grd;
@@ -2351,16 +2707,16 @@ function Milli_Chart(settings) {
2351
2707
  m_ctx.fill();
2352
2708
  } else
2353
2709
  m_ctx.closePath();
2354
- // eftersom vi kör med m_datapoints här så missar vi dom som plottas på samma ställe som punkten innan, gör vi det???
2355
- plotExternalHistoricalData(data);
2710
+
2711
+ if (instrument == 0) {
2712
+ drawPriceIndicator();
2713
+ drawClosePriceIndicator();
2714
+ plotExternalHistoricalData(data);
2715
+ }
2356
2716
  m_ctx.restore();
2357
2717
  }
2358
2718
 
2359
- function drawCompare(resp) {
2360
- parseData(resp[0], 1);
2361
- _this.drawChart();
2362
- return;
2363
- }
2719
+
2364
2720
  _this.setChartLength = function(len) {
2365
2721
  _this.settings.chartlen = len;
2366
2722
  m_zoom.mousedown.timestamp = null;
@@ -2382,6 +2738,7 @@ function Milli_Chart(settings) {
2382
2738
  const uppervariance = mean + variance;
2383
2739
  const lowervariance = mean - variance;
2384
2740
  standardDeviations.push({ timestamp: prices[index - 1].timestamp, datapoints: [uppervariance, lowervariance, mean] });
2741
+ if (typeof prices[index] == 'undefined' || prices[index].timestamp > new Date().getTime()) break;
2385
2742
  }
2386
2743
  return standardDeviations;
2387
2744
  }
@@ -2390,7 +2747,6 @@ function Milli_Chart(settings) {
2390
2747
  if (!prices || prices.length < window) {
2391
2748
  return [];
2392
2749
  }
2393
-
2394
2750
  let index = window - 1;
2395
2751
  const length = prices.length + 1;
2396
2752
 
@@ -2402,6 +2758,7 @@ function Milli_Chart(settings) {
2402
2758
  const windowSlice = prices.slice(index - window, index);
2403
2759
  const sum = windowSlice.reduce((prev, curr) => prev + curr.price, 0);
2404
2760
  simpleMovingAverages.push({ timestamp: prices[index - 1].timestamp, datapoints: [sum / window] });
2761
+ if (typeof prices[index] == 'undefined' || prices[index].timestamp > new Date().getTime()) break;
2405
2762
  }
2406
2763
  return simpleMovingAverages;
2407
2764
  }
@@ -2423,44 +2780,52 @@ function Milli_Chart(settings) {
2423
2780
  const previousEma = [exponentialMovingAverages[previousEmaIndex++].datapoints[0]];
2424
2781
  const currentEma = (value * smoothingFactor) + (previousEma * (1 - smoothingFactor));
2425
2782
  exponentialMovingAverages.push({ timestamp: prices[index].timestamp, datapoints: [currentEma] });
2783
+ if (typeof prices[index] == 'undefined' || prices[index].timestamp > new Date().getTime()) break;
2426
2784
  }
2427
2785
  return exponentialMovingAverages;
2428
2786
  }
2429
- _this.removeIndicator = function(index) {
2430
- if (m_analyzisMethod.get(index)) {
2431
- m_analyzisMethod.delete(index);
2432
- _this.drawChart();
2433
- return true;
2787
+ _this.removeAllIndicators = function(j) {
2788
+ _this.settings.indicators = [];
2789
+ _this.drawChart();
2790
+
2791
+ return false;
2792
+ };
2793
+
2794
+ _this.removeIndicator = function(obj) {
2795
+ for (var i = 0; i < _this.settings.indicators.length; i++) {
2796
+ if (_this.settings.indicators[i].method == obj.method && _this.settings.indicators[i].method_length == obj.method_length) {
2797
+ if (obj.method != 'bb' || obj.stddev == _this.settings.indicators[i].stddev) {
2798
+ _this.settings.indicators.splice(i, 1);
2799
+ _this.drawChart();
2800
+ return true;
2801
+ }
2802
+ }
2434
2803
  }
2435
2804
  return false;
2436
- }
2805
+ };
2437
2806
 
2438
2807
  _this.addIndicator = function(method) {
2439
2808
  if (typeof method !== 'object' || method == null || typeof method.type == undefined) return;
2440
2809
  switch (method.method) {
2441
2810
  case 'sma':
2442
2811
  {
2443
- if (typeof method.length === undefined) return;
2444
- method.history = simpleMovingAverage(_this.instruments[0].history, method.length);
2445
- method.trades = simpleMovingAverage(_this.instruments[0].trades, method.length);
2812
+ if (typeof method.method_length !== 'number') return;
2813
+ method.history = simpleMovingAverage(_this.instruments[0].history, method.method_length);
2814
+ method.trades = simpleMovingAverage(_this.instruments[0].trades, method.method_length);
2446
2815
  }
2447
2816
  break;
2448
2817
  case 'ema':
2449
2818
  {
2450
- if (typeof method.length === undefined) return;
2451
- method.index = m_analyzisIndex++;
2452
- method.history = exponentialMovingAverage(_this.instruments[0].history, method.length);
2453
- method.trades = exponentialMovingAverage(_this.instruments[0].trades, method.length);
2819
+ if (typeof method.method_length !== 'number') return;
2820
+ method.history = exponentialMovingAverage(_this.instruments[0].history, method.method_length);
2821
+ method.trades = exponentialMovingAverage(_this.instruments[0].trades, method.method_length);
2454
2822
  break;
2455
2823
  }
2456
- case 'bollinger':
2824
+ case 'bb':
2457
2825
  {
2458
- if (typeof method.length === undefined) return;
2459
- if (!method.stddev) method.stddev = 2;
2460
- if (!method.length) method.stddev = 20;
2461
- method.index = m_analyzisIndex++;
2462
- method.history = bollingerBands(_this.instruments[0].history, method.length, method.stddev | 2);
2463
- method.trades = bollingerBands(_this.instruments[0].trades, method.length, method.stddev | 2);
2826
+ if (typeof method.method_length !== 'number' || typeof method.stddev !== 'number') return;
2827
+ method.history = bollingerBands(_this.instruments[0].history, method.method_length, method.stddev);
2828
+ method.trades = bollingerBands(_this.instruments[0].trades, method.method_length, method.stddev);
2464
2829
  break;
2465
2830
  }
2466
2831
  default:
@@ -2471,12 +2836,32 @@ function Milli_Chart(settings) {
2471
2836
  }
2472
2837
  break;
2473
2838
  }
2474
- method.index = m_analyzisIndex++;
2475
- m_analyzisMethod.set(method.index, method);
2476
- console.log(method, m_analyzisMethod);
2839
+ _this.settings.indicators.push(method);
2477
2840
  _this.drawChart();
2478
2841
  };
2479
2842
 
2843
+ function getXhrJson(url) {
2844
+ var req = new XMLHttpRequest();
2845
+ req.onload = function() {
2846
+ _this.buildwidget(JSON.parse(this.responseText));
2847
+ };
2848
+ req.open("GET", url, true);
2849
+ req.onerror = function(error) {
2850
+
2851
+ };
2852
+ req.send();
2853
+ }
2854
+
2855
+ _this.refreshData = function() {
2856
+ _this.instruments.forEach(function(c, pos) {
2857
+ if (c.insref != 0) {
2858
+ fetchTrades(c.insref);
2859
+ fetchHistory(c.insref);
2860
+ }
2861
+ });
2862
+
2863
+ };
2864
+
2480
2865
  _this.removeAllCompares = function() {
2481
2866
  if (_this.instruments.length == 1) return;
2482
2867
  for (var i = 0; i < 3; i++)
@@ -2486,12 +2871,13 @@ function Milli_Chart(settings) {
2486
2871
  _this.removeCompare = function(insref) {
2487
2872
  var instrument = parseInt(insref);
2488
2873
  if (instrument == 0 || isNaN(instrument)) return;
2489
- for (var i = 0; i < _this.instruments.length; i++) {
2874
+ for (var i = 1; i < _this.instruments.length; i++) {
2490
2875
  if (_this.instruments[i].insref == instrument) {
2491
2876
  _this.instruments[i] = { insref: 0 };
2492
2877
  _this.drawChart();
2493
2878
  }
2494
2879
  }
2880
+ requestStreaming();
2495
2881
  };
2496
2882
 
2497
2883
  _this.addCompare = function(insref) {
@@ -2521,23 +2907,12 @@ function Milli_Chart(settings) {
2521
2907
  };
2522
2908
 
2523
2909
  _this.instruments[pos] = instr;
2524
- var oldfields = _this.settings.fields;
2525
- if (_this.settings.compare1 != '') {
2526
- _this.settings.fields = [...['name', 'tradecurrency', 'time', 'date', 'tradeprice', 'tradequantity', 'marketopen', 'marketclose', 'closeprice1d'], ...oldfields];
2527
- var url = milli_data_api_url + "widget=intradaychart&token=" + _this.settings.token + "&target=buildwidget&fields=" + _this.settings.fields + "&language=sv&compress=1&insref=" + instrument + '&intradaylen=' + _this.settings.intradaylen;
2528
- _this.settings.fields = oldfields;
2529
- millistream_data_api.fetch(url, function(data) {
2530
- drawCompare(data);
2531
- });
2532
- _this.settings.fields = [...['name', 'tradecurrency', 'date', 'closeprice', 'closequantity', 'marketopen', 'marketclose'], ...oldfields];
2533
- url = milli_data_api_url + "widget=historychart&token=" + _this.settings.token + "&target=buildwidget&insref=" + instrument + "&fields=" + _this.settings.fields + "&language=sv&startdate=" + _this.settings.startdate + "&adjusted=1";
2534
- _this.settings.fields = oldfields;
2535
- millistream_data_api.fetch(url, function(data) {
2536
- drawCompare(data);
2537
- });
2538
- }
2910
+
2911
+ fetchTrades(insref);
2912
+ fetchHistory(insref);
2539
2913
  return 1;
2540
2914
  };
2915
+
2541
2916
 
2542
2917
  function setChartSize() {
2543
2918
  var offset = 0;
@@ -2546,11 +2921,46 @@ function Milli_Chart(settings) {
2546
2921
  }
2547
2922
  _this.settings.target.style.height = (_this.settings.target.parentNode.offsetHeight - offset) + 'px';
2548
2923
  _this.settings.target.style.width = _this.settings.target.parentNode.offsetWidth + 'px';
2549
- m_canvas.height = _this.settings.target.offsetHeight;
2550
- m_canvas.width = _this.settings.target.offsetWidth;
2924
+
2925
+
2926
+ m_canvas.setRect(_this.settings.target.offsetHeight, _this.settings.target.offsetWidth);
2551
2927
  }
2928
+
2929
+ _this.resizeStart = function(e, ui) {
2930
+ m_resizing.width = m_canvas.width;
2931
+ m_resizing.height = m_canvas.height;
2932
+ };
2933
+
2934
+ _this.resize = function(e, ui) {
2935
+ var diff = (m_resizing.height - m_canvas.height) / m_canvas.height * 100;
2936
+ if (Math.abs(diff) > 1) {
2937
+ setChartSize();
2938
+ m_resizing.width = m_canvas.width;
2939
+ m_resizing.height = m_canvas.height;
2940
+ _this.drawChart();
2941
+ } else {
2942
+ diff = (m_resizing.width - m_canvas.width) / m_canvas.width * 100;
2943
+ if (Math.abs(diff) > 1) {
2944
+ setChartSize();
2945
+
2946
+
2947
+ m_resizing.width = m_canvas.width;
2948
+ m_resizing.height = m_canvas.height;
2949
+ _this.drawChart();
2950
+ }
2951
+ }
2952
+ var cache = m_ctx.getImageData(0, 0, m_canvas.width, m_canvas.height);
2953
+ setChartSize();
2954
+ m_ctx.putImageData(cache, 0, 0);
2955
+ };
2956
+
2957
+ _this.resizeEnd = function(e, ui) {
2958
+ setChartSize();
2959
+ _this.drawChart();
2960
+ };
2961
+
2552
2962
  _this.buildwidget = function(resp) {
2553
- //console.log('buildwidget', resp);
2963
+ if (typeof _this.settings.onData === 'function') _this.settings.onData(resp[0]);
2554
2964
  parseData(resp[0], 1);
2555
2965
  var period = _this.settings.chartlen.substring(_this.settings.chartlen.length - 1);
2556
2966
  var len = parseInt(_this.settings.chartlen.substring(0, _this.settings.chartlen.length - 1));
@@ -2563,15 +2973,13 @@ function Milli_Chart(settings) {
2563
2973
 
2564
2974
  if (m_canvas == null) {
2565
2975
  m_canvas = MillistreamWidgetApi_addElement(_this, 'canvas', 'millistream-chart-canvas', _this.settings.target);
2566
-
2567
- setChartSize();
2568
-
2569
2976
  m_ctx = m_canvas.getContext("2d");
2570
- m_canvas.addEventListener('mousemove', onMouseMove, false); // disable while loading and enable on drawReady
2977
+ setChartSize();
2978
+ m_canvas.addEventListener('mousemove', onMouseMove, false);
2571
2979
  m_canvas.addEventListener('mouseout', onMouseOut, false);
2572
2980
  m_canvas.style.cursor = "crosshair";
2573
2981
  m_canvas.onmousedown = (function(evt) {
2574
- if (evt.which == 3 || evt.which == 2) return; // ignore right and middle
2982
+ if (!evt.which == 1) return;
2575
2983
  if (_this.settings.enablezoom == false) return;
2576
2984
  if (m_datapoints.length == 0) return;
2577
2985
  var rect = m_canvas.getBoundingClientRect();
@@ -2580,6 +2988,7 @@ function Milli_Chart(settings) {
2580
2988
  if (x <= m_datapoints[i].x) {
2581
2989
  m_zoom.mousedown.pos = x;
2582
2990
  m_zoom.mousedown.i = i;
2991
+ m_zoom.mousedown.oldtimestamp = m_zoom.mousedown.timestamp;
2583
2992
  m_zoom.mousedown.timestamp = m_datapoints[i].timestamp;
2584
2993
  m_zoom.isZooming = true;
2585
2994
  break;
@@ -2591,11 +3000,12 @@ function Milli_Chart(settings) {
2591
3000
  if (m_datapoints.length == 0 || m_zoom.mousedown.timestamp == null) return;
2592
3001
  var rect = m_canvas.getBoundingClientRect();
2593
3002
  var x = evt.clientX - rect.left - 1;
3003
+ m_zoom.isZooming = false;
2594
3004
  if (x < m_zoom.mousedown.pos) {
2595
3005
  clearZoom();
2596
3006
  return;
2597
3007
  }
2598
- if (Math.abs(x - m_zoom.mousedown.pos) > 5) { // only handle zoom with 5 pixels width
3008
+ if (Math.abs(x - m_zoom.mousedown.pos) > 5) {
2599
3009
  var i;
2600
3010
  for (i = m_datapoints.length - 1; i > 0; i--) {
2601
3011
  if (x >= m_datapoints[i].x) {
@@ -2608,25 +3018,38 @@ function Milli_Chart(settings) {
2608
3018
  if (Math.abs(m_zoom.mouseup.i - m_zoom.mousedown.i) > 0) {
2609
3019
  _this.drawChart();
2610
3020
  }
2611
- //console.log('onmouseup', m_zoom.mousedown.timestamp, m_zoom.mouseup.timestamp)
3021
+ } else {
3022
+ m_zoom.mousedown.pos = 0;
3023
+ m_zoom.mousedown.i = 0;
3024
+ if (m_zoom.mousedown.oldtimestamp != null) {
3025
+ m_zoom.mousedown.timestamp = m_zoom.mousedown.oldtimestamp;
3026
+ m_zoom.mousedown.oldtimestamp = null;
3027
+ } else
3028
+ m_zoom.mousedown.timestamp = null;
2612
3029
  }
2613
3030
  if (m_zoom.div) m_canvas.parentNode.removeChild(m_zoom.div);
2614
3031
  m_zoom.div = null;
2615
- m_zoom.isZooming = false;
2616
3032
  });
2617
- } else {
2618
- //m_ctx.clearRect(0, 0, m_canvas.width, m_canvas.height);
2619
3033
  }
2620
- //m_marketopen = resp[0].marketopen;
2621
- //m_marketclose = resp[0].marketclose;
2622
- _this.drawChart();
2623
-
2624
- if (_this.settings.streaming != false && typeof resp[0].trades !== 'undefined') {
2625
- m_requestid = _this.settings.streaming.MillistreamWidgetStreamingApi_subscribeInstruments(_this, m_requestid, [_this.settings.instrument]);
3034
+ if (_this.instruments[0].trades.length > 0) {
3035
+ _this.drawChart();
3036
+ requestStreaming();
3037
+ if (_this.settings.onreadyCallback) _this.settings.onreadyCallback();
2626
3038
  }
2627
- if (_this.settings.onreadyCallback) _this.settings.onreadyCallback();
2628
3039
  };
2629
3040
 
3041
+ function requestStreaming() {
3042
+ var arr = [];
3043
+ _this.instruments.forEach(function(instr) {
3044
+ if (instr.insref != 0) arr.push(instr.insref);
3045
+ });
3046
+ if (_this.settings.streaming != false) {
3047
+ if (typeof _this.unsubscriptions === 'undefined' || typeof _this.unsubscriptions.insrefs === 'undefined' || _this.unsubscriptions.insrefs != arr.length) {
3048
+ _this.requestid = _this.settings.streaming.MillistreamWidgetStreamingApi_subscribeInstruments(_this, _this.requestid, arr);
3049
+ }
3050
+ }
3051
+ }
3052
+
2630
3053
  _this.streamingCallback = function(insref, mref, json) {
2631
3054
  var update = false;
2632
3055
  var calcAnalyizis = false;
@@ -2636,115 +3059,233 @@ function Milli_Chart(settings) {
2636
3059
  if (instr == null) {
2637
3060
  return;
2638
3061
  }
2639
- if (json['3'] && json['36'] && json['13'] && (json['12'] || json['201'])) {
2640
- var timestamp = new Date(json['3'] + 'T' + json['36'].substring(0, 6) + '00' + 'Z').getTime();
2641
-
2642
- var data = instr.hashmap.get(timestamp);
2643
- if (typeof data === 'undefined') {
3062
+ if (mref == 'performance') {
3063
+ if (instr.pricetype == 'price' || instr.pricetype == 'nav') {
3064
+ if (typeof json['148'] !== 'undefined') {
3065
+ instr.closeprice1d = parseFloat(json['148']);
3066
+ }
3067
+ } else
3068
+ if (typeof json['262'] !== 'undefined') {
3069
+ instr.closeprice1d = parseFloat(json['148']);
3070
+ }
3071
+ }
3072
+ if (mref == 'quote') {
3073
+ if (instr.history.length == 0) return;
3074
+ if (json['3'] && !isToday(new Date(json['3']))) return;
3075
+ if (json['3']) {
2644
3076
  update = true;
2645
- data = {};
2646
- //data.tradereference = json['14'];
2647
- data.timestamp = timestamp;
2648
- instr.hashmap.set(data.timestamp, data);
2649
- calcAnalyizis = true;
2650
- data.price = parseFloat(json['12']); // eller 201 för tradeyield
2651
- data.open = parseFloat(json['12']); // eller 201 för tradeyield
2652
- data.high = parseFloat(json['12']); // eller 201 för tradeyield
2653
- data.low = parseFloat(json['12']); // eller 201 för tradeyield
2654
- data.quantity = parseInt(json['13']);
2655
-
2656
- if (instr.trades.length != 0 && data.timestamp < instr.trades[instr.trades.length - 1].timestamp) {
2657
- //console.log("pushtrade is older than last trade ignoring, should file it on correct postition");
2658
- } else
2659
- instr.trades.push(data);
3077
+ instr.quotedate = new Date(json['3']).getTime();
3078
+ instr.quotedate -= instr.quotedate % 86400000;
3079
+ }
3080
+ var price = undefined;
3081
+ var quantity = undefined;
3082
+ var timestamp = new Date().getTime();
3083
+ timestamp -= timestamp % 86400000;
3084
+ var obj = instr.history[instr.history.length - 1];
3085
+ if (instr.pricetype == 'yield') {
3086
+ if (!json['76']) {
3087
+ if (update) _this.drawChart();
3088
+ return;
3089
+ }
3090
+ price = json['76'];
2660
3091
  } else {
2661
- if (data.price != parseFloat(json['12']))
3092
+ if (!json['7'] && !json['13']) {
3093
+ if (update) _this.drawChart();
3094
+ return;
3095
+ }
3096
+ price = json['7'] === 'undefined' ? undefined : json['7'];
3097
+ quantity = json['13'] === 'undefined' ? undefined : json['13'];
3098
+ }
3099
+ if (obj.timestamp != timestamp) {
3100
+ obj = [];
3101
+ obj.timestamp = timestamp;
3102
+ instr.history.push(obj);
3103
+ }
3104
+ obj.price = typeof price === 'undefined' ? obj.price : parseFloat(price);
3105
+ obj.quantity = typeof quantity === 'undefined' ? obj.quantity : quantity;
3106
+ if (_this.scaleinfoY.type == 'history') update = true;
3107
+ } else {
3108
+ if (json['3'] && json['36'] && (json['12'] || json['201'])) {
3109
+ var timestamp = new Date(json['3'] + 'T' + json['36'].substring(0, 6) + '00' + 'Z').getTime();
3110
+ var data = instr.hashmap.get(timestamp);
3111
+ if (typeof data === 'undefined') {
3112
+ data = {};
3113
+
3114
+ data.timestamp = timestamp;
2662
3115
  calcAnalyizis = true;
2663
- data.price = parseFloat(json['12']); // eller 201 för tradeyield
2664
- data.quantity += parseInt(json['13']);
2665
- update = true;
2666
- // updatera med quantity, open , high,low osv?
3116
+ if (instr.pricetype == 'price') {
3117
+ update = true;
3118
+ data.price = parseFloat(json['12']);
3119
+ data.open = parseFloat(json['12']);
3120
+ data.high = parseFloat(json['12']);
3121
+ data.low = parseFloat(json['12']);
3122
+ data.quantity = typeof json['13'] === 'undefined' ? 0 : parseInt(json['13']);
3123
+ } else if (instr.pricetype == 'price') {
3124
+ data.price = parseFloat(json['201']);
3125
+ data.open = parseFloat(json['201']);
3126
+ data.high = parseFloat(json['201']);
3127
+ data.low = parseFloat(json['201']);
3128
+ data.quantity = typeof json['13'] === 'undefined' ? 0 : parseInt(json['13']);
3129
+ update = true;
3130
+ }
3131
+ if (update) {
3132
+ if (instr.trades.length != 0 && data.timestamp < instr.trades[instr.trades.length - 1].timestamp) {
3133
+
3134
+ } else
3135
+ instr.hashmap.set(data.timestamp, data);
3136
+ instr.trades.push(data);
3137
+ }
3138
+ } else {
3139
+ if (instr.pricetype == 'price') {
3140
+ if (data.price != parseFloat(json['12']))
3141
+ calcAnalyizis = true;
3142
+ data.price = parseFloat(json['12']);
3143
+ data.quantity += typeof json['13'] === 'undefined' ? 0 : parseInt(json['13']);
3144
+ if (_this.scaleinfoY.type == 'trades') update = true;
3145
+ } else {
3146
+ if (instr.pricetype == 'price') {
3147
+ if (data.price != parseFloat(json['201']))
3148
+ calcAnalyizis = true;
3149
+ data.price = parseFloat(json['201']);
3150
+ data.quantity += typeof json['13'] === 'undefined' ? 0 : parseInt(json['13']);
3151
+ if (_this.scaleinfoY.type == 'trades') update = true;
3152
+ }
3153
+
3154
+ }
3155
+ }
2667
3156
  }
2668
- }
2669
- if (calcAnalyizis) {
2670
- for (const [key, a] of m_analyzisMethod.entries()) {
2671
- switch (a.method) {
2672
- case 'sma':
2673
- a.trades = [];
2674
- a.trades = simpleMovingAverage(_this.instruments[0].trades, a.length);
2675
- break;
2676
- case 'ema':
2677
- a.trades = [];
2678
- a.trades = exponentialMovingAverage(_this.instruments[0].trades, a.length);
2679
- break;
2680
- case 'bollinger':
2681
- a.trades = [];
2682
- a.trades = bollingerBands(_this.instruments[0].trades, a.length, a.stddev | 2);
2683
- break;
2684
- default:
2685
- // draw custom added?
2686
- break;
3157
+ if (calcAnalyizis && insref == _this.instruments[0].insref) {
3158
+ for (var i = 0; i < _this.settings.indicators.length; i++) {
3159
+
3160
+ switch (_this.settings.indicators[i].method) {
3161
+ case 'sma':
3162
+ _this.settings.indicators[i].trades = [];
3163
+ _this.settings.indicators[i].trades = simpleMovingAverage(_this.instruments[0].trades, _this.settings.indicators[i].method_length);
3164
+ break;
3165
+ case 'ema':
3166
+ _this.settings.indicators[i].trades = [];
3167
+ _this.settings.indicators[i].trades = exponentialMovingAverage(_this.instruments[0].trades, _this.settings.indicators[i].method_length);
3168
+ break;
3169
+ case 'bb':
3170
+ _this.settings.indicators[i].trades = [];
3171
+ _this.settings.indicators[i].trades = bollingerBands(_this.instruments[0].trades, _this.settings.indicators[i].method_length, _this.settings.indicators[i].stddev | 2);
3172
+ break;
3173
+ default:
3174
+
3175
+ break;
3176
+ }
2687
3177
  }
2688
3178
  }
2689
- }
3179
+ if (update) {
3180
+ _this.drawChart();
3181
+ }
3182
+ return;
3183
+ };
3184
+ }
2690
3185
 
2691
- if (update && _this.settings.chartlen != 'ytd' && _this.settings.chartlen.substring(_this.settings.chartlen.length - 1) == 'd') { // do not redraw if not tickchart
2692
- _this.drawChart();
2693
- }
2694
- };
3186
+
3187
+ _this.exportData = function() {
3188
+ let ret = [];
2695
3189
 
2696
- function changeOrientation() {
2697
- if (m_canvas == null) return;
2698
- m_canvas.setAttribute('height', _this.settings.target.getBoundingClientRect().height);
2699
- m_canvas.setAttribute('width', _this.settings.target.getBoundingClientRect().width);
2700
- _this.drawChart();
2701
- }
3190
+ if (_this.scaleinfoY.type == 'trades') {
3191
+ if (_this.instruments.length > 0) {
3192
+ for (var i = 0; i < _this.instruments[0].trades.length; i++) {
3193
+ var date = new Date(_this.instruments[0].trades[i].timestamp - new Date().getTimezoneOffset() * 60000);
3194
+ var datestr = date.toISOString();
2702
3195
 
2703
- function getXhrJson(url) {
2704
- var req = new XMLHttpRequest();
2705
- req.onload = function() {
2706
- _this.buildwidget(JSON.parse(this.responseText));
2707
- };
2708
- req.open("GET", url, true);
2709
- req.onerror = function(error) {
2710
- console.log('Fetch data error', error);
2711
- };
2712
- req.send();
3196
+ ret.push([datestr.substring(0, 10), datestr.substring(11, 23), _this.instruments[0].trades[i].price, _this.instruments[0].trades[i].quantity]);
3197
+ }
3198
+ }
3199
+
3200
+ return [
3201
+ ["Date", "Time", "Price", "Quantity"],
3202
+ ...ret
3203
+ ];
3204
+ } else {
3205
+ if (_this.instruments.length > 0) {
3206
+ for (var i = 0; i < _this.instruments[0].history.length; i++) {
3207
+ var date = new Date(_this.instruments[0].history[i].timestamp);
3208
+ var datestr = date.toISOString();
3209
+
3210
+ ret.push([datestr.substring(0, 10), "", _this.instruments[0].history[i].price, _this.instruments[0].history[i].quantity]);
3211
+ }
3212
+ }
3213
+
3214
+ return [
3215
+ ["Date", "Time", "Price", "Quantity"],
3216
+ ...ret
3217
+ ];
3218
+ }
2713
3219
  }
2714
3220
 
2715
3221
  _this.destroyWidget = function() {
2716
- // if we have subscriptions send in an empty array to unsubscribe all and release it
3222
+
2717
3223
  if (MillistreamWidgetApi_isObjectEmpty(_this.unsubscriptions) == false)
2718
3224
  _this.requestid = _this.settings.streaming.MillistreamWidgetStreamingApi_subscribeInstruments(_this, _this.requestid, []);
2719
3225
  return 0;
2720
3226
  };
2721
3227
 
3228
+ function fetchTrades(instrument) {
3229
+ var oldfields = _this.settings.fields;
3230
+ _this.settings.fields = [...['name', 'tradecurrency', 'time', 'date', 'tradeprice', 'tradequantity', 'marketopen', 'marketclose', 'closeprice1d'], ...oldfields];
3231
+ var url = milli_data_api_url + "widget=intradaychart&token=" + _this.settings.token + "&target=buildwidget&fields=" + _this.settings.fields + "&language=sv&compress=" + _this.settings.compress + "&insref=" + instrument + '&intradaylen=' + _this.settings.intradaylen + '&xhr=' + (_this.settings.xhr == true ? '1' : '0');
3232
+ if (typeof _this.settings.pricetype !== 'undefined') url += '&pricingtype=' + _this.settings.pricetype;
3233
+ if (_this.settings.adjusted == true) url += '&adjusted=1';
3234
+ _this.settings.fields = oldfields;
3235
+ if (_this.settings.xhr) {
3236
+ getXhrJson(url);
3237
+ } else {
3238
+ millistream_data_api.fetch(url, function(data) {
3239
+ _this.buildwidget(data);
3240
+ });
3241
+ }
3242
+
3243
+ }
3244
+
3245
+ function fetchHistory(instrument) {
3246
+ var oldfields = _this.settings.fields;
3247
+ _this.settings.fields = [...['name', 'tradecurrency', 'date', 'closeprice', 'closequantity', 'marketopen', 'marketclose'], ...oldfields];
3248
+ var url = milli_data_api_url + "widget=historychart&token=" + _this.settings.token + "&target=buildwidget&fields=" + _this.settings.fields + "&language=sv&insref=" + instrument + '&startdate=' + m_startdate + '&intradaylen=' + _this.settings.intradaylen + '&xhr=' + (_this.settings.xhr == true ? '1' : '0');
3249
+ if (typeof _this.settings.pricetype !== 'undefined') url += '&pricingtype=' + _this.settings.pricetype;
3250
+ if (_this.settings.adjusted == true) url += '&adjusted=1';
3251
+ _this.settings.fields = oldfields;
3252
+ if (_this.settings.xhr) {
3253
+ getXhrJson(url);
3254
+ } else {
3255
+ millistream_data_api.fetch(url, function(data) {
3256
+ _this.buildwidget(data);
3257
+ });
3258
+ }
3259
+ }
3260
+
2722
3261
  _this.drawWidget = function() {
2723
- // remove standard fields from array, they will be requested anyway
3262
+
2724
3263
  _this.settings.fields = _this.settings.fields.filter(function(obj) {
2725
3264
  return ['name', 'tradecurrency', 'time', 'date', 'tradeprice', 'tradequantity', 'marketopen', 'marketclose', 'closeprice1d', 'closeprice', 'closequantity'].indexOf(obj) == -1;
2726
3265
  });
2727
- //_this.settings.drawy2axis = false;
2728
- m_tradedates = [];
2729
- _this.settings.scaleinfoY = {};
2730
3266
  if (m_dummyDiv == null) m_dummyDiv = document.createElement('div');
2731
3267
  m_dummyDiv.style.display = 'none';
2732
3268
  m_dummyDiv.setAttribute('class', 'millistream-chart');
2733
3269
  _this.settings.target.appendChild(m_dummyDiv);
3270
+ var insrefs;
3271
+ if (Array.isArray(_this.settings.instrument)) {
3272
+ insrefs = _this.settings.instrument;
3273
+ } else insrefs = [_this.settings.instrument];
3274
+
2734
3275
  _this.instruments[0] = {
2735
- insref: _this.settings.instrument,
3276
+ insref: insrefs[0],
2736
3277
  history: [],
2737
3278
  trades: [],
2738
3279
  hashmap: new Map(),
2739
3280
  intradayQuantity: []
2740
3281
  };
2741
- var d, url, oldfields;
3282
+
2742
3283
  if (_this.settings.intradaylen) {
2743
- d = new Date().getTime();
3284
+ var d = new Date().getTime();
2744
3285
  var e = new Date();
2745
3286
  var days = 0;
2746
3287
  var newlen = 0;
2747
- while (days < _this.settings.intradaylen - 1) { // include today
3288
+ while (days < _this.settings.intradaylen - 1) {
2748
3289
  d -= 86400000;
2749
3290
  e.setTime(d);
2750
3291
  if (e.getDay() != 0 && e.getDay() != 6)
@@ -2752,84 +3293,51 @@ function Milli_Chart(settings) {
2752
3293
  newlen++;
2753
3294
  }
2754
3295
  _this.settings.intradaylen = newlen.toString();
2755
- oldfields = _this.settings.fields;
2756
- _this.settings.fields = [...['name', 'tradecurrency', 'time', 'date', 'tradeprice', 'tradequantity', 'marketopen', 'marketclose', 'closeprice1d'], ...oldfields];
2757
- _this.settings.startdate = e.getFullYear() + '-' + zeroPad(e.getMonth() + 1, 2) + '-' + zeroPad(e.getDate(), 2);
2758
- url = MillistreamWidgetApi_buildQuery(_this, 'intradaychart');
2759
- _this.settings.fields = oldfields;
2760
- if (_this.settings.xhr) {
2761
- getXhrJson(url);
2762
- } else {
2763
- millistream_data_api.fetch(url, function(data) {
2764
- _this.buildwidget(data);
2765
- });
2766
- }
3296
+ fetchTrades(_this.instruments[0].insref);
2767
3297
  }
2768
3298
  if (_this.settings.historylen) {
2769
3299
  var len = _this.settings.historylen.substring(0, _this.settings.historylen.length - 1);
2770
3300
  var period = this.settings.historylen.substring(_this.settings.historylen.length - 1);
2771
- var startdate = new Date().getTime();
3301
+ var sdate = new Date();
2772
3302
  switch (period) {
2773
3303
  case 'w':
2774
- startdate -= len * (86400000 * 7);
3304
+ sdate.setDate(sdate.getDate() - len);
2775
3305
  break;
2776
3306
  case 'm':
2777
- for (var i = 0; i < len; i++) {
2778
- d = new Date(startdate);
2779
- switch (d.getMonth() + 1) {
2780
- case 1:
2781
- case 3:
2782
- case 5:
2783
- case 7:
2784
- case 8:
2785
- case 10:
2786
- case 12:
2787
- startdate -= 86400000 * 31;
2788
- break;
2789
- case 4:
2790
- case 6:
2791
- case 9:
2792
- case 11:
2793
- startdate -= 86400000 * 30;
2794
- break;
2795
- case 2:
2796
- startdate -= 86400000 * 30; // remember leapyear
2797
- break;
2798
- }
2799
- }
3307
+ sdate.setMonth(sdate.getMonth() - len);
2800
3308
  break;
2801
3309
  case 'y':
2802
- startdate -= 86400000 * 365 * len; // remember leapyear
3310
+ sdate.setFullYear(sdate.getFullYear() - len);
2803
3311
  break;
2804
3312
  case 'x':
2805
- startdate = new Date('1970-01-01T00:00:00Z').getTime();
3313
+ sdate = new Date('1970-01-01T00:00:00Z');
2806
3314
  break;
2807
3315
  }
2808
- // must be reset when changing from intraday -> history and vice versa
2809
- startdate = new Date(startdate);
2810
- oldfields = _this.settings.fields;
2811
- _this.settings.fields = [...['name', 'tradecurrency', 'date', 'closeprice', 'closequantity', 'marketopen', 'marketclose'], ...oldfields];
2812
- _this.settings.startdate = startdate.getFullYear() + '-' + zeroPad(startdate.getMonth() + 1, 2) + '-' + zeroPad(startdate.getDate(), 2);
2813
- url = MillistreamWidgetApi_buildQuery(_this, 'historychart');
2814
- _this.settings.fields = oldfields;
2815
- if (_this.settings.xhr) {
2816
- getXhrJson(url);
2817
- } else {
2818
- millistream_data_api.fetch(url, function(data) {
2819
- _this.buildwidget(data);
2820
-
2821
- });
2822
- }
3316
+ m_startdate = sdate.getFullYear() + '-' + zeroPad(sdate.getMonth() + 1, 2) + '-' + zeroPad(sdate.getDate(), 2);
3317
+ fetchHistory(_this.instruments[0].insref);
2823
3318
  }
3319
+ for (var i = 1; i < insrefs.length && i < 4; i++) {
3320
+ if (insrefs[i] != 0)
3321
+ this.addCompare(insrefs[i]);
3322
+ }
3323
+
2824
3324
  };
2825
3325
  if (this.settings.autodraw == true) this.drawWidget();
2826
3326
 
2827
- window.addEventListener('resize', function() {
2828
- if (m_canvas != null)
2829
- changeOrientation();
3327
+ (function updatePixelRatio() {
3328
+ matchMedia(`(resolution: ${window.devicePixelRatio}dppx)`).addEventListener('change', updatePixelRatio, { once: true });
3329
+
3330
+ _this.drawChart();
3331
+ })();
2830
3332
 
3333
+ window.addEventListener('resize', function() {
3334
+ if (m_canvas != null) {
3335
+ setChartSize();
3336
+ _this.drawChart();
3337
+ }
2831
3338
  });
2832
3339
  }
3340
+
2833
3341
  var milli_data_api_url = 'https://stage.millistream.com/widgets/3.0.3/data/milli_widget_dataapi.php?';
2834
3342
 
2835
3343
  var millistream_data_api = {
@@ -2878,14 +3386,14 @@ function MillistreamWidgetApi_buildQuery(widget, type) {
2878
3386
  if (typeof widget.settings.instrumenttype !== 'object') {
2879
3387
  throw new Error(widget.constructor.name + ': instrumenttype is not valid');
2880
3388
  }
2881
- //if (widget.settings.instrument == null) // removed 2021-10-12 for "mylist" functionality
3389
+
2882
3390
  url += '&instrumenttypes=' + widget.settings.instrumenttype.join();
2883
3391
  }
2884
3392
  if (widget.settings.instrumentsubtype != null) {
2885
3393
  if (typeof widget.settings.instrumentsubtype !== 'object') {
2886
3394
  throw new Error(widget.constructor.name + ': instrumentsubtype is not valid');
2887
3395
  }
2888
- //if (widget.settings.instrument == null) // removed 2021-10-12 for "mylist" functionality
3396
+
2889
3397
  url += '&instrumentsubtypes=' + widget.settings.instrumentsubtype.join();
2890
3398
  }
2891
3399
  if (widget.settings.derivativeindicator != null) {
@@ -3234,12 +3742,12 @@ function MillistreamWidgetApi_addPagination(widget) {
3234
3742
  li.onclick = function() {
3235
3743
  MillistreamWidgetApi_getPaginationPage(widget, 'next');
3236
3744
  };
3237
- if (widget.pagination.numPages < max + 1) li.style.display = 'none'; // dont show if less than 6 pages
3745
+ if (widget.pagination.numPages < max + 1) li.style.display = 'none';
3238
3746
  li = MillistreamWidgetApi_addElement(widget, 'li', 'millistream-list-pagination-li', widget.pagination.ul, null, '>>');
3239
3747
  li.onclick = function() {
3240
3748
  MillistreamWidgetApi_getPaginationPage(widget, 'last');
3241
3749
  };
3242
- if (widget.pagination.numPages < max + 1) li.style.display = 'none'; // dont show if less than 6 pages
3750
+ if (widget.pagination.numPages < max + 1) li.style.display = 'none';
3243
3751
  }
3244
3752
  } else
3245
3753
  if (widget.settings.pagination > 0 && widget.pagination.numPages < 2) {
@@ -3307,11 +3815,11 @@ function MillistreamWidgetApi_getPaginationPage(widget, page) {
3307
3815
  startno = 1;
3308
3816
  } else
3309
3817
  if (widget.pagination.selectedPage > widget.pagination.numPages - 2) {
3310
- startno = widget.pagination.numPages - (max - 1); //4;
3818
+ startno = widget.pagination.numPages - (max - 1);
3311
3819
 
3312
3820
  } else {
3313
3821
  startno = widget.pagination.selectedPage - 2 < 1 ? 1 : widget.pagination.selectedPage - (max - Math.ceil(max / 2));
3314
- //startno = widget.pagination.selectedPage - 1;
3822
+
3315
3823
  }
3316
3824
  for (i = 2; i < items.length - 2; i++) {
3317
3825
  items[i].innerHTML = (startno);
@@ -3350,15 +3858,15 @@ function MillistreamWidgetApi_getElementHeight(el) {
3350
3858
  return rect.height + s;
3351
3859
  }
3352
3860
 
3353
- // Push blipp funktioner
3861
+
3354
3862
  function MillistreamWidgetApi_clearFlash(el) {
3355
- //internal and external
3863
+
3356
3864
  el.classList.remove('millistream-flash-up');
3357
3865
  el.classList.remove('millistream-flash-down');
3358
3866
  }
3359
3867
 
3360
3868
  function milli_clearValuedFlash(widget, el, oldValue) {
3361
- // internal borde gå att bygga bort
3869
+
3362
3870
  var currentValue = MillistreamWidgetApi_getElementNumber(widget, el);
3363
3871
  if (currentValue == oldValue || currentValue == 0) {
3364
3872
  MillistreamWidgetApi_clearFlash(el);
@@ -3366,7 +3874,7 @@ function milli_clearValuedFlash(widget, el, oldValue) {
3366
3874
  }
3367
3875
 
3368
3876
  function MillistreamWidgetApi_flashElement(widget, el, newValue, oldValue) {
3369
- // internal
3877
+
3370
3878
  if (newValue == oldValue) return;
3371
3879
  MillistreamWidgetApi_clearFlash(el);
3372
3880
  if (newValue == '' || !newValue) return;
@@ -3385,7 +3893,7 @@ function MillistreamWidgetApi_flashElement(widget, el, newValue, oldValue) {
3385
3893
  }
3386
3894
 
3387
3895
 
3388
- // numeriska funktioner
3896
+
3389
3897
  function MillistreamWidgetApi_isNumber(widget, testsubject) {
3390
3898
  if (!testsubject) return;
3391
3899
  var n = testsubject.replace(widget.settings.decimalseparator, '.').split(widget.settings.thousandseparator).join('');
@@ -3398,7 +3906,7 @@ function MillistreamWidgetApi_getNumDecimals(widget, value, current, validfields
3398
3906
  if (value == null || MillistreamWidgetApi_isNumber(widget, value) == false) return current;
3399
3907
  var parts = value.toString().split('.');
3400
3908
  if (parts.length == 2) {
3401
- while (parts[1].charAt(parts[1].length - 1) == "0") { // remove trailing zeros
3909
+ while (parts[1].charAt(parts[1].length - 1) == "0") {
3402
3910
  parts[1] = parts[1].slice(0, -1);
3403
3911
  }
3404
3912
  return current > parts[1].length ? current : parts[1].length;
@@ -3407,7 +3915,7 @@ function MillistreamWidgetApi_getNumDecimals(widget, value, current, validfields
3407
3915
  }
3408
3916
 
3409
3917
  function MillistreamWidgetApi_getElementNumber(widget, el) {
3410
- // internal and Orderbook
3918
+
3411
3919
  var res = parseFloat(el.innerHTML.replace(widget.settings.decimalseparator, '.').split(widget.settings.thousandseparator).join(''));
3412
3920
  if (!isNaN(parseFloat(res)) && isFinite(res)) return res;
3413
3921
  return 0;
@@ -3438,7 +3946,7 @@ function MillistreamWidgetApi_colorCell(widget, element, info) {
3438
3946
  MillistreamWidgetApi_setCellColor(widget, element, v);
3439
3947
  }
3440
3948
  } else
3441
- if (widget.settings.controlcolumn || widget.settings.controlcolumn == 0) { // works for tables
3949
+ if (widget.settings.controlcolumn || widget.settings.controlcolumn == 0) {
3442
3950
  if (widget.settings.stylecolumn === null) return;
3443
3951
  var tr = element.parentNode;
3444
3952
  while (tr.tagName.toLowerCase() != 'tr') {
@@ -3447,13 +3955,13 @@ function MillistreamWidgetApi_colorCell(widget, element, info) {
3447
3955
  if (tr.cells.length > widget.settings.controlcolumn) {
3448
3956
  v = MillistreamWidgetApi_getElementNumber(widget, tr.cells[widget.settings.controlcolumn]);
3449
3957
  var el;
3450
- if (widget.settings.stylecolumn && widget.settings.stylecolumn[0] == -1) { // color row
3451
- el = tr; //element.parentNode;
3958
+ if (widget.settings.stylecolumn && widget.settings.stylecolumn[0] == -1) {
3959
+ el = tr;
3452
3960
  MillistreamWidgetApi_setCellColor(widget, tr, v);
3453
3961
 
3454
3962
  } else {
3455
3963
  for (var s = 0; s < widget.settings.stylecolumn.length; s++) {
3456
- el = tr.cells[widget.settings.stylecolumn[s]]; //element.parentNode.cells[widget.stylecolumn[s]];
3964
+ el = tr.cells[widget.settings.stylecolumn[s]];
3457
3965
  if (el) {
3458
3966
  MillistreamWidgetApi_setCellColor(widget, el, v);
3459
3967
  }
@@ -3461,17 +3969,17 @@ function MillistreamWidgetApi_colorCell(widget, element, info) {
3461
3969
  }
3462
3970
  }
3463
3971
  } else
3464
- if (widget.settings.positiveclass && widget.settings.negativeclass) { // non table elements
3972
+ if (widget.settings.positiveclass && widget.settings.negativeclass) {
3465
3973
  v = MillistreamWidgetApi_getElementNumber(widget, element);
3466
3974
  MillistreamWidgetApi_setCellColor(widget, element, v);
3467
3975
  }
3468
3976
  }
3469
3977
 
3470
3978
  function print_field(widget, element, field, value, overridedecimals) {
3471
- // internal and external
3979
+
3472
3980
  var f = parseInt(field);
3473
3981
  var info = MillistreamWidgetApi_getColumnInfo(widget, f.toString());
3474
- if (typeof value === 'undefined' || value == null || (!value && isNaN(value) == true)) { // kolla field?
3982
+ if (typeof value === 'undefined' || value == null || (!value && isNaN(value) == true)) {
3475
3983
  if (info[4] & 16) {
3476
3984
  value = '0.0';
3477
3985
  } else {
@@ -3489,7 +3997,7 @@ function print_field(widget, element, field, value, overridedecimals) {
3489
3997
  element.innerHTML = formatTime(value, widget.settings.timeformat);
3490
3998
  break;
3491
3999
  case 'date':
3492
- element.innerHTML = formatDate(value, widget.settings.dateformat);
4000
+ element.innerHTML = formatDate(value, widget.settings.dateformat, widget);
3493
4001
  break;
3494
4002
  case 'datetime':
3495
4003
  element.innerHTML = formatDateTime(value, widget.settings.datetimeformat);
@@ -3517,7 +4025,7 @@ function print_field(widget, element, field, value, overridedecimals) {
3517
4025
  else
3518
4026
  element.innerHTML = formatFactorNumber(value, widget.settings.factor, widget.settings.num_decimals, widget.settings.thousandseparator, widget.settings.decimalseparator);
3519
4027
  } else if (info[4] & 4)
3520
- element.innerHTML = formatNiceNumber(value, widget.settings.thousandseparator, widget.settings.decimalseparator, 0); // no decimals
4028
+ element.innerHTML = formatNiceNumber(value, widget.settings.thousandseparator, widget.settings.decimalseparator, 0);
3521
4029
  else if (info[4] & 1 && overridedecimals)
3522
4030
  element.innerHTML = formatNiceNumber(value, widget.settings.thousandseparator, widget.settings.decimalseparator, overridedecimals || widget.settings.num_decimals);
3523
4031
  else {
@@ -3535,8 +4043,8 @@ function print_field(widget, element, field, value, overridedecimals) {
3535
4043
  }
3536
4044
 
3537
4045
  function MillistreamWidgetApi_getColumnInfo(widget, name) {
3538
- // internal and external
3539
- // return array with MDF_F_FIELD,type,align, name var, overridable decimal bitwise [1 = override output,2 = can override,4 = no decimals,8 can be shortened to M, K etc], 16 = override NULL with 0 , 32 = can color diff
4046
+
4047
+
3540
4048
  switch (name) {
3541
4049
  case '222':
3542
4050
  case 'accountsreceivable':
@@ -3627,7 +4135,7 @@ function MillistreamWidgetApi_getColumnInfo(widget, name) {
3627
4135
  return [232, 'numeric', 'right', widget.get_lang_text(name) || name, 8];
3628
4136
  case '404':
3629
4137
  case 'd1':
3630
- return [404, 'date', 'right', widget.get_lang_text(name) || name, 0]; // Security type
4138
+ return [404, 'date', 'right', widget.get_lang_text(name) || name, 0];
3631
4139
  case '3':
3632
4140
  case 'date':
3633
4141
  return [3, 'date', 'right', widget.get_lang_text(name) || name, 0];
@@ -3865,7 +4373,7 @@ function MillistreamWidgetApi_getColumnInfo(widget, name) {
3865
4373
  case '1022':
3866
4374
  case 'marketcap':
3867
4375
  return [1022, 'numeric', 'right', widget.get_lang_text(name) || name, 12];
3868
- case '54':
4376
+ case '54':
3869
4377
  case 'marketplace':
3870
4378
  return [54, 'numeric', 'left', widget.get_lang_text(name) || name, 0];
3871
4379
  case 'marketplacename':
@@ -3881,10 +4389,10 @@ function MillistreamWidgetApi_getColumnInfo(widget, name) {
3881
4389
  return [229, 'numeric', 'right', widget.get_lang_text(name) || name, 8];
3882
4390
  case '395':
3883
4391
  case 'n2':
3884
- return [395, 'numeric', 'left', widget.get_lang_text(name) || name, 0]; // Security type
4392
+ return [395, 'numeric', 'left', widget.get_lang_text(name) || name, 0];
3885
4393
  case '396':
3886
4394
  case 'n3':
3887
- return [396, 'numeric', 'left', widget.get_lang_text(name) || name, 0]; // Security type
4395
+ return [396, 'numeric', 'left', widget.get_lang_text(name) || name, 0];
3888
4396
  case '22':
3889
4397
  case 'name':
3890
4398
  return [22, 'string', 'left', widget.get_lang_text(name) || name, 0];
@@ -3896,10 +4404,10 @@ function MillistreamWidgetApi_getColumnInfo(widget, name) {
3896
4404
  return [138, 'numeric', 'right', widget.get_lang_text(name) || name, 8];
3897
4405
  case '48':
3898
4406
  case 'newsid':
3899
- return [48, 'string', 'left', 'newsid', 0]; // hardoded should not be used by any display
4407
+ return [48, 'string', 'left', 'newsid', 0];
3900
4408
  case 'newstype':
3901
4409
  case '86':
3902
- return [86, 'string', 'left', 'newstype', 0]; // hardoded should not be used by any display
4410
+ return [86, 'string', 'left', 'newstype', 0];
3903
4411
  case '219':
3904
4412
  case 'noncurrentasset':
3905
4413
  return [219, 'numeric', 'right', widget.get_lang_text(name) || name, 8];
@@ -3959,13 +4467,13 @@ function MillistreamWidgetApi_getColumnInfo(widget, name) {
3959
4467
  return [98, 'string', 'left', widget.get_lang_text(name) || name, 0];
3960
4468
  case '180':
3961
4469
  case 's3':
3962
- return [180, 'string', 'left', widget.get_lang_text(name) || name, 0]; // Position
4470
+ return [180, 'string', 'left', widget.get_lang_text(name) || name, 0];
3963
4471
  case '181':
3964
4472
  case 's4':
3965
- return [181, 'string', 'left', widget.get_lang_text(name) || name, 0]; // Position
4473
+ return [181, 'string', 'left', widget.get_lang_text(name) || name, 0];
3966
4474
  case '393':
3967
4475
  case 's10':
3968
- return [393, 'string', 'left', widget.get_lang_text(name) || name, 0]; // comment
4476
+ return [393, 'string', 'left', widget.get_lang_text(name) || name, 0];
3969
4477
  case '127':
3970
4478
  case 'sales':
3971
4479
  return [127, 'numeric', 'right', widget.get_lang_text(name) || name, 8];
@@ -4002,7 +4510,7 @@ function MillistreamWidgetApi_getColumnInfo(widget, name) {
4002
4510
  case '227':
4003
4511
  case 'totalassets':
4004
4512
  return [227, 'numeric', 'right', widget.get_lang_text(name) || name, 8];
4005
- case '1023': // TODO, define this with correct value
4513
+ case '1023':
4006
4514
  case 'totalnumberofshares':
4007
4515
  return [1023, 'numeric', 'right', widget.get_lang_text(name) || name, 8];
4008
4516
  case '233':
@@ -4051,7 +4559,7 @@ function MillistreamWidgetApi_getColumnInfo(widget, name) {
4051
4559
  case 'vega':
4052
4560
  return [703, 'numeric', 'right', widget.get_lang_text(name) || name, 0];
4053
4561
 
4054
- // brokerstats
4562
+
4055
4563
  case '3000':
4056
4564
  case 'boughtquantity':
4057
4565
  return [3000, 'numeric', 'right', widget.get_lang_text(name) || name, 4];
@@ -4239,7 +4747,7 @@ function MillistreamWidgetApi_getColumnInfo(widget, name) {
4239
4747
  case '3060':
4240
4748
  case 'soldturnoverytd':
4241
4749
  return [3060, 'numeric', 'left', widget.get_lang_text(name) || name, 4];
4242
- // key ratios egen definerade
4750
+
4243
4751
  case 'per_last':
4244
4752
  case '3100':
4245
4753
  return [3100, 'numeric', 'right', widget.get_lang_text(name) || name, 0];
@@ -4360,7 +4868,7 @@ function MillistreamWidgetApi_getColumnInfo(widget, name) {
4360
4868
  case 'latestreport':
4361
4869
  case '3140':
4362
4870
  return [3140, 'date', 'right', widget.get_lang_text(name) || name, 0];
4363
- // basicdata join fields
4871
+
4364
4872
  case 'fundcompanyname':
4365
4873
  case '3200':
4366
4874
  return [3200, 'string', 'left', widget.get_lang_text(name) || name, 0];
@@ -4379,17 +4887,17 @@ function MillistreamWidgetApi_getColumnInfo(widget, name) {
4379
4887
  case '3205':
4380
4888
  case 'underlyingsymbol':
4381
4889
  return [3204, 'string', 'left', widget.get_lang_text(name) || name, 0];
4382
- case '3206': // tmcwatch
4890
+ case '3206':
4383
4891
  case 'multiplier':
4384
4892
  return [3206, 'string', 'left', widget.get_lang_text(name) || name, 0];
4385
- case '3207': // tmcwach
4893
+ case '3207':
4386
4894
  case 'type':
4387
4895
  return [3207, 'string', 'left', widget.get_lang_text(name) || name, 0];
4388
- case '3208': // tmcwach
4896
+ case '3208':
4389
4897
  case 'direction':
4390
4898
  return [3208, 'string', 'left', widget.get_lang_text(name) || name, 0];
4391
4899
 
4392
- // optionwatch
4900
+
4393
4901
  case '3300':
4394
4902
  case 'iv30d':
4395
4903
  case 'ivXXd':
@@ -4432,8 +4940,8 @@ function MillistreamWidgetApi_getColumnInfo(widget, name) {
4432
4940
  }
4433
4941
  }
4434
4942
 
4435
- function set_hashed_element(widget, insref, info, json, num_dec) { // called from push
4436
- // external : list
4943
+ function set_hashed_element(widget, insref, info, json, num_dec) {
4944
+
4437
4945
  var key = insref + '_' + info[0];
4438
4946
  var arr = widget.cell_map.get(key);
4439
4947
  if (arr !== undefined) {
@@ -4443,9 +4951,9 @@ function set_hashed_element(widget, insref, info, json, num_dec) { // called fro
4443
4951
  }
4444
4952
  }
4445
4953
 
4446
- // Create Element functions
4954
+
4447
4955
  function MillistreamWidgetApi_addElementToMap(insref, field, element, widget) {
4448
- // internal
4956
+
4449
4957
  if (insref && field && widget && widget.cell_map) {
4450
4958
  var key = insref + '_' + field;
4451
4959
  var arr = widget.cell_map.get(key);
@@ -4461,7 +4969,7 @@ function MillistreamWidgetApi_addElementToMap(insref, field, element, widget) {
4461
4969
  }
4462
4970
 
4463
4971
  function MillistreamWidgetApi_addElement(widget, el, cl, parent, field, value, overridedecimals) {
4464
- // external
4972
+
4465
4973
  var element = document.createElement(el);
4466
4974
  if (cl)
4467
4975
  element.setAttribute('class', cl);
@@ -4544,7 +5052,7 @@ function MillistreamWidgetApi_addTableCell(widget, key, cl, parent, json, decima
4544
5052
  widget.settings.link_field.forEach(function(element) {
4545
5053
  hrefparam[element] = json[element];
4546
5054
  });
4547
- if (info[0] == 1) { // headline, borde inte behövas i list
5055
+ if (info[0] == 1) {
4548
5056
  td.onclick = function(e) {
4549
5057
  hrefparam.event = e;
4550
5058
  hrefparam.source = widget;
@@ -4660,7 +5168,7 @@ function fabs(value) {
4660
5168
  }
4661
5169
 
4662
5170
  function zeroPad(number, width) {
4663
- //internal
5171
+
4664
5172
  if (number <= 9.9999999 * Math.pow(10, width)) return ("0000000" + number).slice(-width);
4665
5173
  return number;
4666
5174
  }
@@ -4704,8 +5212,8 @@ function formatNiceNumber(y, thousandSeparator, decimalSeparator, precision, add
4704
5212
  return parts;
4705
5213
  }
4706
5214
 
4707
- function formatDate(date, format) {
4708
- // internal
5215
+ function formatDate(date, format, widget) {
5216
+
4709
5217
  var timeStamp, mon, day;
4710
5218
  if (format == 'yyyy-mm-dd') {
4711
5219
  timeStamp = new Date(date);
@@ -4719,50 +5227,66 @@ function formatDate(date, format) {
4719
5227
  day = timeStamp.getDate();
4720
5228
  return timeStamp.getFullYear() % 100 + '-' + (mon <= 9 ? '0' + mon : mon) + '-' + (day <= 9 ? '0' + day : day);
4721
5229
  }
4722
- if (format == 'b dd') { // Jan 01
5230
+ if (format == 'b dd') {
4723
5231
  timeStamp = new Date(date);
4724
5232
  mon = timeStamp.toDateString().split(' ');
4725
5233
  day = timeStamp.getDate();
4726
5234
  return mon[1] + ' ' + (day <= 9 ? '0' + day : day);
4727
5235
  }
4728
- if (format == 'b dd yyyy') { // Jan 01 2017
5236
+ if (format == 'b dd yyyy') {
4729
5237
  timeStamp = new Date(date);
4730
5238
  mon = timeStamp.toDateString().split(' ');
4731
5239
  day = timeStamp.getDate();
4732
5240
  return mon[1] + ' ' + (day <= 9 ? '0' + day : day) + ' ' + timeStamp.getFullYear();
4733
5241
  }
4734
- if (format == 'dd/mm') { // Jan 01 2017
5242
+ if (format == 'dd/mm') {
4735
5243
  timeStamp = new Date(date);
4736
5244
  mon = timeStamp.getMonth() + 1;
4737
5245
  day = timeStamp.getDate();
4738
5246
  return (day <= 9 ? '0' + day : day) + '/' + (mon <= 9 ? '0' + mon : mon);
4739
5247
  }
4740
- if (format == 'd/m') { // Jan 01 2017
5248
+ if (format == 'd/m') {
4741
5249
  timeStamp = new Date(date);
4742
5250
  return (timeStamp.getDate() + '/' + (timeStamp.getMonth() + 1));
4743
5251
  }
4744
5252
  if (format == 'd mmm yyyy') {
4745
5253
  timeStamp = new Date(date);
4746
- mon = timeStamp.toDateString().split(' ');
5254
+ mon = timeStamp.toLocaleString(widget.settings.locale, { month: 'short' }).substring(0, 3);
5255
+ day = timeStamp.getDate();
5256
+ return day + ' ' + mon + ' ' + timeStamp.getFullYear();
5257
+ }
5258
+ if (format == 'dd mmm yyyy') {
5259
+ timeStamp = new Date(date);
5260
+ mon = timeStamp.toLocaleString(widget.settings.locale, { month: 'short' }).substring(0, 3);
5261
+ day = timeStamp.getDate();
5262
+ return (day <= 9 ? '0' + day : day) + ' ' + mon + ' ' + timeStamp.getFullYear();
5263
+ }
5264
+ if (format == 'dd mmm') {
5265
+ timeStamp = new Date(date);
5266
+ mon = timeStamp.toLocaleString(widget.settings.locale, { month: 'short' }).substring(0, 3);
4747
5267
  day = timeStamp.getDate();
4748
- return (day <= 9 ? '0' + day : day) + ' ' + mon[1] + ' ' + timeStamp.getFullYear();
5268
+ return (day <= 9 ? '0' + day : day) + ' ' + mon;
5269
+ }
5270
+ if (format == 'd mmm') {
5271
+ timeStamp = new Date(date);
5272
+ mon = timeStamp.toLocaleString(widget.settings.locale, { month: 'short' }).substring(0, 3);
5273
+ day = timeStamp.getDate();
5274
+ return day + ' ' + mon;
4749
5275
  }
4750
5276
  if (format == 'mmm yyyy') {
4751
5277
  timeStamp = new Date(date);
4752
- //mon = timeStamp.toDateString().split(' ');
4753
- mon = timeStamp.toLocaleString('sv-SE', { month: 'short' }).substring(0, 3); // lang....
5278
+ mon = timeStamp.toLocaleString(widget.settings.locale, { month: 'short' }).substring(0, 3);
4754
5279
  timeStamp = mon + ' ' + timeStamp.getFullYear();
4755
5280
  return timeStamp;
4756
5281
  }
4757
5282
  if (format == 'mmm yy') {
4758
5283
  timeStamp = new Date(date);
4759
- //mon = timeStamp.toDateString().split(' ');
4760
- mon = timeStamp.toLocaleString('sv-SE', { month: 'short' }).substring(0, 3); // lang
5284
+ mon = timeStamp.toLocaleString(widget.settings.locale, { month: 'short' }).substring(0, 3);
4761
5285
  timeStamp = mon + ' ' + (timeStamp.getFullYear() % 100 < 9 ? '0' + timeStamp.getFullYear() % 100 : timeStamp.getFullYear() % 100);
4762
5286
  return timeStamp;
4763
5287
  }
4764
5288
 
4765
- // default yyyy-mm-dd
5289
+
4766
5290
  timeStamp = new Date(date);
4767
5291
  mon = timeStamp.getMonth() + 1;
4768
5292
  day = timeStamp.getDate();
@@ -4770,7 +5294,7 @@ function formatDate(date, format) {
4770
5294
  }
4771
5295
 
4772
5296
  function formatTime(value, format) {
4773
- // internal
5297
+
4774
5298
  if (typeof value !== 'string') return "";
4775
5299
  var datetime = new Date();
4776
5300
  var tz_offset = datetime.getTimezoneOffset();
@@ -4837,7 +5361,7 @@ function MillistreamWidgetApi_formatDateTime(widget, date, time, ignoreDateIfTod
4837
5361
  //var newsdate = new Date(resp.headlines[i].date + 'T' + resp.headlines[i].time + '.000+00:00');
4838
5362
  var newsdate = new Date(date + 'T' + time);
4839
5363
  if (ignoreDateIfToday == false || (today.getDate() != newsdate.getDate() || today.getMonth() != newsdate.getMonth() || today.getFullYear() != newsdate.getFullYear())) {
4840
- datetime = formatDate(date, widget.settings.dateformat) + ' ';
5364
+ datetime = formatDate(date, widget.settings.dateformat, widget) + ' ';
4841
5365
  }
4842
5366
  datetime += formatTime(time, widget.settings.timeformat);
4843
5367
  return datetime;
@@ -4976,7 +5500,7 @@ function milli_widget_get_data(request, callback) {
4976
5500
  }
4977
5501
 
4978
5502
  function MillistreamWidgetApi_scrollIntoView(scrollarea, elem, xalign, yalign) {
4979
- //console.log("MillistreamWidgetApi_scrollIntoView", scrollarea, elem, elem.offsetLeft, elem.offsetTop, elem.offsetHeight);
5503
+
4980
5504
 
4981
5505
  if (typeof xalign == "undefined")
4982
5506
  xalign = null;
@@ -4999,11 +5523,12 @@ function MillistreamWidgetApi_scrollIntoView(scrollarea, elem, xalign, yalign) {
4999
5523
  scrollarea.scrollLeft = elem.offsetLeft - scrollarea.getBoundingClientRect().width / 2;
5000
5524
  }
5001
5525
 
5002
- // scrollIntoView : replace this, breaks apps
5526
+
5003
5527
  }
5004
5528
 
5005
5529
  var MillistreamWidgetSettings = {
5006
5530
  language: "sv",
5531
+ locale: 'sv-SE',
5007
5532
  timeformat: 'HH:mm:ss',
5008
5533
  dateformat: "yyyy-mm-dd",
5009
5534
  decimalseparator: ',',
@@ -5019,9 +5544,9 @@ function MillistreamWidgetStreamingApi(settings) {
5019
5544
  server: 'wss://stage.millistream.com:8900',
5020
5545
  alarmClient: null
5021
5546
  };
5022
- var m_requestid = 1; // 0 is invalid
5547
+ var m_requestid = 1;
5023
5548
  var m_socket = null;
5024
- var m_requests = []; // queued requests not sent
5549
+ var m_requests = [];
5025
5550
  var m_requestcallbacks = new Map();
5026
5551
 
5027
5552
 
@@ -5054,7 +5579,7 @@ function MillistreamWidgetStreamingApi(settings) {
5054
5579
  req = new Object({
5055
5580
  "widget": widget,
5056
5581
  });
5057
- m_requestcallbacks.set(requestid.toString(), req); // this requestid will be forarded to this widget
5582
+ m_requestcallbacks.set(requestid.toString(), req);
5058
5583
  }
5059
5584
  var request = '';
5060
5585
  if (MillistreamWidgetApi_isObjectEmpty(widget.unsubscriptions) == false) {
@@ -5116,215 +5641,20 @@ function MillistreamWidgetStreamingApi(settings) {
5116
5641
 
5117
5642
 
5118
5643
  widget.unsubscriptions.type = 'insrefs';
5119
- widget.unsubscriptions.insrefs = insrefs.slice(0); // copy array
5644
+ widget.unsubscriptions.insrefs = insrefs.slice(0);
5120
5645
  widget.unsubscriptions.messagetypes = widget.settings.messagetypes;
5121
5646
  widget.unsubscriptions.requestid = requestid;
5122
5647
 
5123
5648
  return requestid;
5124
5649
  };
5125
- /*
5126
- _this.MillistreamWidgetStreamingApi_request = function(widget, requestid, insrefs) {
5127
- if (typeof requestid !== 'number' || requestid == 0) requestid = m_requestid++;
5128
- var req = m_requestcallbacks.get(requestid.toString());
5129
-
5130
- if (typeof req === 'undefined') {
5131
- req = new Object({
5132
- "widget": widget,
5133
- });
5134
- m_requestcallbacks.set(requestid.toString(), req); // this requestid will be forarded to this widget
5135
- }
5136
- var request = '';
5137
- if (MillistreamWidgetApi_isObjectEmpty(widget.unsubscriptions) == false) {
5138
- var mref_subscribe = Math.abs(widget.settings.messagetypes - widget.unsubscriptions.messagetypes);
5139
- //var instruments = insrefs.filter(x => !widget.unsubscriptions.insrefs.includes(x)); // new instruments against old request
5140
- var instruments = insrefs.filter(function(x) { return !widget.unsubscriptions.insrefs.includes(x); });
5141
- //var oldinstruments = widget.unsubscriptions.insrefs.filter(x => !insrefs.includes(x));
5142
- var oldinstruments = widget.unsubscriptions.insrefs.filter(function(x) { return !insrefs.includes(x); });
5143
-
5144
- // unsubscribe oldinstruments
5145
- if (oldinstruments.length != 0) {
5146
- // instruments no longer needed
5147
- //request = '{ "token":"' + _this.settings.token + '","requests":[{"id":"' + widget.unsubscriptions.requestid + '","unsubscribe" : true,"mc":"' + widget.unsubscriptions.messagetypes + '","insrefs": "' + oldinstruments.join() + '"';
5148
- request = '"requests":[{"id":"' + widget.unsubscriptions.requestid + '","unsubscribe" : true,"mc":"' + widget.unsubscriptions.messagetypes + '","insrefs": "' + oldinstruments.join() + '"';
5149
- request += '}]}';
5150
- MillistreamWidgetStreamingApi_send(request, requestid, true);
5151
- }
5152
- if (mref_subscribe != 0) {
5153
- //unsubscribe mrefs we no longer need from the active instruments in the old request
5154
- //var keptinstruments = widget.unsubscriptions.insrefs.filter(x => !oldinstruments.includes(x));
5155
- var keptinstruments = widget.unsubscriptions.insrefs.filter(function(x) { return !oldinstruments.includes(x); });
5156
- //request = '{ "token":"' + _this.settings.token + '","requests":[{"id":"' + widget.unsubscriptions.requestid + '","unsubscribe" : true,"mc":"' + mref_subscribe + '","insrefs": "' + keptinstruments.join() + '"';
5157
- request = '"requests":[{"id":"' + widget.unsubscriptions.requestid + '","unsubscribe" : true,"mc":"' + mref_subscribe + '","insrefs": "' + keptinstruments.join() + '"';
5158
- request += '}]}';
5159
- MillistreamWidgetStreamingApi_send(request, requestid, true);
5160
- }
5161
- if (instruments.length != 0) {
5162
- // request new instruments with new mref
5163
- //request = '{ "token":"' + _this.settings.token + '","requests":[{"id":"' + requestid + '","mc":"' + widget.settings.messagetypes + '","insrefs": "' + instruments.join() + '"';
5164
- request = '"requests":[{"id":"' + requestid + '","mc":"' + widget.settings.messagetypes + '","insrefs": "' + instruments.join() + '"';
5165
- request += '}]}';
5166
- MillistreamWidgetStreamingApi_send(request, requestid, false);
5167
- }
5168
- for (var i = 0; i < m_requests.length; i++) {
5169
- if (m_requests[i].requestid == widget.requestid) {
5170
- // change the request we store for rerequest on disconnect, why?
5171
- //m_requests[i].request = '{ "token":"' + _this.settings.token + '","requests":[{"id":"' + requestid + '","mc":"' + widget.settings.messagetypes + '","insrefs": "' + insrefs.join() + '"}]}';
5172
- m_requests[i].request = '"requests":[{"id":"' + requestid + '","mc":"' + widget.settings.messagetypes + '","insrefs": "' + insrefs.join() + '"}]}';
5173
- }
5174
- }
5175
- } else {
5176
- if (insrefs.length > 0) {
5177
- //request = '{ "token":"' + _this.settings.token + '","requests":[{"id":"' + requestid + '","mc":"' + widget.settings.messagetypes + '","insrefs": "' + insrefs.join() + '"}]}';
5178
- request = '"requests":[{"id":"' + requestid + '","mc":"' + widget.settings.messagetypes + '","insrefs": "' + insrefs.join() + '"}]}';
5179
- MillistreamWidgetStreamingApi_send(request, requestid, false);
5180
- } else {}
5181
- }
5182
- //console.log(request);
5183
- if (insrefs.length == 0) {
5184
- // if we have no insrefs it is the same as an unsubscribe so remove it from our map to release it for destruction
5185
- var callback = m_requestcallbacks.get(requestid);
5186
- if (typeof callback !== 'undefined') {
5187
- m_requestcallbacks.delete(requestid);
5188
- }
5189
- widget.unsubscriptions = {};
5190
- return;
5191
- }
5192
-
5193
-
5194
- widget.unsubscriptions.type = 'insrefs';
5195
- widget.unsubscriptions.insrefs = insrefs.slice(0); // copy array
5196
- widget.unsubscriptions.messagetypes = widget.settings.messagetypes;
5197
- widget.unsubscriptions.requestid = requestid;
5198
-
5199
- return requestid;
5200
- };
5201
-
5202
-
5203
-
5204
- _this.MillistreamWidgetStreamingApi_unsubscribe = function(widget) {
5205
- if (MillistreamWidgetApi_isObjectEmpty(widget.unsubscriptions)) throw new Error('MillistreamWidget_streamingAPI: invalid unsubcscription');
5206
- for (var i = 0; i < m_requests.length; i++) {
5207
- if (m_requests[i].requestid == widget.m_requestid) {
5208
- m_requests.splice(i, 1);
5209
- }
5210
- }
5211
-
5212
- var mref_unsubscribe = Math.abs((widget.unsubscriptions.messagetypes & widget.settings.messagetypes) - widget.unsubscriptions.messagetypes);
5213
- var type = widget.unsubscriptions.type;
5214
- var request;
5215
- if (widget.settings[type] == null || (typeof widget.settings[type] !== 'object' && typeof widget.settings[type] !== 'number')) { // invalidated or changed from instruments request to something else so just unsubscribe it all
5216
- //request = '{ "token":"' + _this.settings.token + '","requests":[{"id":"' + widget.unsubscriptions.requestid + '","unsubscribe" : true,"mc":"' + widget.unsubscriptions.messagetypes + '","' + type + '" : "' + widget.unsubscriptions.insrefs.join() + '"';
5217
- request = '"requests":[{"id":"' + widget.unsubscriptions.requestid + '","unsubscribe" : true,"mc":"' + widget.unsubscriptions.messagetypes + '","' + type + '" : "' + widget.unsubscriptions.insrefs.join() + '"';
5218
- if (widget.unsubscriptions.instrumenttypes) request += ',"instrumenttype" : "' + widget.unsubscriptions.instrumenttypes.join() + '"';
5219
- request += '}]}';
5220
- MillistreamWidgetStreamingApi_send(request);
5221
- widget.unsubscriptions = {};
5222
- return;
5223
- } else {
5224
- var unsubscribes = widget.unsubscriptions.insrefs.filter(function(x) { return !widget.settings[type].includes(x); }); // ubsubscribes is all the instruments that have been removed
5225
- if (unsubscribes.length != 0) { // have we removed any insrefs, then unsubscribe them completely
5226
- //request = '{ "token":"' + _this.settings.token + '","requests":[{"id":"' + widget.unsubscriptions.requestid + '","unsubscribe" : true,"mc":"' + widget.unsubscriptions.messagetypes + '","' + type + '" : "' + unsubscribes.join() + '"';
5227
- request = '"requests":[{"id":"' + widget.unsubscriptions.requestid + '","unsubscribe" : true,"mc":"' + widget.unsubscriptions.messagetypes + '","' + type + '" : "' + unsubscribes.join() + '"';
5228
- if (widget.unsubscriptions.instrumenttypes) request += ',"instrumenttype" : "' + widget.unsubscriptions.instrumenttypes.join() + '"';
5229
- request += '}]}';
5230
- MillistreamWidgetStreamingApi_send(request);
5231
- }
5232
- if (mref_unsubscribe != 0) {
5233
- //request = '{ "token":"' + _this.settings.token + '","requests":[{"id":"' + widget.unsubscriptions.requestid + '","unsubscribe" : true,"mc":"' + mref_unsubscribe + '","' + type + '" : "' + widget.unsubscriptions.insrefs.join() + '"';
5234
- request = '"requests":[{"id":"' + widget.unsubscriptions.requestid + '","unsubscribe" : true,"mc":"' + mref_unsubscribe + '","' + type + '" : "' + widget.unsubscriptions.insrefs.join() + '"';
5235
- if (widget.unsubscriptions.instrumenttypes) request += ',"instrumenttype" : "' + widget.unsubscriptions.instrumenttypes.join() + '"';
5236
- request += '}]}';
5237
- MillistreamWidgetStreamingApi_send(request);
5238
- }
5239
- }
5240
- return;
5241
- };
5242
- */
5243
-
5244
- /*
5245
- _this.MillistreamWidgetStreamingApi_subscribe = function(widget, requestid) {
5246
- if (typeof requestid !== 'number' || requestid == 0) requestid = m_requestid++;
5247
- var req = m_requestcallbacks.get(requestid.toString());
5248
- //console.log('subsc');
5249
-
5250
- if (typeof req === 'undefined') {
5251
- req = new Object({
5252
- "widget": widget,
5253
- });
5254
- m_requestcallbacks.set(requestid.toString(), req);
5255
- }
5256
5650
 
5257
- var request = '';
5258
- var insrefs = null;
5259
- var type = null;
5260
- var instrumenttypes = null;
5261
- var maxrows = null;
5262
- if (widget.settings.agency) {
5263
- insrefs = widget.settings.agency;
5264
- type = 'insrefs';
5265
- maxrows = typeof widget.settings.maxrows === 'number' ? widget.settings.maxrows : null;
5266
- } else
5267
- if (widget.settings.instrument) {
5268
- insrefs = typeof widget.settings.instrument === 'object' ? widget.settings.instrument : [widget.settings.instrument];
5269
- type = 'insrefs';
5270
- } else
5271
- if (widget.settings.list) {
5272
- insrefs = widget.settings.list;
5273
- type = 'list';
5274
- } else
5275
- if (widget.settings.marketplace) {
5276
- insrefs = widget.settings.marketplace;
5277
- type = 'marketplace';
5278
- instrumenttypes = widget.settings.instrumenttype;
5279
- }
5280
- if (MillistreamWidgetApi_isObjectEmpty(widget.unsubscriptions) == false) {
5281
- //console.log('unsubscribe', widget.unsubscriptions);
5282
- var mref_subscribe = Math.abs(widget.settings.messagetypes - widget.unsubscriptions.messagetypes);
5283
- var instruments = widget.settings[type].filter(function(x) { return !widget.unsubscriptions.insrefs.includes(x); }); // new instruments against old request
5284
- if (instruments.length != 0) {
5285
- //request = '{ "token":"' + _this.settings.token + '","requests":[{"id":"' + requestid + '","mc":"' + widget.settings.messagetypes + '","' + type + '": "' + instruments.join() + '"';
5286
- request = '"requests":[{"id":"' + requestid + '","mc":"' + widget.settings.messagetypes + '","' + type + '": "' + instruments.join() + '"';
5287
- if (instrumenttypes) request += ',"instrumenttype" : "' + widget.settings.instrumenttype.join() + '"';
5288
- if (maxrows) request += ',"maxrows": ' + maxrows;
5289
- request += '}]}';
5290
- MillistreamWidgetStreamingApi_send(request, requestid);
5291
- }
5292
- if (mref_subscribe != 0) {
5293
- instruments = widget.unsubscriptions.insrefs.filter(function(x) { return widget.settings[type].includes(x); }); // subscribes all the instruments that we have not unsubscribed
5294
- if (instruments.length != 0) {
5295
- //request = '{ "token":"' + _this.settings.token + '","requests":[{"id":"' + requestid + '","mc":"' + mref_subscribe + '","' + type + '": "' + instruments.join() + '"';
5296
- request = '"requests":[{"id":"' + requestid + '","mc":"' + mref_subscribe + '","' + type + '": "' + instruments.join() + '"';
5297
- if (instrumenttypes) request += ',"instrumenttype" : "' + widget.settings.instrumenttype.join() + '"';
5298
- if (maxrows) request += ',"maxrows": ' + maxrows;
5299
- request += '}]}';
5300
- MillistreamWidgetStreamingApi_send(request);
5301
- }
5302
- }
5303
- } else {
5304
- //request = '{ "token":"' + _this.settings.token + '","requests":[{"id":"' + requestid + '","mc":"' + widget.settings.messagetypes + '","' + type + '": "' + insrefs.join() + '"';
5305
- request = '"requests":[{"id":"' + requestid + '","mc":"' + widget.settings.messagetypes + '","' + type + '": "' + insrefs.join() + '"';
5306
- if (instrumenttypes) request += ',"instrumenttype" : "' + widget.settings.instrumenttype.join() + '"';
5307
- if (maxrows) request += ',"maxrows": ' + maxrows;
5308
- request += '}]}';
5309
- MillistreamWidgetStreamingApi_send(request, requestid, false);
5310
- }
5311
- widget.unsubscriptions.type = type;
5312
- //widget.unsubscriptions.insrefs = [...insrefs];
5313
- widget.unsubscriptions.insrefs = [].concat(insrefs);
5314
- //widget.unsubscriptions.instrumenttypes = instrumenttypes == null ? null : [...instrumenttypes];
5315
- widget.unsubscriptions.instrumenttypes = instrumenttypes == null ? null : [].concat(instrumenttypes);
5316
- widget.unsubscriptions.messagetypes = widget.settings.messagetypes;
5317
- widget.unsubscriptions.requestid = requestid;
5318
- return requestid;
5319
- };
5320
- */
5321
5651
  _this.milli_stream_disconnect = function() {
5322
5652
  m_socket.close();
5323
5653
  };
5324
5654
 
5325
5655
  function reconnect() {
5326
5656
  if (!m_socket.CLOSED) {
5327
- //console.log('not closed');
5657
+
5328
5658
  return;
5329
5659
  }
5330
5660
  m_requests.forEach(function(request) {
@@ -5343,22 +5673,19 @@ function MillistreamWidgetStreamingApi(settings) {
5343
5673
  try {
5344
5674
  m_socket = new WebSocket(_this.settings.server);
5345
5675
  m_socket.onopen = function() {
5346
- console.log('Connected to millistream push'); /*RemoveLogging:skip*/
5347
- if (m_requests.length > 0) {
5676
+
5348
5677
  m_requests.forEach(function(request) {
5349
5678
  if (request.send == 0) {
5350
- //console.log('rerequest:', request.request);
5679
+
5351
5680
  m_socket.send('{ "token":"' + _this.settings.token + '",' + request.request);
5352
5681
  }
5353
5682
  });
5354
5683
  }
5355
5684
  };
5356
5685
  m_socket.onerror = function() {
5357
- console.log('Error, disconnected'); /*RemoveLogging:skip*/
5358
- };
5686
+
5359
5687
  m_socket.onclose = function() {
5360
- console.log('Disconnected'); /*RemoveLogging:skip*/
5361
- reconnect();
5688
+
5362
5689
  };
5363
5690
 
5364
5691
  m_socket.onmessage = function(msg) {
@@ -5366,9 +5693,8 @@ function MillistreamWidgetStreamingApi(settings) {
5366
5693
  try {
5367
5694
  jsondata = JSON.parse(msg.data);
5368
5695
  } catch (e) {
5369
- console.log('invalid data', msg.data); /*RemoveLogging:skip*/
5370
- }
5371
- //console.log(JSON.stringify(jsondata));
5696
+
5697
+
5372
5698
  if (typeof jsondata.instruments !== 'undefined') {
5373
5699
  for (var s = 0; s < jsondata.instruments.length; s++) {
5374
5700
  var insref = jsondata.instruments[s].insref;
@@ -5394,21 +5720,20 @@ function MillistreamWidgetStreamingApi(settings) {
5394
5720
  if (_this.settings.statusCallback !== null) _this.settings.statusCallback(jsondata);
5395
5721
  } else
5396
5722
  if (typeof jsondata.alarm !== 'undefined') {
5397
- console.log('Alarm: ' + JSON.stringify(jsondata));
5723
+
5398
5724
  if (null != _this.settings.alarmClient) {
5399
5725
  _this.settings.alarmClient(jsondata);
5400
5726
  }
5401
5727
 
5402
5728
  } else
5403
- console.log(JSON.stringify(jsondata)); /*RemoveLogging:skip*/
5404
- };
5729
+
5405
5730
  } catch (exception) {
5406
- console.log('Exception error: ' + exception); /*RemoveLogging:skip*/
5407
- reconnect();
5731
+
5408
5732
  }
5409
5733
  }
5410
5734
  milli_stream_connect();
5411
5735
  }
5736
+
5412
5737
  exports.Milli_Chart = Milli_Chart;
5413
5738
  exports.MillistreamWidgetSettings = MillistreamWidgetSettings;
5414
5739
  exports.formatDate = formatDate;