@millistream/millistream-widgets 1.0.23 → 1.0.25

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 +1165 -478
  2. package/package.json +1 -1
@@ -1,24 +1,24 @@
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
- (function(prototype) {
1
+ /**
2
+ * HiDPI Canvas Polyfill (1.0.10)
3
+ *
4
+ * Author: Jonathan D. Johnson (http://jondavidjohn.com)
5
+ * Homepage: https://github.com/jondavidjohn/hidpi-canvas-polyfill
6
+ * Issue Tracker: https://github.com/jondavidjohn/hidpi-canvas-polyfill/issues
7
+ * License: Apache-2.0
8
+ */
9
+ (function(prototype) {
10
10
 
11
11
  var pixelRatio = (function() {
12
12
  var canvas = document.createElement('canvas'),
13
13
  context = canvas.getContext('2d');
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
14
+ /*backingStore = context.backingStorePixelRatio ||
15
+ context.webkitBackingStorePixelRatio ||
16
+ context.mozBackingStorePixelRatio ||
17
+ context.msBackingStorePixelRatio ||
18
+ context.oBackingStorePixelRatio ||
19
+ context.backingStorePixelRatio || 1;
20
+ return (window.devicePixelRatio || 1) / backingStore;
21
+ */
22
22
  })(),
23
23
  forEach = function(obj, func) {
24
24
  for (var p in obj) {
@@ -29,8 +29,8 @@
29
29
  },
30
30
 
31
31
  ratioArgs = {
32
-
33
-
32
+ //'fillRect': 'all',
33
+ //'clearRect': 'all',
34
34
  'strokeRect': 'all',
35
35
  'moveTo': 'all',
36
36
  'lineTo': 'all',
@@ -43,18 +43,18 @@
43
43
  'rect': 'all',
44
44
  'translate': 'all',
45
45
  'createRadialGradient': 'all',
46
-
46
+ //'createLinearGradient': 'all'
47
47
  };
48
48
 
49
49
  if (pixelRatio === 1) return;
50
50
 
51
51
  function getPixelRatio(_this) {
52
-
53
-
54
-
55
-
56
-
57
-
52
+ /* var backingStore = this.backingStorePixelRatio ||
53
+ this.webkitBackingStorePixelRatio ||
54
+ this.mozBackingStorePixelRatio ||
55
+ this.msBackingStorePixelRatio ||
56
+ this.oBackingStorePixelRatio ||
57
+ this.backingStorePixelRatio || 1;*/
58
58
  var backingStore = _this.backingStorePixelRatio ||
59
59
  _this.webkitBackingStorePixelRatio ||
60
60
  _this.mozBackingStorePixelRatio ||
@@ -63,14 +63,14 @@
63
63
  _this.backingStorePixelRatio || 1;
64
64
  return (window.devicePixelRatio || 1) / backingStore;
65
65
 
66
- };
66
+ }
67
67
 
68
68
  forEach(ratioArgs, function(value, key) {
69
69
  prototype[key] = (function(_super) {
70
70
  return function() {
71
71
  var i, len,
72
72
  args = Array.prototype.slice.call(arguments);
73
- if (key == 'lineTo' || key == 'moveTo') {
73
+ if (key == 'lineTo' || key == 'moveTo') { // PF
74
74
  args = args.map(function(a) {
75
75
  return a;
76
76
  });
@@ -90,7 +90,7 @@
90
90
  })(prototype[key]);
91
91
  });
92
92
 
93
-
93
+ // Stroke lineWidth adjustment
94
94
  prototype.stroke = (function(_super) {
95
95
  return function() {
96
96
  this.lineWidth *= getPixelRatio(this);
@@ -114,12 +114,12 @@
114
114
  var i = _super.apply(this, args);
115
115
 
116
116
  this.font = tmp;
117
-
118
-
119
-
120
-
121
-
122
-
117
+ /*this.font = this.font.replace(
118
+ /(\d+)(px|em|rem|pt)/g,
119
+ function(w, m, u) {
120
+ return Math.floor(m / getPixelRatio()) + u;
121
+ }
122
+ );*/
123
123
  return i;
124
124
  };
125
125
  })(prototype.measureText);
@@ -145,8 +145,8 @@
145
145
  return function() {
146
146
  var args = Array.prototype.slice.call(arguments);
147
147
 
148
- args[1] *= getPixelRatio(this);
149
- args[2] *= getPixelRatio(this);
148
+ args[1] *= getPixelRatio(this); // x
149
+ args[2] *= getPixelRatio(this); // y
150
150
  var tmp = this.font;
151
151
  var _this = this;
152
152
  this.font = this.font.replace(
@@ -158,12 +158,12 @@
158
158
 
159
159
  _super.apply(this, args);
160
160
  this.font = tmp;
161
-
162
-
163
-
164
-
165
-
166
-
161
+ /*this.font = this.font.replace(
162
+ /(\d+)(px|em|rem|pt)/g,
163
+ function(w, m, u) {
164
+ return (m / getPixelRatio()) + u;
165
+ }
166
+ );*/
167
167
  };
168
168
  })(prototype.strokeText);
169
169
 
@@ -185,17 +185,17 @@
185
185
  }
186
186
  prototype.getContext = (function(_super) {
187
187
  return function(type) {
188
-
188
+ //var backingStore, ratio;
189
189
  context = _super.call(this, type);
190
190
 
191
191
  if (type === '2d') {
192
192
 
193
-
194
-
195
-
196
-
197
-
198
-
193
+ /*backingStore = context.backingStorePixelRatio ||
194
+ context.webkitBackingStorePixelRatio ||
195
+ context.mozBackingStorePixelRatio ||
196
+ context.msBackingStorePixelRatio ||
197
+ context.oBackingStorePixelRatio ||
198
+ context.backingStorePixelRatio || 1;*/
199
199
 
200
200
  var ratio = getPixelRatio();
201
201
  if (ratio > 1) {
@@ -220,7 +220,7 @@
220
220
 
221
221
  })(HTMLCanvasElement.prototype);
222
222
 
223
-
223
+ // Millistream Chart
224
224
  function Milli_Chart(settings) {
225
225
  "use strict";
226
226
  var _this = this;
@@ -242,13 +242,13 @@ function Milli_Chart(settings) {
242
242
  compress: 1,
243
243
  curveOnTop: true,
244
244
  dateformat: 'd/m',
245
- drawxaxis: true,
245
+ drawxaxis: true, // TODO: 0 no, 1 yes, 2 yeas with markers (3px lines)
246
246
  drawyaxis: true,
247
247
  drawy2axis: false,
248
248
  enablezoom: true,
249
249
  fields: ['name', 'tradecurrency', 'time', 'date', 'tradeprice', 'tradequantity', 'marketopen', 'marketclose'],
250
250
  fillchart: false,
251
- gridVerticalLines: true,
251
+ gridVerticalLines: true, // 0 off, 1 draw grid lines ,2 fillrect modulo
252
252
  gridVerticalLinesStyle: 'line',
253
253
  gridHorizontalLines: true,
254
254
  gridHorizontalLinesStyle: 'dash',
@@ -257,7 +257,7 @@ function Milli_Chart(settings) {
257
257
  instrument: null,
258
258
  intradayDatePos: { x: 'center', y: 'bottom', orientation: 'horizontal', dateformat: 'd mmm' },
259
259
  intradaylen: null,
260
- messagetypes: 1030,
260
+ messagetypes: 1030, // quote,trades and performance
261
261
  nochartlabel: 'No data to draw on',
262
262
  onreadyCallback: null,
263
263
  previousDayClose: true,
@@ -272,8 +272,8 @@ function Milli_Chart(settings) {
272
272
  display: 'block'
273
273
  },
274
274
  xAxisSpacing: 0,
275
- yAxisSpacing: 4,
276
- xAxisModulo: 1
275
+ yAxisSpacing: 4, // undocumented
276
+ xAxisModulo: 1 // undocumented
277
277
  };
278
278
  var m_startdate = null;
279
279
  var m_chartspaces = {
@@ -286,10 +286,10 @@ function Milli_Chart(settings) {
286
286
  height: 0
287
287
  }
288
288
  };
289
- var m_dummyDiv = null;
289
+ var m_dummyDiv = null; // dummy div For chartclasses
290
290
  var m_canvas = null;
291
291
  var m_ctx = null;
292
- var m_datapoints = [];
292
+ var m_datapoints = []; // for mouseover
293
293
  var m_dataPoints = {
294
294
  arr: [],
295
295
  map: new Map()
@@ -378,7 +378,7 @@ function Milli_Chart(settings) {
378
378
  }
379
379
  var m_instrumentCss = [{
380
380
  color: '#E2507A',
381
-
381
+ //backgroundImage: 'linear-gradient(rgba(226, 80, 122, 0.6),rgba(226, 80, 122, 0))',
382
382
  width: 1
383
383
  }, {
384
384
  color: '#ff0000',
@@ -427,10 +427,10 @@ function Milli_Chart(settings) {
427
427
  }
428
428
 
429
429
  function dateDiffInDays(a, b) {
430
-
430
+ // Discard the time and time-zone information.
431
431
  const utc1 = Date.UTC(a.getFullYear(), a.getMonth(), a.getDate());
432
432
  const utc2 = Date.UTC(b.getFullYear(), b.getMonth(), b.getDate());
433
- return Math.floor((utc2 - utc1) / 86400000);
433
+ return Math.floor((utc2 - utc1) / 86400000); // ms per day
434
434
  }
435
435
 
436
436
  function findFirstWeekDay(date) {
@@ -444,7 +444,7 @@ function Milli_Chart(settings) {
444
444
  }
445
445
 
446
446
  function getFontSize(obj) {
447
-
447
+ //return parseInt(obj.fontSize) * window.devicePixelRatio;
448
448
  return parseInt(obj.fontSize);
449
449
  }
450
450
 
@@ -601,11 +601,23 @@ function Milli_Chart(settings) {
601
601
  _this.scaleinfoY.lowLowerChart = null;
602
602
  _this.scaleinfoY.highLowerChart = null;
603
603
  var data, i;
604
+ var useCloseprice = false;
605
+ var today = new Date().getTime();
606
+ today -= today % 86400000;
607
+ var lastTradeDate = new Date().getTime();
608
+ var todaysOpenTime = new Date(new Date().toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketopen + 'Z').getTime();
609
+ if (typeof _this.instruments[0].trades !== 'undefined' && _this.instruments[0].trades.length > 0) {
610
+ lastTradeDate = new Date(_this.instruments[0].trades[_this.instruments[0].trades.length - 1].timestamp).getTime();
611
+ lastTradeDate -= lastTradeDate % 86400000;
612
+ }
613
+ var quote_timestamp = _this.instruments[0].quotedate + _this.instruments[0].quotetime;
614
+
615
+ if ((_this.instruments[0].quotedate == today && quote_timestamp > todaysOpenTime) || _this.instruments[0].quotedate == lastTradeDate) useCloseprice = true;
604
616
  for (var s = 0; s < _this.instruments.length; s++) {
605
617
  if (_this.instruments[s].insref == 0) continue;
606
618
  _this.instruments[s].startValue = null;
607
619
  data = _this.instruments[s][_this.scaleinfoY.type];
608
- if (_this.scaleinfoY.type != 'history') {
620
+ if (_this.scaleinfoY.type != 'history' && useCloseprice) {
609
621
  if ((_this.settings.chartlen == '1d' || _this.settings.chartlen == '0d') && !m_zoom.mousedown.timestamp) {
610
622
  _this.instruments[s].startValue = parseFloat(_this.instruments[s].closeprice1d) * _this.instruments[s].factor;
611
623
  }
@@ -613,7 +625,7 @@ function Milli_Chart(settings) {
613
625
  var quantity = 0;
614
626
 
615
627
  for (i = 0; i < data.length; i++) {
616
-
628
+ // only calc on visible data
617
629
  var price = data[i].price * _this.instruments[s].factor;
618
630
  quantity = 0;
619
631
  if (data[i].quantity !== 'undefined') {
@@ -621,7 +633,8 @@ function Milli_Chart(settings) {
621
633
  }
622
634
  if (data[i].timestamp < _this.scaleinfoX.startTimeStamp) {
623
635
  if (_this.scaleinfoY.type == 'history') _this.instruments[s].startValue = price;
624
- else if (_this.settings.chartlen != '1d' && _this.settings.chartlen != '0d' && !m_zoom.mousedown.timestamp) {
636
+ //else if (_this.settings.chartlen != '1d' && _this.settings.chartlen != '0d' && !m_zoom.mousedown.timestamp) {
637
+ else if (useCloseprice == false || m_zoom.mousedown.timestamp) {
625
638
  _this.instruments[s].startValue = price;
626
639
  }
627
640
  continue;
@@ -631,7 +644,7 @@ function Milli_Chart(settings) {
631
644
  }
632
645
 
633
646
  if (_this.scaleinfoY.type != 'history' && (data[i].timestamp % 86400000 < _this.instruments[0].opentimestamp || data[i].timestamp % 86400000 > _this.instruments[0].closetimestamp)) {
634
-
647
+ // stämmer detta kan det bli överlapp vid sommartid/vintertid?
635
648
  continue;
636
649
  }
637
650
 
@@ -658,7 +671,7 @@ function Milli_Chart(settings) {
658
671
  if (_this.scaleinfoY.lowLowerChart == null || _this.scaleinfoY.lowLowerChart > quantity) _this.scaleinfoY.lowLowerChart = quantity;
659
672
  if (_this.scaleinfoY.highLowerChart == null || _this.scaleinfoY.highLowerChart < quantity) _this.scaleinfoY.highLowerChart = quantity;
660
673
  }
661
- if ((_this.settings.chartlen == '1d' || _this.settings.chartlen == '0d') && !m_zoom.mousedown.timestamp) {
674
+ if ((_this.settings.chartlen == '1d' || _this.settings.chartlen == '0d') && !m_zoom.mousedown.timestamp) { // if closeprice is used calch high/low on it
662
675
  var cp = parseFloat(_this.instruments[s].closeprice1d) * _this.instruments[s].factor;
663
676
  if (_this.scaleinfoY.lowValue > cp) _this.scaleinfoY.lowValue = cp;
664
677
  else
@@ -687,11 +700,11 @@ function Milli_Chart(settings) {
687
700
  _this.scaleinfoY.lowValue -= 1;
688
701
  _this.scaleinfoY.highValue += 1;
689
702
  }
690
-
703
+ // do we have any analyzis we need to take into account
691
704
  for (i = 0; i < _this.settings.indicators.length; i++) {
692
705
  if (_this.scaleinfoY.type == 'history') data = _this.settings.indicators[i].history;
693
706
  else data = _this.settings.indicators[i].trades;
694
- for (var s = 0; s < data.length; s++) {
707
+ for (s = 0; s < data.length; s++) {
695
708
  if (data[s].timestamp < _this.scaleinfoX.startTimeStamp) {
696
709
  continue;
697
710
  }
@@ -707,38 +720,11 @@ function Milli_Chart(settings) {
707
720
  }
708
721
  }
709
722
  }
723
+ _this.scaleinfoY2.lowValue = (_this.scaleinfoY.lowValue - _this.instruments[0].startValue) / _this.instruments[0].startValue * 100;
724
+ _this.scaleinfoY2.highValue = (_this.scaleinfoY.highValue - _this.instruments[0].startValue) / _this.instruments[0].startValue * 100;
710
725
  return 1;
711
726
  }
712
727
 
713
- function plotLower(valuePerPixel, lineLength) {
714
- m_ctx.save();
715
- m_ctx.strokeStyle = m_instrumentCss[0].color;
716
- m_ctx.lineWidth = m_instrumentCss[0].width;
717
- var width = Math.round(m_chartspaces.lowerChart.width / (m_datapoints.length + 1) / 2);
718
- if (width < 2) width = 2;
719
- else if (width > 20) width = 20;
720
- m_ctx.lineWidth = width;
721
- for (var i = 0; i < m_datapoints.length; i++) {
722
- var x = m_datapoints[i].x + 0.5;
723
- m_ctx.lineWidth = width;
724
- if (x - width <= m_chartspaces.lowerChart.left) {
725
- m_ctx.lineWidth = width / 2;
726
- x += m_ctx.lineWidth / 2;
727
- } else
728
- if (x + width >= m_chartspaces.lowerChart.right) {
729
- m_ctx.lineWidth = width / 2;
730
- x -= m_ctx.lineWidth / 2 + 1;
731
- }
732
- m_ctx.beginPath();
733
- m_ctx.moveTo(x, m_chartspaces.lowerChart.bottom - 0.5);
734
- var y = Math.round(m_chartspaces.lowerChart.bottom - (m_datapoints[i].quantity * valuePerPixel)) - 1;
735
- m_ctx.closePath();
736
- m_ctx.lineTo(x, y - 0.5);
737
- m_ctx.stroke();
738
- }
739
- m_ctx.restore();
740
- }
741
-
742
728
  function drawYLegendLower(x, numticks, lineLength, markers) {
743
729
  var i;
744
730
  _this.scaleinfoY.lowLowerChart = null;
@@ -760,7 +746,7 @@ function Milli_Chart(settings) {
760
746
  var maxValue = _this.scaleinfoY.highLowerChart == 0 ? 100 : _this.scaleinfoY.highLowerChart + (tickSize * 0.2);
761
747
  var valuePerPixel = lineLength / maxValue;
762
748
  if (isNaN(valuePerPixel) || !isFinite(valuePerPixel)) {
763
- () => {};
749
+ console.log('cant draw valuePerPixel' + valuePerPixel, lineLength, maxValue);
764
750
  return false;
765
751
  }
766
752
  var value = 0;
@@ -781,7 +767,7 @@ function Milli_Chart(settings) {
781
767
  m_ctx.closePath();
782
768
  m_ctx.restore();
783
769
  } else
784
- if (_this.settings.drawyaxis == true && markers == true) {
770
+ if (_this.settings.drawyaxis == true && markers == true) { // draw legenditem markers for price
785
771
  m_ctx.beginPath();
786
772
  m_ctx.moveTo(m_chartspaces.lowerChart.left, y + 0.5);
787
773
  m_ctx.lineTo(m_chartspaces.lowerChart.left + 3, y + 0.5);
@@ -793,7 +779,7 @@ function Milli_Chart(settings) {
793
779
  var label = formatLargeNumber(value, 0, _this);
794
780
  var textpos = x - 5;
795
781
  if (m_yLegendCss.verticalAlign == 'top') {
796
- if (y - (getFontSize(m_yLegendCss)) > 0)
782
+ if (y - (getFontSize(m_yLegendCss)) > 0) // dont draw if cropped
797
783
  m_ctx.fillText(label, textpos, y - ((getFontSize(m_yLegendCss) + 2)));
798
784
  } else
799
785
  m_ctx.fillText(label, textpos, y - (getFontSize(m_yLegendCss) / 2));
@@ -811,7 +797,7 @@ function Milli_Chart(settings) {
811
797
  m_ctx.fillStyle = m_yLegendCss.color;
812
798
  var lineLen = m_chartspaces.lowerChart.bottom - m_chartspaces.lowerChart.top;
813
799
  var numticks = lineLen / (getFontSize(m_yLegendCss) * 2);
814
- if (numticks > 8) numticks = 8;
800
+ if (numticks > 8) numticks = 8; // limit to 8 items on Y legend ( this is not an absolut count, since we calculate nice legend numbers
815
801
 
816
802
  m_ctx.beginPath();
817
803
  m_ctx.strokeStyle = m_gridVerticalCss.color;
@@ -825,21 +811,22 @@ function Milli_Chart(settings) {
825
811
  }
826
812
 
827
813
  function checkYLegendSpace(y, text) {
828
-
814
+ //if (y - (getFontSize(m_yLegendCss) / 2) - m_chartspaces.chart.top < 0) return false;
829
815
  if (y - (getFontSize(m_yLegendCss)) - m_chartspaces.chart.top < 0) return false;
830
816
  if (y > m_chartspaces.chart.bottom) return false;
831
817
  return true;
832
818
  }
833
819
 
834
- function drawY2Legend(x) {
820
+ function drawY2Legend(x) { // percent
821
+ if (_this.instruments[0].pricetype == 'yield') return;
835
822
  if (_this.settings.absoluteScaling == true) {
836
823
  for (var s = 1; s < _this.instruments.length; s++) {
837
824
  if (_this.instruments[s].insref != 0) return;
838
825
  }
839
826
  }
840
- if (_this.instruments[0].startValue == null || (_this.scaleinfoY2.highValue == 100 && _this.scaleinfoY2.lowValue == 0)) return false;
827
+
841
828
  _this.scaleinfoY2.maxValue = _this.scaleinfoY2.highValue + (_this.scaleinfoY2.tickSize * 0.2);
842
- _this.scaleinfoY2.minValue = _this.scaleinfoY2.lowValue + (_this.scaleinfoY2.tickSize * 0.2);
829
+ _this.scaleinfoY2.minValue = _this.scaleinfoY2.lowValue - (_this.scaleinfoY2.tickSize * 0.2);
843
830
  m_ctx.font = m_y2LegendCss.fontWeight + ' ' + m_y2LegendCss.fontSize + ' ' + m_y2LegendCss.fontFamily;
844
831
  var value;
845
832
  if (_this.scaleinfoY2.highValue == _this.scaleinfoY2.lowValue) {
@@ -859,7 +846,7 @@ function Milli_Chart(settings) {
859
846
  var count = 0;
860
847
  for (;;) {
861
848
  if (count++ > 10) {
862
- () => {};
849
+ console.log('break out');
863
850
  break;
864
851
  }
865
852
  var v;
@@ -870,9 +857,9 @@ function Milli_Chart(settings) {
870
857
  var y = Math.round(m_chartspaces.chart.height - getScaledSetting(m_chartCss.marginBottom) - ((v - _this.scaleinfoY.minValue) * _this.scaleinfoY.valuePerPixel));
871
858
 
872
859
  if (y <= m_chartspaces.chart.top) break;
873
-
860
+ //if (y > m_chartspaces.chart.bottom) break;
874
861
  if (y <= m_chartspaces.chart.bottom) {
875
- if (_this.settings.drawy2axis == true) {
862
+ if (_this.settings.drawy2axis == true) { // draw legenditem markers for diff
876
863
  m_ctx.beginPath();
877
864
  m_ctx.moveTo(x, y + 0.5);
878
865
  if ((m_y2LegendCss.float == 'left' && m_y2LegendCss.textAlign == 'left') || (m_y2LegendCss.float == 'right' && m_y2LegendCss.textAlign == 'left')) {
@@ -902,10 +889,16 @@ function Milli_Chart(settings) {
902
889
 
903
890
  function drawYLegend(si, x, gridHorizontalLines, number, draw) {
904
891
  var value;
905
- si.maxValue = si.highValue + (si.tickSize * 0.2);
906
- si.minValue = si.lowValue - (si.tickSize * 0.2);
892
+ //si.maxValue = si.highValue + (si.tickSize * 0.2);
893
+ //si.minValue = si.lowValue - (si.tickSize * 0.2);
894
+
895
+ let v = (si.highValue - si.lowValue) / si.lineLength;
896
+ si.maxValue = si.highValue + (v * parseInt(m_yLegendCss.fontSize));
897
+ si.minValue = si.lowValue - (v * parseInt(m_yLegendCss.fontSize));
898
+
899
+
907
900
  m_ctx.font = m_yLegendCss.fontWeight + ' ' + m_yLegendCss.fontSize + ' ' + m_yLegendCss.fontFamily;
908
- if (si.highValue == si.lowValue) {
901
+ if (si.highValue == si.lowValue) { // only have one value so set values for 1 line only
909
902
  si.maxValue = si.maxValue + si.tickSize;
910
903
  si.minValue = si.minValue - si.tickSize;
911
904
  value = Math.abs(si.lowValue);
@@ -917,14 +910,14 @@ function Milli_Chart(settings) {
917
910
  }
918
911
  si.valuePerPixel = si.lineLength / (si.maxValue - si.minValue);
919
912
  if (isNaN(si.valuePerPixel) || !isFinite(si.valuePerPixel)) {
920
- () => {};
913
+ console.log('cant draw valuePerPixel', si.valuePerPixel, si.lineLength, si.maxValue, si.minValue);
921
914
  return false;
922
915
  }
923
916
  var textpos;
924
917
  var count = 0;
925
918
  for (;;) {
926
919
  if (count++ > 10) {
927
- () => {};
920
+ console.log('failsafe break');
928
921
  break;
929
922
  }
930
923
  var y = Math.round(m_chartspaces.chart.height - getScaledSetting(m_chartCss.marginBottom) - ((value - si.minValue) * si.valuePerPixel));
@@ -948,7 +941,7 @@ function Milli_Chart(settings) {
948
941
  }
949
942
 
950
943
  } else
951
- if (_this.settings.drawyaxis == true && number == 1 && draw) {
944
+ if (_this.settings.drawyaxis == true && number == 1 && draw) { // draw legenditem markers for price
952
945
  if (!draw) return;
953
946
  m_ctx.beginPath();
954
947
  m_ctx.moveTo(m_chartspaces.chart.left, y + 0.5);
@@ -986,48 +979,49 @@ function Milli_Chart(settings) {
986
979
  m_ctx.fillStyle = m_yLegendCss.color;
987
980
  if (0 == calcHighLow()) {
988
981
  m_ctx.restore();
989
- () => {};
982
+ console.log('fail highlow');
990
983
  return;
991
984
  }
992
985
  _this.scaleinfoY.lineLength = m_chartspaces.chart.bottom - m_chartspaces.chart.top;
993
986
  _this.scaleinfoY2.lineLength = _this.scaleinfoY.lineLength;
994
-
987
+ //var numticks = (_this.scaleinfoY.lineLength / window.devicePixelRatio) / (getFontSize(m_yLegendCss) * _this.settings.yAxisSpacing);
995
988
  var numticks = _this.scaleinfoY.lineLength / (getFontSize(m_yLegendCss) * _this.settings.yAxisSpacing);
996
- if (numticks > 8) numticks = 8;
989
+ if (numticks > 8) numticks = 8; // limit to 8 items on Y legend ( this is not an absolut count, since we calculate nice legend numbers
997
990
  _this.scaleinfoY.tickSize = getTickValue(_this.scaleinfoY.lowValue, _this.scaleinfoY.highValue, numticks);
998
- _this.scaleinfoY.decimals = _this.scaleinfoY.tickSize.countDecimals();
991
+ _this.scaleinfoY.decimals = _this.scaleinfoY.tickSize.countDecimals(); // räkna på diffen mellan high low kanske?
999
992
  _this.scaleinfoY.decimals = _this.scaleinfoY.decimals > 4 ? 4 : _this.scaleinfoY.decimals;
1000
993
  _this.scaleinfoY.decimals = _this.scaleinfoY.decimals < 2 ? 2 : _this.scaleinfoY.decimals;
1001
994
  var label = formatNiceNumber(_this.scaleinfoY.highValue, _this.settings.thousandseparator, _this.settings.decimalseparator, _this.scaleinfoY.decimals);
1002
995
  if (_this.settings.drawyaxis) {
1003
996
  if (m_yLegendCss.float != 'right') {
1004
- m_chartspaces.chart.left = 10 + Math.round(m_ctx.measureText(label).width);
997
+ 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å?
1005
998
  m_chartspaces.lowerChart.left = m_chartspaces.chart.left;
1006
999
  } else {
1007
1000
  if (m_yLegendCss.textAlign == 'right') {
1008
- m_chartspaces.chart.right = m_canvas.width - (10 + Math.round(m_ctx.measureText(label).width));
1001
+ 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å?
1009
1002
  m_chartspaces.lowerChart.right = m_chartspaces.chart.right;
1010
1003
  }
1011
1004
  }
1012
1005
  }
1013
- if (_this.settings.drawy2axis) {
1014
-
1006
+ if (_this.settings.drawy2axis) { // calc space for y2
1007
+ //var numticks = _this.scaleinfoY2.lineLength / (getFontSize(m_yLegendCss) * _this.settings.yAxisSpacing);
1015
1008
  _this.scaleinfoY2.tickSize = getTickValue(_this.scaleinfoY2.lowValue, _this.scaleinfoY2.highValue, numticks);
1016
1009
 
1017
- _this.scaleinfoY2.decimals = _this.scaleinfoY2.tickSize.countDecimals();
1010
+ _this.scaleinfoY2.decimals = _this.scaleinfoY2.tickSize.countDecimals(); // räkna på diffen mellan high low kanske?
1018
1011
  _this.scaleinfoY2.decimals = _this.scaleinfoY2.decimals > 4 ? 4 : _this.scaleinfoY2.decimals;
1019
1012
  _this.scaleinfoY2.decimals = _this.scaleinfoY2.decimals < 0 ? 0 : _this.scaleinfoY2.decimals;
1020
1013
 
1021
1014
  var widestDiff = '-' + Math.max(Math.abs(_this.scaleinfoY2.highValue), Math.abs(_this.scaleinfoY2.lowValue));
1022
- label = formatNiceNumber(widestDiff, _this.settings.thousandseparator, _this.settings.decimalseparator, _this.scaleinfoY2.decimals) + ' %';
1015
+ if (_this.settings.priceIndicator == false) label = formatNiceNumber(widestDiff, _this.settings.thousandseparator, _this.settings.decimalseparator, _this.scaleinfoY2.decimals) + ' %';
1016
+ else label = formatNiceNumber(widestDiff, _this.settings.thousandseparator, _this.settings.decimalseparator, _this.scaleinfoY2.decimals < 2 ? 2 : _this.scaleinfoY2.decimals) + ' %'; // priceIndicator has 2 decimals
1023
1017
  if (m_y2LegendCss.float != 'right') {
1024
1018
  if (m_y2LegendCss.textAlign == 'left')
1025
- m_chartspaces.chart.left = 10 + Math.round(m_ctx.measureText(label).width);
1019
+ 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å?
1026
1020
  m_chartspaces.lowerChart.left = m_chartspaces.chart.left;
1027
1021
  } else {
1028
-
1022
+ // kolla setting om den skall vara "i diagrammet"
1029
1023
  if (m_y2LegendCss.textAlign == 'right')
1030
- m_chartspaces.chart.right = m_canvas.width - (10 + Math.round(m_ctx.measureText(label).width));
1024
+ 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å?
1031
1025
  m_chartspaces.lowerChart.right = m_chartspaces.chart.right;
1032
1026
  }
1033
1027
  }
@@ -1075,7 +1069,7 @@ function Milli_Chart(settings) {
1075
1069
  }
1076
1070
 
1077
1071
  function drawXAxisGridlines(p, newday) {
1078
-
1072
+ // draws the vertical grid or dots
1079
1073
  m_ctx.save();
1080
1074
  m_ctx.strokeStyle = m_gridVerticalCss.color;
1081
1075
  if (_this.settings.gridVerticalLines) {
@@ -1098,7 +1092,7 @@ function Milli_Chart(settings) {
1098
1092
  m_ctx.closePath();
1099
1093
  }
1100
1094
  } else
1101
- if (_this.settings.drawxaxis != 0) {
1095
+ if (_this.settings.drawxaxis != 0) { // if no grid but drawxaxis , add markers for date/time
1102
1096
  m_ctx.beginPath();
1103
1097
  m_ctx.moveTo(p.x + 0.5, p.y);
1104
1098
  m_ctx.lineTo(p.x + 0.5, p.y + 3);
@@ -1109,13 +1103,13 @@ function Milli_Chart(settings) {
1109
1103
  }
1110
1104
 
1111
1105
  function calcXScale(starttime, endtime) {
1112
-
1106
+ // vad är detta?
1113
1107
  _this.scaleinfoX.startDate = new Date(starttime);
1114
1108
  _this.scaleinfoX.endDate = new Date(endtime);
1115
1109
  _this.scaleinfoX.days = getNumberOfDays(starttime, endtime);
1116
1110
  _this.scaleinfoX.lineLength = m_chartspaces.chart.right - m_chartspaces.chart.left;
1117
- var datesize = new Date('2888-12-28');
1118
- _this.scaleinfoX.itemwidth = getStringWidth(m_ctx, formatDate(datesize, _this.settings.dateformat, _this)) * 2;
1111
+ var datesize = new Date('2888-12-28'); // bredaste datum jag kan komma på
1112
+ _this.scaleinfoX.itemwidth = getStringWidth(m_ctx, formatDate(datesize, _this.settings.dateformat, _this)) * 2; // kolla rätt format en 8a för varje tecken
1119
1113
 
1120
1114
  var maxLegendItems = _this.scaleinfoX.lineLength / (_this.scaleinfoX.itemwidth * 2);
1121
1115
 
@@ -1137,7 +1131,7 @@ function Milli_Chart(settings) {
1137
1131
  var tmp = 60;
1138
1132
  while (tmp < x) {
1139
1133
  tmp += 60;
1140
- if (x - tmp < 20) break;
1134
+ if (x - tmp < 20) break; // if less than 20 mins to next hour breakout
1141
1135
  }
1142
1136
  _this.scaleinfoX.ticksize = tmp * 60000;
1143
1137
  }
@@ -1145,22 +1139,22 @@ function Milli_Chart(settings) {
1145
1139
  }
1146
1140
 
1147
1141
  function getXPosition(timestamp) {
1148
- var offset = (timestamp.getTime() - _this.scaleinfoX.startDate.getTime()) / (86400000 * 7);
1142
+ var offset = (timestamp.getTime() - _this.scaleinfoX.startDate.getTime()) / (86400000 * 7); // veckor
1149
1143
  offset = offset * 86400000 * 2 / _this.scaleinfoX.timePerPixel;
1150
1144
  return Math.round(m_chartspaces.chart.left + ((timestamp.getTime() - _this.scaleinfoX.startDate.getTime()) / _this.scaleinfoX.timePerPixel) - offset);
1151
1145
  }
1152
1146
 
1153
1147
  function checkXLegendSides(x, text) {
1154
-
1148
+ // right
1155
1149
  if (_this.scaleinfoX.lineLength + m_chartspaces.chart.left < x + (m_ctx.measureText(text).width / 2)) return false;
1156
-
1150
+ // left
1157
1151
  if (m_chartspaces.chart.left > x - (m_ctx.measureText(text).width / 2)) return false;
1158
1152
  return true;
1159
1153
 
1160
1154
  }
1161
1155
 
1162
1156
  function drawXAxisYears(starttime, endtime) {
1163
- if (getNumberOfDays(starttime, endtime) < 250) return drawXAxisMonth(starttime, endtime);
1157
+ if (getNumberOfDays(starttime, endtime) < 250) return drawXAxisMonth(starttime, endtime); // exchange days
1164
1158
  m_ctx.save();
1165
1159
  m_ctx.font = m_xLegendCss.fontWeight + ' ' + m_xLegendCss.fontSize + ' ' + m_xLegendCss.fontFamily;
1166
1160
  m_ctx.strokeStyle = m_gridHorizontalCss.color;
@@ -1176,7 +1170,7 @@ function Milli_Chart(settings) {
1176
1170
  }
1177
1171
  m_ctx.strokeStyle = m_gridVerticalCss.color;
1178
1172
  var legendItems = [];
1179
-
1173
+ // draw Years
1180
1174
  var year = _this.scaleinfoX.startDate.getFullYear() + 1;
1181
1175
  var numItems = 0,
1182
1176
  x, draw, i, text;
@@ -1193,7 +1187,7 @@ function Milli_Chart(settings) {
1193
1187
  text = year;
1194
1188
  if (checkXLegendSides(x, text)) {
1195
1189
  if (_this.settings.yearLabelsPos == 'top') {
1196
- m_ctx.save();
1190
+ m_ctx.save(); // flip and write new years on top
1197
1191
  var fontMetrix = m_ctx.measureText(text);
1198
1192
  x = x + fontMetrix.actualBoundingBoxAscent + fontMetrix.actualBoundingBoxDescent + 2;
1199
1193
  var y = m_chartspaces.chart.top;
@@ -1210,14 +1204,14 @@ function Milli_Chart(settings) {
1210
1204
  }
1211
1205
  year++;
1212
1206
  }
1213
- if (numItems * m_ctx.measureText('8888').width / _this.scaleinfoX.lineLength > 0.3) numItems = 11;
1214
-
1215
- if (numItems < 10) {
1207
+ if (numItems * m_ctx.measureText('8888').width / _this.scaleinfoX.lineLength > 0.3) numItems = 11; // keep it clean
1208
+ // draw half year
1209
+ if (numItems < 10) { // max 10 items här för att skriva halvår
1216
1210
  year = new Date(_this.scaleinfoX.startDate.getFullYear() + '-07-01T00:00:00Z');
1217
1211
  if (year.getTime() < _this.scaleinfoX.startDate.getTime())
1218
1212
  year = new Date(_this.scaleinfoX.startDate.getFullYear() + 1 + '-07-01T00:00:00Z');
1219
1213
  while (year < _this.scaleinfoX.endDate) {
1220
- x = getXPosition(new Date(year.getFullYear() + '-07-01T00:00:00Z'));
1214
+ x = getXPosition(new Date(year.getFullYear() + '-07-01T00:00:00Z')); // 7
1221
1215
  draw = true;
1222
1216
  for (i = 0; i < legendItems.length; i++) {
1223
1217
  if (Math.abs(legendItems[i].x - x) < getMaxDateWidth()) {
@@ -1236,13 +1230,13 @@ function Milli_Chart(settings) {
1236
1230
  year = new Date((year.getFullYear() + 1) + '-07-01T00:00:00Z');
1237
1231
  }
1238
1232
  }
1239
-
1240
- if (numItems * m_ctx.measureText('8888').width / _this.scaleinfoX.lineLength > 0.3) numItems = 11;
1241
- if (numItems < 10) {
1233
+ // draw Quarter
1234
+ if (numItems * m_ctx.measureText('8888').width / _this.scaleinfoX.lineLength > 0.3) numItems = 11; // keep it clean
1235
+ if (numItems < 10) { // max 10 items här för att skriva kvartal
1242
1236
  year = new Date(_this.scaleinfoX.startDate.getFullYear() + '-04-01T00:00:00Z');
1243
1237
  if (year.getTime() < _this.scaleinfoX.startDate.getTime())
1244
1238
  year = new Date(_this.scaleinfoX.startDate.getFullYear() + 1 + '-04-01T00:00:00Z');
1245
- var dontPrint = false;
1239
+ var dontPrint = false; // if no space for first quarter dont print second either
1246
1240
  while (year < _this.scaleinfoX.endDate) {
1247
1241
  x = getXPosition(new Date(year.getFullYear() + '-04-01T00:00:00Z'));
1248
1242
  draw = true;
@@ -1263,7 +1257,7 @@ function Milli_Chart(settings) {
1263
1257
  legendItems.push({ 'text': text, timestamp: new Date(year + '-04-01T00:00:00Z'), 'x': x });
1264
1258
  year = new Date((year.getFullYear() + 1) + '-04-01T00:00:00Z');
1265
1259
  }
1266
-
1260
+ // Draw Quarter 2
1267
1261
  if (dontPrint == false) {
1268
1262
  year = new Date(_this.scaleinfoX.startDate.getFullYear() + '-10-01T00:00:00Z');
1269
1263
  if (year.getTime() < _this.scaleinfoX.startDate.getTime())
@@ -1300,7 +1294,7 @@ function Milli_Chart(settings) {
1300
1294
  m_ctx.strokeStyle = m_gridHorizontalCss.color;
1301
1295
  m_ctx.fillStyle = m_xLegendCss.color;
1302
1296
  calcXScale(starttime, endtime);
1303
- if (_this.settings.drawxaxis != 0) {
1297
+ if (_this.settings.drawxaxis != 0) { // draw line
1304
1298
  m_ctx.beginPath();
1305
1299
  m_ctx.moveTo(m_chartspaces.chart.left, m_chartspaces.chart.height - getScaledSetting(m_chartCss.marginBottom) + 0.5);
1306
1300
  m_ctx.lineTo(m_chartspaces.chart.right, m_chartspaces.chart.height - getScaledSetting(m_chartCss.marginBottom) + 0.5);
@@ -1315,14 +1309,14 @@ function Milli_Chart(settings) {
1315
1309
  var draw = true;
1316
1310
  var offset = 0;
1317
1311
  var count = 0;
1318
- while (currentDate.getTime() < _this.scaleinfoX.endTimeStamp) {
1312
+ while (currentDate.getTime() < _this.scaleinfoX.endTimeStamp) { // oklart om det skall vara så här 2021-06-01
1319
1313
  draw = true;
1320
- while (currentDate.getDay() == 0 || currentDate.getDay() == 6) {
1314
+ while (currentDate.getDay() == 0 || currentDate.getDay() == 6) { // move past weekends , maybe skip this if date is available in data
1321
1315
  currentDate = new Date(currentDate.getTime() + 86400000);
1322
1316
  offset += 86400000 / _this.scaleinfoX.timePerPixel;
1323
1317
  }
1324
1318
  x = Math.round(m_chartspaces.chart.left + ((currentDate.getTime() - _this.scaleinfoX.startDate.getTime()) / _this.scaleinfoX.timePerPixel) - offset);
1325
- if (lastx == 0 && m_chartspaces.chart.left > (x - (getMaxDateWidth() / 2))) {
1319
+ if (lastx == 0 && m_chartspaces.chart.left > (x - (getMaxDateWidth() / 2))) { // do not print left of y legend
1326
1320
  currentDate = new Date(currentDate.getTime() + 86400000);
1327
1321
  continue;
1328
1322
  }
@@ -1340,7 +1334,7 @@ function Milli_Chart(settings) {
1340
1334
  }
1341
1335
  currentDate = new Date(currentDate.getTime() + 86400000);
1342
1336
  }
1343
-
1337
+ // vad är detta?
1344
1338
  if (typeof m_chartCss.boxShadow !== 'undefined' && typeof m_chartCss.boxShadow.rightWidth !== 'undefined') {
1345
1339
  if (m_chartCss.boxShadow.rightWidth == 0) drawXAxisGridlines({ 'x': x, y: m_chartspaces.chart.bottom }, false);
1346
1340
  } else {
@@ -1352,9 +1346,9 @@ function Milli_Chart(settings) {
1352
1346
  function calcXScaleTick(starttime, endtime) {
1353
1347
  _this.scaleinfoX.startDate = new Date(starttime);
1354
1348
  _this.scaleinfoX.endDate = new Date(endtime);
1355
- _this.scaleinfoX.days = getNumberOfDays(starttime, endtime);
1356
- _this.scaleinfoX.lineLength = m_chartspaces.chart.right - m_chartspaces.chart.left;
1357
- _this.scaleinfoX.itemwidth = getStringWidth(m_ctx, '88:88') * 2;
1349
+ _this.scaleinfoX.days = getNumberOfDays(starttime, endtime); // kan vi nog skita i
1350
+ _this.scaleinfoX.lineLength = m_chartspaces.chart.right - m_chartspaces.chart.left;
1351
+ _this.scaleinfoX.itemwidth = getStringWidth(m_ctx, '88:88') * 2; // kolla rätt format en 8a för varje tecken
1358
1352
  var maxLegendItems = Math.floor(_this.scaleinfoX.lineLength / (_this.scaleinfoX.itemwidth * 2));
1359
1353
 
1360
1354
  if (_this.scaleinfoY.type != 'history') {
@@ -1381,38 +1375,41 @@ function Milli_Chart(settings) {
1381
1375
  for (i = 0; i < arr.length; i++) {
1382
1376
  pixelsperday[i] = arr[i] * timePerPixel;
1383
1377
  }
1384
- var x = totalmilli / maxLegendItems / 60000;
1378
+ //var x = totalmilli / maxLegendItems / 60000;
1385
1379
  var numticks = maxLegendItems;
1386
1380
 
1387
1381
  _this.scaleinfoX.milliPerDay = new Date('2019-01-01T' + _this.instruments[0].marketclose + 'Z') - new Date('2019-01-01T' + _this.instruments[0].marketopen + 'Z');
1388
1382
  _this.scaleinfoX.timePerPixel = timePerPixel;
1389
1383
 
1384
+ //_this.scaleinfoX.timePerPixel = (_this.scaleinfoX.milliPerDay * _this.scaleinfoX.days) / _this.scaleinfoX.lineLength;
1385
+
1386
+
1390
1387
  _this.scaleinfoX.tickPixelsPerDay = pixelsperday;
1391
1388
 
1392
1389
  var factor = 60;
1393
1390
  if (numticks < 1)
1394
- _this.scaleinfoX.ticksize = 86400000;
1391
+ _this.scaleinfoX.ticksize = 86400000; // öhh?
1395
1392
  else {
1396
1393
  if (numticks < 2) numticks = 2;
1397
- x = _this.scaleinfoX.milliPerDay / numticks / 60000;
1398
- if (totalmilli > 4 * 3600000) factor = 60;
1394
+ // x = _this.scaleinfoX.milliPerDay / numticks / 60000;
1395
+ if (totalmilli > 4 * 3600000) factor = 60; // 4 timmar
1399
1396
  else
1400
- if (totalmilli > 2 * 3600000) factor = 30;
1397
+ if (totalmilli > 2 * 3600000) factor = 30; // 2 timmar
1401
1398
  else
1402
- if (totalmilli > 3600000) factor = 20;
1399
+ if (totalmilli > 3600000) factor = 20; // 1 timma
1403
1400
  else
1404
- if (totalmilli > 3600000 / 2) factor = 10;
1401
+ if (totalmilli > 3600000 / 2) factor = 10; // 30 min
1405
1402
  else
1406
- if (totalmilli > 3600000 / 4) factor = 5;
1403
+ if (totalmilli > 3600000 / 4) factor = 5; // 15 min
1407
1404
  else factor = 1;
1408
- _this.scaleinfoX.ticksize = factor * 60000;
1405
+ _this.scaleinfoX.ticksize = factor * 60000; // time to add to next legenditem
1409
1406
  }
1410
1407
  return;
1411
1408
  }
1412
1409
  }
1413
1410
 
1414
1411
  function formatChartTime(value, format) {
1415
-
1412
+ // internal
1416
1413
  if (typeof value !== 'string') return "";
1417
1414
  var datetime = new Date();
1418
1415
  datetime.setHours(parseInt(value));
@@ -1471,7 +1468,7 @@ function Milli_Chart(settings) {
1471
1468
  m_ctx.fillStyle = m_xLegendCss.color;
1472
1469
  m_ctx.textAlign = "left";
1473
1470
  calcXScaleTick(starttime, endtime);
1474
- if (_this.settings.drawxaxis != 0) {
1471
+ if (_this.settings.drawxaxis != 0) { // draw line for legend
1475
1472
  m_ctx.beginPath();
1476
1473
  m_ctx.moveTo(m_chartspaces.chart.left, m_chartspaces.chart.bottom + 0.5);
1477
1474
  m_ctx.lineTo(m_chartspaces.chart.right, m_chartspaces.chart.bottom + 0.5);
@@ -1488,20 +1485,19 @@ function Milli_Chart(settings) {
1488
1485
  var legendItems = [];
1489
1486
  var openhour = new Date(new Date(currentDate.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketopen + 'Z')).getTime() % 86400000;
1490
1487
  var closehour = new Date(new Date(currentDate.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketclose + 'Z')).getTime() % 86400000;
1491
-
1488
+ // add daysstarts
1492
1489
  var middleOfDay = new Date(currentDate.getTime() - (currentDate.getTime() % 86400000) + ((openhour + closehour) / 2));
1493
1490
  if (_this.settings.intradayDatePos.x == 'left' && (_this.settings.intradayDatePos.y == 'scale' || _this.settings.intradayDatePos.y == 'top')) {
1494
1491
  middleOfDay = new Date(currentDate.getTime());
1495
1492
  }
1496
- if (currentDate.getTime() % 3600000 != 0)
1497
- currentDate = new Date(currentDate.getTime() - currentDate.getTime() % 3600000 + 3600000);
1498
-
1493
+ if (currentDate.getTime() % 3600000 != 0) // if not full hour, move up to next full hour
1494
+ currentDate = new Date(currentDate.getTime() - currentDate.getTime() % 3600000 + 3600000); // START om full hour (if modulo == 0 then + 3600000 kanske)
1499
1495
  var firstDate = new Date(currentDate);
1500
1496
  var days = calcTimeSpanInDays(starttime, endtime);
1501
1497
  if (m_zoom.mouseup.timestamp == null || (m_zoom.mouseup.timestamp != null && days > 1)) {
1502
1498
  while (currentDate.getTime() < _this.scaleinfoX.endTimeStamp) {
1503
1499
  draw = true;
1504
- while (currentDate.getDay() == 0 || currentDate.getDay() == 6) {
1500
+ while (currentDate.getDay() == 0 || currentDate.getDay() == 6) { // move past weekends , maybe skip this if date is available in data
1505
1501
  currentDate = new Date(currentDate.getTime() + 86400000);
1506
1502
  if (_this.settings.intradayDatePos.x == 'left' && (_this.settings.intradayDatePos.y == 'scale' || _this.settings.intradayDatePos.y == 'top')) {
1507
1503
  middleOfDay = new Date(currentDate.getTime());
@@ -1514,20 +1510,20 @@ function Milli_Chart(settings) {
1514
1510
  if (lastx != 0 && lastx + (getMaxTimeWidth() / 2) > (x - getMaxTimeWidth())) {
1515
1511
  draw = false;
1516
1512
  } else
1517
- if (m_zoom.mouseup.timestamp != null && firstDate.getTime() === currentDate.getTime())
1513
+ if (m_zoom.mouseup.timestamp != null && firstDate.getTime() === currentDate.getTime()) {
1518
1514
  draw = false;
1515
+ }
1519
1516
  if (draw) {
1520
1517
  lastx = x + 0.5;
1521
1518
  var text = formatChartTime(currentDate.toTimeString().substring(0, 8), _this.settings.timeformat);
1522
1519
  var date = formatDate(currentDate, _this.settings.intradayDatePos.dateformat, _this);
1523
- if (_this.scaleinfoX.lineLength + m_chartspaces.chart.left > x - getMaxTimeWidth()) {
1520
+ if (_this.scaleinfoX.lineLength + m_chartspaces.chart.left > x - getMaxTimeWidth()) { // not to far right?
1524
1521
  if (_this.settings.intradayDatePos.y == 'scale' && _this.settings.chartlen != '0d' && _this.settings.chartlen != '1d') {
1525
-
1522
+ // draw date on under time, todo fix setting name
1526
1523
  m_ctx.fillText(date, middleX - (m_ctx.measureText(date).width / 2), m_chartspaces.chart.bottom + getScaledSetting(m_xLegendCss.paddingTop));
1527
1524
  legendItems.push({ x: middleX, type: 0, text: date, width: m_ctx.measureText(date) });
1528
1525
  } else if (_this.settings.intradayDatePos.y == 'bottom' && _this.settings.chartlen != '0d' && _this.settings.chartlen != '1d') {
1529
1526
  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);
1530
-
1531
1527
  m_ctx.fillText(text, x - (m_ctx.measureText(text).width / 2), m_chartspaces.chart.bottom + getScaledSetting(m_xLegendCss.paddingTop));
1532
1528
  legendItems.push({ x: x, type: 0, text: text });
1533
1529
  } else {
@@ -1547,7 +1543,7 @@ function Milli_Chart(settings) {
1547
1543
  if (_this.settings.intradayDatePos.x == 'center') {
1548
1544
  m_ctx.fillText(date, middleX - (m_ctx.measureText(date).width / 2), getScaledSetting(m_chartCss.marginTop));
1549
1545
  } else {
1550
-
1546
+ //m_ctx.fillText(date, x - (m_ctx.measureText(date).width / 2), getScaledSetting(m_chartCss.marginTop));
1551
1547
  m_ctx.fillText(date, middleX + 1, getScaledSetting(m_chartCss.marginTop));
1552
1548
  }
1553
1549
  }
@@ -1555,17 +1551,17 @@ function Milli_Chart(settings) {
1555
1551
  }
1556
1552
  }
1557
1553
  }
1558
- if (x != m_chartspaces.chart.left + 0.5) {
1554
+ if (x != m_chartspaces.chart.left + 0.5) { // do not draw the first line, it is already drawn
1559
1555
  if (_this.settings.intradayDatePos.y != 'bottom') {
1560
1556
  if (openhour == currentDate.getTime() % 86400000) {
1561
- drawXAxisGridlines({ 'x': x, y: m_chartspaces.chart.bottom }, true);
1557
+ drawXAxisGridlines({ 'x': x, y: m_chartspaces.chart.bottom }, true); // dash?
1562
1558
  } else {
1563
- drawXAxisGridlines({ 'x': x, y: m_chartspaces.chart.bottom }, false);
1559
+ drawXAxisGridlines({ 'x': x, y: m_chartspaces.chart.bottom }, false); // dash?
1564
1560
  }
1565
1561
  }
1566
1562
  }
1567
1563
  }
1568
-
1564
+ // Move to next day and set starting hour correct if we have open at half hour
1569
1565
  currentDate = new Date(currentDate.getTime() + 86400000);
1570
1566
  currentDate = new Date(currentDate.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketopen + 'Z');
1571
1567
  middleOfDay = new Date(currentDate.getTime() - (currentDate.getTime() % 86400000) + ((openhour + closehour) / 2));
@@ -1573,23 +1569,23 @@ function Milli_Chart(settings) {
1573
1569
  middleOfDay = new Date(currentDate);
1574
1570
  }
1575
1571
 
1576
- if (currentDate.getTime() % 3600000 != 0)
1577
- currentDate = new Date(currentDate.getTime() - currentDate.getTime() % 3600000 + 3600000);
1578
-
1572
+ if (currentDate.getTime() % 3600000 != 0) // if not full hour, move up to next full hour
1573
+ currentDate = new Date(currentDate.getTime() - currentDate.getTime() % 3600000 + 3600000); // START om full hour (if modulo == 0 then + 3600000 kanske)
1574
+ //}
1579
1575
  offset += (86400000 - _this.scaleinfoX.milliPerDay) / _this.scaleinfoX.timePerPixel;
1580
1576
  }
1581
1577
  }
1582
-
1578
+ // add timestamps
1583
1579
  currentDate = new Date(starttime);
1584
- if (currentDate.getTime() % 3600000 != 0)
1585
- currentDate = new Date(currentDate.getTime() - currentDate.getTime() % 3600000 + 3600000);
1580
+ if (currentDate.getTime() % 3600000 != 0) // if not full hour, move up to next full hour
1581
+ currentDate = new Date(currentDate.getTime() - currentDate.getTime() % 3600000 + 3600000); // START om full hour (if modulo == 0 then + 3600000 kanske)
1586
1582
 
1587
1583
  var maxHourLegends;
1588
1584
  if (legendItems.length == 0)
1589
- maxHourLegends = Math.floor((_this.scaleinfoX.lineLength - m_chartspaces.chart.left - getMaxTimeWidth()) / (getMaxTimeWidth() * 3));
1585
+ maxHourLegends = Math.floor((_this.scaleinfoX.lineLength - m_chartspaces.chart.left - getMaxTimeWidth()) / (getMaxTimeWidth() * 3)); // varför tar vi bort margin???
1590
1586
  else if (legendItems.length == 1) {
1591
1587
  if (m_zoom.mouseup.timestamp && days == 2) {
1592
-
1588
+ // ta den största delen av linjen och mät på
1593
1589
  if (_this.scaleinfoX.lineLength / 2 < legendItems[0].x + m_chartspaces.chart.left)
1594
1590
  maxHourLegends = Math.floor((_this.scaleinfoX.lineLength - (_this.scaleinfoX.lineLength - legendItems[0].x) - getMaxTimeWidth()) / (getMaxTimeWidth() * 3));
1595
1591
  else
@@ -1597,15 +1593,15 @@ function Milli_Chart(settings) {
1597
1593
  } else
1598
1594
  maxHourLegends = Math.floor((_this.scaleinfoX.lineLength - legendItems[0].x - getMaxTimeWidth()) / (getMaxTimeWidth() * 3));
1599
1595
  } else {
1600
- maxHourLegends = Math.floor((legendItems[legendItems.length - 1].x - legendItems[legendItems.length - 2].x - getMaxTimeWidth()) / (getMaxTimeWidth() * 3));
1596
+ maxHourLegends = Math.floor((legendItems[legendItems.length - 1].x - legendItems[legendItems.length - 2].x - getMaxTimeWidth()) / (getMaxTimeWidth() * 3)); // calculate with the last days length
1601
1597
  }
1602
1598
 
1603
- var tickSize;
1599
+ var tickSize; // per day
1604
1600
  if (days == 1) {
1605
-
1601
+ // use start and endtime as ticksize
1606
1602
  tickSize = new Date(endtime - starttime);
1607
- } else if (m_zoom.mouseup.timestamp && days == 2) {
1608
-
1603
+ } else if (m_zoom.mouseup.timestamp && days == 2) { // zoom with 2 days
1604
+ // use the day with most time as tickSize
1609
1605
  var tmpDate = new Date(starttime);
1610
1606
  tickSize = new Date(new Date(tmpDate.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketclose + 'Z') - new Date(starttime)).getTime();
1611
1607
  var firstDay = tickSize;
@@ -1614,13 +1610,13 @@ function Milli_Chart(settings) {
1614
1610
  tickSize += new Date(endtime - new Date(tmpDate.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketopen + 'Z').getTime()).getTime();
1615
1611
  tickSize = new Date(Math.max(firstDay, secondDay));
1616
1612
  } else {
1617
-
1613
+ // use full day as tickSize
1618
1614
  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'));
1619
1615
  }
1620
1616
  var interval;
1621
1617
  var modularvalue = 3600000;
1622
1618
 
1623
-
1619
+ // calc the ticksize to add to time(interval) when drawing and the modulu value
1624
1620
  if (tickSize.getTime() < 1800000) {
1625
1621
  tickSize = tickSize.getTime() / 60000;
1626
1622
  interval = Math.floor(tickSize / (maxHourLegends + 1)) * 60000;
@@ -1639,14 +1635,14 @@ function Milli_Chart(settings) {
1639
1635
  interval = Math.floor(tickSize / (maxHourLegends + 1)) * 3600000;
1640
1636
  }
1641
1637
  if (interval == 0) {
1642
-
1638
+ // default 1h
1643
1639
  interval = 3600000;
1644
1640
  modularvalue = 3600000;
1645
1641
  }
1646
1642
  if (interval % 60000 != 0) {
1647
- interval = (interval - interval % 60000) + 60000;
1643
+ interval = (interval - interval % 60000) + 60000; // remove sekunder
1648
1644
  }
1649
-
1645
+ // print other times
1650
1646
  offset = 0;
1651
1647
  lastx = 0;
1652
1648
  var closeTime = new Date(currentDate.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketclose + 'Z');
@@ -1655,41 +1651,41 @@ function Milli_Chart(settings) {
1655
1651
 
1656
1652
  var workDate = new Date(currentDate);
1657
1653
  currentDate = new Date(starttime);
1658
- if (currentDate.getTime() % modularvalue != 0)
1659
- currentDate = new Date(currentDate.getTime() - currentDate.getTime() % modularvalue + modularvalue);
1654
+ if (currentDate.getTime() % modularvalue != 0) // if not full hour, move up to next full hour
1655
+ currentDate = new Date(currentDate.getTime() - currentDate.getTime() % modularvalue + modularvalue); // START om full hour (if modulo == 0 then + 3600000 kanske)
1660
1656
 
1661
1657
  var count = 0;
1662
1658
  while (currentDate.getTime() <= _this.scaleinfoX.endTimeStamp) {
1663
1659
  dayLightChange = (closeTime.getTimezoneOffset() - new Date().getTimezoneOffset()) * 60000;
1664
1660
  if (count++ > 100) {
1665
- break;
1661
+ break; // just make sure we dont do an infinity loop
1666
1662
 
1667
1663
  }
1668
1664
  draw = true;
1669
- while (currentDate.getDay() == 0 || currentDate.getDay() == 6) {
1670
-
1671
- currentDate = new Date(currentDate.getTime() + 86400000);
1672
- closeTime = new Date(currentDate.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketclose + 'Z');
1673
- if (currentDate.getTime() % modularvalue != 0)
1674
- currentDate = new Date(currentDate.getTime() - currentDate.getTime() % modularvalue + modularvalue);
1675
- workDate = new Date(workDate.getTime() + 86400000);
1676
- offset += 86400000 / _this.scaleinfoX.timePerPixel;
1677
- }
1665
+ // bytt plats if och while nedan 2022-11-07
1678
1666
  if (currentDate.getTime() > closeTime.getTime()) {
1679
-
1667
+ // draw DayEnd(start) dash line
1680
1668
  var dayStart = new Date(workDate.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketclose + 'Z');
1681
1669
  x = Math.round(m_chartspaces.chart.left + ((dayStart.getTime() - _this.scaleinfoX.startDate.getTime()) / _this.scaleinfoX.timePerPixel) - offset);
1682
- drawXAxisGridlines({ 'x': x, y: m_chartspaces.chart.bottom }, true);
1670
+ drawXAxisGridlines({ 'x': x, y: m_chartspaces.chart.bottom }, true); // dash?
1683
1671
 
1684
1672
  closeTime = new Date(closeTime.getTime() + 86400000);
1685
1673
  workDate = new Date(workDate.getTime() + 86400000);
1686
1674
  currentDate = new Date(workDate.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketopen + 'Z');
1687
1675
 
1688
- if (currentDate.getTime() % modularvalue != 0)
1689
- currentDate = new Date(currentDate.getTime() - currentDate.getTime() % modularvalue + modularvalue);
1676
+ if (currentDate.getTime() % modularvalue != 0) // if not full hour, move up to next full hour
1677
+ currentDate = new Date(currentDate.getTime() - currentDate.getTime() % modularvalue + modularvalue); // START om full hour (if modulo == 0 then + 3600000 kanske)
1690
1678
  offset += (86400000 - _this.scaleinfoX.milliPerDay) / _this.scaleinfoX.timePerPixel;
1691
1679
  continue;
1692
1680
  }
1681
+ while (currentDate.getDay() == 0 || currentDate.getDay() == 6) { // move past weekends , maybe skip this if date is available in data
1682
+ currentDate = new Date(currentDate.getTime() + 86400000);
1683
+ closeTime = new Date(currentDate.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketclose + 'Z');
1684
+ if (currentDate.getTime() % modularvalue != 0) // if not full hour, move up to next full hour
1685
+ currentDate = new Date(currentDate.getTime() - currentDate.getTime() % modularvalue + modularvalue); // START om full hour (if modulo == 0 then + 3600000 kanske)
1686
+ workDate = new Date(workDate.getTime() + 86400000);
1687
+ offset += 86400000 / _this.scaleinfoX.timePerPixel;
1688
+ }
1693
1689
  x = Math.round(m_chartspaces.chart.left + ((currentDate.getTime() - _this.scaleinfoX.startDate.getTime()) / _this.scaleinfoX.timePerPixel) - offset);
1694
1690
  for (var i = 0; i < legendItems.length; i++) {
1695
1691
  if (x < legendItems[i].x && x + (getMaxTimeWidth() / 2) > (legendItems[i].x - getMaxTimeWidth())) {
@@ -1706,23 +1702,23 @@ function Milli_Chart(settings) {
1706
1702
  }
1707
1703
  }
1708
1704
  if (lastx + (getMaxTimeWidth() / 2) > (x - getMaxTimeWidth())) {
1709
-
1705
+ //draw = false;
1710
1706
  }
1711
1707
  if (draw) {
1712
1708
  lastx = x;
1713
-
1714
- if (_this.scaleinfoX.lineLength + m_chartspaces.chart.left > x - getMaxTimeWidth()) {
1709
+ // if day change and setting print on top as well
1710
+ if (_this.scaleinfoX.lineLength + m_chartspaces.chart.left > x - getMaxTimeWidth()) { // not to far right?
1715
1711
  var label = formatChartTime(currentDate.toTimeString().substring(0, 8), _this.settings.timeformat);
1716
1712
  x = Math.round(x);
1717
1713
  m_ctx.fillText(label, x - (m_ctx.measureText(label).width / 2), m_chartspaces.chart.bottom + getScaledSetting(m_xLegendCss.paddingTop));
1718
- legendItems.push({ x: x, type: 0 });
1714
+ legendItems.push({ x: x, type: 0, text: label });
1719
1715
  }
1720
1716
  drawXAxisGridlines({ 'x': x, y: m_chartspaces.chart.bottom }, false);
1721
1717
  }
1722
1718
  currentDate = new Date(currentDate.getTime() + interval);
1723
1719
  }
1724
1720
 
1725
-
1721
+ // vad är detta?
1726
1722
  if (typeof m_chartCss.boxShadow !== 'undefined' && typeof m_chartCss.boxShadow.rightWidth !== 'undefined') {
1727
1723
  if (m_chartCss.boxShadow.rightWidth == 0) drawXAxisGridlines({ 'x': x, y: m_chartspaces.chart.bottom }, false);
1728
1724
 
@@ -1756,11 +1752,15 @@ function Milli_Chart(settings) {
1756
1752
  var oldValue = undefined;
1757
1753
  var newValue = undefined;
1758
1754
  var offsetWidth = 0;
1759
- if (_this.settings.drawyaxis && m_yLegendCss.float == 'right') {
1755
+ if (_this.instruments[0].pricetype == 'yield') {
1756
+ newValue = formatNiceNumber(obj.instruments[0].price, _this.settings.thousandseparator, _this.settings.decimalseparator, _this.settings.num_decimals, false);
1757
+ if (m_y2LegendCss.textAlign == 'left') offsetWidth = 1;
1758
+ } else if (_this.settings.drawyaxis && m_yLegendCss.float == 'right') {
1760
1759
  newValue = formatNiceNumber(obj.instruments[0].price, _this.settings.thousandseparator, _this.settings.decimalseparator, _this.settings.num_decimals, false);
1761
1760
  if (m_yLegendCss.textAlign == 'left') offsetWidth = 1;
1762
1761
  } else if (_this.settings.drawy2axis && m_y2LegendCss.float == 'right') {
1763
- newValue = formatNiceNumber(obj.instruments[0].diff, _this.settings.thousandseparator, _this.settings.decimalseparator, 2, false) + '%';
1762
+ if (obj.instruments[0].diff > 0) newValue = '+' + formatNiceNumber(obj.instruments[0].diff, _this.settings.thousandseparator, _this.settings.decimalseparator, 2, false) + '%';
1763
+ else newValue = formatNiceNumber(obj.instruments[0].diff, _this.settings.thousandseparator, _this.settings.decimalseparator, 2, false) + '%';
1764
1764
  if (m_y2LegendCss.textAlign == 'left') offsetWidth = 1;
1765
1765
  } else return;
1766
1766
  if (typeof m_priceIndicator !== 'undefined') {
@@ -1771,7 +1771,7 @@ function Milli_Chart(settings) {
1771
1771
  m_priceIndicator.setAttribute('class', 'millistream-chart-price-indicator');
1772
1772
  }
1773
1773
  m_priceIndicator.innerHTML = newValue;
1774
- m_priceIndicator.style.left = (m_chartspaces.chart.right / window.devicePixelRatio) - (offsetWidth == 0 ? -1 : m_priceIndicator.offsetWidth) + 'px';
1774
+ m_priceIndicator.style.left = (m_chartspaces.chart.right / window.devicePixelRatio) - (offsetWidth == 0 ? -1 : m_priceIndicator.offsetWidth) + 'px'; // offsetWidth with devicePixelRatio???
1775
1775
  m_priceIndicator.style.top = obj.instruments[0].y - (m_priceIndicator.offsetHeight / 2) + 'px';
1776
1776
  newValue = MillistreamWidgetApi_getElementNumber(_this, m_priceIndicator);
1777
1777
  MillistreamWidgetApi_flashElement(_this, m_priceIndicator, newValue, oldValue);
@@ -1850,6 +1850,8 @@ function Milli_Chart(settings) {
1850
1850
  var instr = {};
1851
1851
  instr.chartType = _this.scaleinfoY.type;
1852
1852
  instr.name = _this.instruments[x].name;
1853
+ instr.instrumenttype = _this.instruments[x].instrumenttype;
1854
+ instr.pricetype = _this.instruments[x].pricetype;
1853
1855
  if (typeof _this.instruments[x].symbol !== 'undefined')
1854
1856
  instr.symbol = _this.instruments[x].symbol;
1855
1857
 
@@ -1858,13 +1860,13 @@ function Milli_Chart(settings) {
1858
1860
  instr.data.price = formatNiceNumber(instr.data.price, _this.settings.thousandseparator, _this.settings.decimalseparator, _this.settings.num_decimals, false);
1859
1861
 
1860
1862
  if (typeof _this.instruments[x].toolTip === 'undefined') {
1861
-
1863
+ // add textdiv
1862
1864
  _this.instruments[x].toolTip = document.createElement('div');
1863
1865
  _this.instruments[x].toolTip.style.display = _this.settings.tooltip.display;
1864
- _this.instruments[x].toolTip.setAttribute('class', 'millistream-chart-tooltip');
1866
+ _this.instruments[x].toolTip.setAttribute('class', 'millistream-chart-tooltip'); // set class so we can measure it might change below depending on position
1865
1867
  _this.instruments[x].toolTip.position = 'absolute';
1866
1868
  m_canvas.parentNode.appendChild(_this.instruments[x].toolTip);
1867
-
1869
+ // add pointer div
1868
1870
  _this.instruments[x].toolTipPointer = document.createElement('div');
1869
1871
  m_canvas.parentNode.appendChild(_this.instruments[x].toolTipPointer);
1870
1872
  _this.instruments[x].toolTipPointer.setAttribute('class', 'millistream-chart-pointer');
@@ -1879,16 +1881,16 @@ function Milli_Chart(settings) {
1879
1881
  var pointerWidth = _this.instruments[x].toolTipPointer.offsetWidth + parseInt(pointerStyle.marginLeft) + parseInt(pointerStyle.marginRight);
1880
1882
  var pointerHeight = _this.instruments[x].toolTipPointer.offsetHeight + parseInt(pointerStyle.marginTop) + parseInt(pointerStyle.marginBottom);
1881
1883
  var posy = obj.instruments[x].y - (_this.instruments[x].toolTip.offsetHeight / 2);
1882
- if (m_dataPoints.arr[i] + (_this.instruments[x].toolTip.offsetWidth * 1.5) > m_canvas.width) {
1883
-
1884
+ 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
1885
+ // draw the hover to the left
1884
1886
  _this.instruments[x].toolTip.style.left = (obj.instruments[x].x - _this.instruments[x].toolTip.offsetWidth - (pointerWidth / 2)) + 1 + 'px';
1885
1887
  } else {
1886
-
1888
+ // draw hover to the right
1887
1889
  _this.instruments[x].toolTip.style.left = (obj.instruments[x].x + (pointerWidth / 2)) + 'px';
1888
1890
  }
1889
1891
  _this.instruments[x].toolTip.style.top = posy + 'px';
1890
1892
  toolArray.push({ top: (obj.instruments[x].y - (pointerHeight / 2)), instrument: x });
1891
- _this.instruments[x].toolTipPointer.style.left = (obj.instruments[x].x - (pointerWidth / 2)) + 1 + 'px';
1893
+ _this.instruments[x].toolTipPointer.style.left = (obj.instruments[x].x - (pointerWidth / 2)) + 1 + 'px'; // hmm plus 1??
1892
1894
  _this.instruments[x].toolTipPointer.style.top = (obj.instruments[x].y - (pointerHeight / 2)) + 'px';
1893
1895
  if (posy > highy) highy = posy;
1894
1896
  if (posy < lowy) lowy = posy;
@@ -1932,13 +1934,12 @@ function Milli_Chart(settings) {
1932
1934
  enddate: new Date(_this.scaleinfoX.endTimeStamp).toISOString().substring(0, 10)
1933
1935
  };
1934
1936
 
1935
- }
1937
+ };
1936
1938
 
1937
1939
  _this.setDateInterval = function(startdate, enddate) {
1938
1940
  startdate = startdate.replaceAll('\/', '-');
1939
1941
  enddate = enddate.replaceAll('\/', '-');
1940
1942
  m_zoom.mousedown.timestamp = findFirstWeekDay(new Date(startdate + 'T00:00:00Z'));
1941
- () => {};
1942
1943
 
1943
1944
  m_zoom.mouseup.timestamp = new Date(enddate + 'T00:00:00Z');
1944
1945
 
@@ -1947,7 +1948,7 @@ function Milli_Chart(settings) {
1947
1948
  m_zoom.mouseup.timestamp = new Date(m_zoom.mouseup.timestamp + 'T00:00:00Z');
1948
1949
  }
1949
1950
  _this.settings.chartlen = 'max';
1950
- _this.scaleinfoY.type == 'history';
1951
+ _this.scaleinfoY.type = 'history';
1951
1952
  _this.drawChart();
1952
1953
  };
1953
1954
 
@@ -1982,7 +1983,7 @@ function Milli_Chart(settings) {
1982
1983
  }
1983
1984
  }
1984
1985
  }
1985
- if (_this.scaleinfoY.type == 'trades' && count > 0 && _this.instruments[0].closeprice1d) return true;
1986
+ if (_this.scaleinfoY.type == 'trades' && count > 0 && _this.instruments[0].closeprice1d) return true; // we can draw on closeprice 1d -> first trade
1986
1987
  var y = (m_chartspaces.chart.bottom - m_chartspaces.chart.top) / 2 + m_chartspaces.chart.top;
1987
1988
  var x = (m_chartspaces.chart.right - m_chartspaces.chart.left) / 2 + m_chartspaces.chart.left;
1988
1989
  m_ctx.save();
@@ -2014,7 +2015,7 @@ function Milli_Chart(settings) {
2014
2015
 
2015
2016
  _this.drawChart = function() {
2016
2017
  if (m_zoom.isZooming) {
2017
- return;
2018
+ return; // prevent redraw due to push updates when zooming
2018
2019
  }
2019
2020
 
2020
2021
  for (var i = 0; i < _this.settings.indicators.length; i++) {
@@ -2057,7 +2058,7 @@ function Milli_Chart(settings) {
2057
2058
  m_dataPoints.map = new Map();
2058
2059
  m_dataPoints.arr = [];
2059
2060
  if (_this.instruments.length < 0) {
2060
- () => {};
2061
+ console.log('no chartdata');
2061
2062
  return;
2062
2063
  }
2063
2064
  calcChartSpaces();
@@ -2066,51 +2067,51 @@ function Milli_Chart(settings) {
2066
2067
  var len = parseInt(_this.settings.chartlen.substring(0, _this.settings.chartlen.length - 1));
2067
2068
  m_ctx.clearRect(0, 0, m_canvas.width, m_canvas.height);
2068
2069
  m_ctx.lineWidth = 1 / window.devicePixelRatio;
2069
- m_ctx.textBaseline = 'top';
2070
- var i;
2070
+ m_ctx.textBaseline = 'top'; // important!
2071
+ var s;
2071
2072
  if (period == 'd' && _this.settings.chartlen != 'ytd') {
2072
2073
  if (m_zoom.mousedown.timestamp) {
2073
2074
  _this.scaleinfoX.endTimeStamp = m_zoom.mouseup.timestamp > m_zoom.mousedown.timestamp ? m_zoom.mouseup.timestamp : m_zoom.mousedown.timestamp;
2074
2075
  _this.scaleinfoX.startTimeStamp = m_zoom.mouseup.timestamp < m_zoom.mousedown.timestamp ? m_zoom.mouseup.timestamp : m_zoom.mousedown.timestamp;
2075
2076
  } else {
2076
- _this.scaleinfoX.startTimeStamp = getTickStartDate(len);
2077
-
2078
-
2077
+ _this.scaleinfoX.startTimeStamp = getTickStartDate(len); // calc not to start with weekends
2078
+ // back up x days from quotedate if needed
2079
+ // TODO if startTimeStamp < quotedate -len borde det vara
2079
2080
  var quoteDate = businessDaysSubtraction(_this.instruments[0].quotedate, len);
2080
- if (_this.scaleinfoX.startTimeStamp - _this.scaleinfoX.startTimeStamp % 86400000 > quoteDate) {
2081
+ if (_this.scaleinfoX.startTimeStamp - _this.scaleinfoX.startTimeStamp % 86400000 > quoteDate) { // if startdate > quotedate back startdate
2081
2082
  _this.scaleinfoX.startTimeStamp -= _this.scaleinfoX.startTimeStamp - _this.scaleinfoX.startTimeStamp % 86400000;
2082
2083
  _this.scaleinfoX.startTimeStamp += quoteDate;
2083
2084
  }
2084
- _this.scaleinfoX.endTimeStamp = new Date();
2085
+ _this.scaleinfoX.endTimeStamp = new Date(); // om helg TODO
2085
2086
  if (len > 1)
2086
2087
  _this.scaleinfoX.endTimeStamp = new Date(_this.scaleinfoX.endTimeStamp.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketclose + 'Z').getTime();
2087
2088
  else if (len == 1) {
2088
-
2089
+ // check if startdate is not today (due to exchange is closed f ex DJ)
2089
2090
  if (_this.scaleinfoX.startTimeStamp % 86400000 != new Date().getTime() % 86400) {
2090
2091
  _this.scaleinfoX.endTimeStamp = new Date(new Date(_this.scaleinfoX.startTimeStamp).toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketclose + 'Z').getTime();
2091
2092
  } else
2092
2093
  _this.scaleinfoX.endTimeStamp = new Date(_this.scaleinfoX.endTimeStamp.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketclose + 'Z').getTime();
2093
2094
  } else {
2094
-
2095
+ // check that the last trade is not later than closetime
2095
2096
  var tradetimestamp = new Date(_this.instruments[0].trades[_this.instruments[0].trades.length - 1].timestamp).getTime();
2096
2097
  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();
2097
2098
  if (closetimestamp < tradetimestamp)
2098
- _this.scaleinfoX.endTimeStamp = new Date(closetimestamp);
2099
+ _this.scaleinfoX.endTimeStamp = new Date(closetimestamp); // borde inte rita med closeprice1d då heller eller spelar det ingen roll?
2099
2100
  else
2100
2101
  _this.scaleinfoX.endTimeStamp = new Date(tradetimestamp);
2101
2102
  }
2102
2103
  if (_this.scaleinfoX.endTimeStamp - (_this.scaleinfoX.endTimeStamp % 86400000) > _this.instruments[0].quotedate) {
2103
2104
  _this.scaleinfoX.endTimeStamp -= _this.scaleinfoX.endTimeStamp - _this.scaleinfoX.endTimeStamp % 86400000;
2104
- _this.scaleinfoX.endTimeStamp += _this.instruments[0].quotedate;
2105
+ _this.scaleinfoX.endTimeStamp += _this.instruments[0].quotedate; // set enddate = last Quotedate
2105
2106
  }
2106
2107
  }
2107
2108
  setTimeSpanData();
2108
2109
  _this.scaleinfoY.type = 'trades';
2109
2110
  if (_this.settings.absoluteScaling == true) {
2110
- for (var s = 1; s < _this.instruments.length; s++) _this.instruments[s].factor = 1;
2111
+ for (s = 1; s < _this.instruments.length; s++) _this.instruments[s].factor = 1;
2111
2112
  } else
2112
2113
  if (_this.instruments.length > 1) {
2113
-
2114
+ // calc factors
2114
2115
  var instrumentprice;
2115
2116
  for (i = 0; i < _this.instruments[0].trades.length; i++) {
2116
2117
  if (_this.instruments[0].trades[i].timestamp >= _this.scaleinfoX.startTimeStamp) {
@@ -2118,7 +2119,7 @@ function Milli_Chart(settings) {
2118
2119
  break;
2119
2120
  }
2120
2121
  }
2121
- for (var s = 1; s < _this.instruments.length; s++) {
2122
+ for (s = 1; s < _this.instruments.length; s++) {
2122
2123
  if (_this.instruments[s].insref != 0) {
2123
2124
  for (i = 0; i < _this.instruments[s].trades.length; i++) {
2124
2125
  if (_this.instruments[s].trades[i].timestamp >= _this.scaleinfoX.startTimeStamp) {
@@ -2147,7 +2148,6 @@ function Milli_Chart(settings) {
2147
2148
 
2148
2149
  } else
2149
2150
  if (period == 'm') {
2150
- () => {};
2151
2151
 
2152
2152
  if (m_zoom.mousedown.timestamp) {
2153
2153
  _this.scaleinfoX.startTimeStamp = m_zoom.mousedown.timestamp > m_zoom.mouseup.timestamp ? m_zoom.mouseup.timestamp : m_zoom.mousedown.timestamp;
@@ -2162,12 +2162,12 @@ function Milli_Chart(settings) {
2162
2162
  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;
2163
2163
 
2164
2164
  _this.scaleinfoX.endTimeStamp = new Date().getTime();
2165
- _this.scaleinfoX.endTimeStamp = _this.scaleinfoX.endTimeStamp - (_this.scaleinfoX.endTimeStamp % 86400000);
2165
+ _this.scaleinfoX.endTimeStamp = _this.scaleinfoX.endTimeStamp - (_this.scaleinfoX.endTimeStamp % 86400000); // TODO: detta kan vi nog ta bort eller skall det vara med closetime?
2166
2166
  }
2167
2167
  setTimeSpanData();
2168
2168
  _this.scaleinfoY.type = 'history';
2169
2169
  if (_this.settings.absoluteScaling == true) {
2170
- for (var s = 1; s < _this.instruments.length; s++) _this.instruments[s].factor = 1;
2170
+ for (s = 1; s < _this.instruments.length; s++) _this.instruments[s].factor = 1;
2171
2171
  } else calcCompareFactors('history');
2172
2172
  _this.instruments[0].factor = 1;
2173
2173
 
@@ -2197,7 +2197,7 @@ function Milli_Chart(settings) {
2197
2197
  _this.scaleinfoX.startTimeStamp = _this.instruments[0].history[0].timestamp;
2198
2198
  } else
2199
2199
  if (_this.settings.chartlen == 'ytd') {
2200
- _this.scaleinfoX.startTimeStamp = new Date(new Date().getFullYear() + '-01-01').getTime();
2200
+ _this.scaleinfoX.startTimeStamp = new Date(new Date().getFullYear() + '-01-01').getTime(); // TODO, hur skall vi göra här om det inte finns data runt här?
2201
2201
  } else {
2202
2202
  _this.scaleinfoX.startTimeStamp = new Date().getTime() - (86400000 * 365 * (isNaN(len) ? 1 : len));
2203
2203
  }
@@ -2205,12 +2205,12 @@ function Milli_Chart(settings) {
2205
2205
  _this.scaleinfoX.startTimeStamp = findFirstWeekDay(_this.scaleinfoX.startTimeStamp).getTime();
2206
2206
 
2207
2207
  _this.scaleinfoX.endTimeStamp = new Date().getTime();
2208
- _this.scaleinfoX.endTimeStamp = _this.scaleinfoX.endTimeStamp - (_this.scaleinfoX.endTimeStamp % 86400000);
2208
+ _this.scaleinfoX.endTimeStamp = _this.scaleinfoX.endTimeStamp - (_this.scaleinfoX.endTimeStamp % 86400000); // TODO: detta kan vi nog ta bort eller skall det vara med closetime?
2209
2209
  }
2210
2210
  setTimeSpanData();
2211
2211
  _this.scaleinfoY.type = 'history';
2212
2212
  if (_this.settings.absoluteScaling == true) {
2213
- for (var s = 1; s < _this.instruments.length; s++) _this.instruments[s].factor = 1;
2213
+ for (s = 1; s < _this.instruments.length; s++) _this.instruments[s].factor = 1;
2214
2214
  } else calcCompareFactors('history');
2215
2215
 
2216
2216
  _this.instruments[0].factor = 1;
@@ -2227,10 +2227,10 @@ function Milli_Chart(settings) {
2227
2227
 
2228
2228
  }
2229
2229
 
2230
-
2231
-
2232
-
2233
-
2230
+ /*for (const [key, a] of m_analyzisMethod.entries()) {
2231
+ if (a.method == 'bb') plotBollingerBand(a, 'history');
2232
+ else plotMovingAverage(a, 'history');
2233
+ }*/
2234
2234
  }
2235
2235
  drawBoxShadow(m_chartspaces.chart);
2236
2236
 
@@ -2241,14 +2241,14 @@ function Milli_Chart(settings) {
2241
2241
  }
2242
2242
  if (typeof m_chartCss.backgroundColor !== 'undefined') {
2243
2243
  m_ctx.save();
2244
-
2244
+ //if (_this.settings.curveOnTop == false)
2245
2245
  m_ctx.globalCompositeOperation = 'destination-over';
2246
2246
  m_ctx.fillStyle = m_chartCss.backgroundColor;
2247
-
2247
+ //m_ctx.fillRect(0, 0, m_canvas.width, m_canvas.height);
2248
2248
  m_ctx.fillRect(0, 0, m_canvas.width, m_canvas.height);
2249
2249
  m_ctx.restore();
2250
2250
  }
2251
-
2251
+ //onMouseOut();
2252
2252
  };
2253
2253
 
2254
2254
  function drawBoxShadow(space) {
@@ -2279,6 +2279,8 @@ function Milli_Chart(settings) {
2279
2279
  if (instr == null) return;
2280
2280
 
2281
2281
  if (typeof data.name !== 'undefined') instr.name = data.name;
2282
+ if (typeof data.instrumenttype !== 'undefined') instr.instrumenttype = data.instrumenttype;
2283
+ else instr.instrumenttype = -1;
2282
2284
  if (typeof data.pricetype !== 'undefined') instr.pricetype = data.pricetype;
2283
2285
  else instr.pricetype = 'price';
2284
2286
  if (typeof data.symbol !== 'undefined') instr.symbol = data.symbol;
@@ -2286,7 +2288,7 @@ function Milli_Chart(settings) {
2286
2288
 
2287
2289
  if (typeof data.tradecurrency !== 'undefined') instr.tradecurrency = data.tradecurrency;
2288
2290
  if (data.marketopen && data.marketclose) {
2289
- if (new Date('2020-01-01T' + data.marketopen + 'Z') > new Date('2020-01-01T' + data.marketclose + 'Z')) {
2291
+ 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
2290
2292
  data.marketopen = '00:00:00';
2291
2293
  data.marketclose = '22:00:00';
2292
2294
  }
@@ -2298,7 +2300,9 @@ function Milli_Chart(settings) {
2298
2300
  instr.quotedate = new Date().getTime();
2299
2301
  instr.quotedate -= instr.quotedate % 86400000;
2300
2302
  }
2301
-
2303
+ if (typeof data.time !== 'undefined') {
2304
+ instr.quotetime = ((parseInt(data.time) * 3600) + (parseInt(data.time.substring(3, 5)) * 60) + parseInt(data.time.substring(6, 8))) * 1000;
2305
+ } else instr.quotetime = 0;
2302
2306
  if (typeof data.marketopen !== 'undefined') {
2303
2307
  if (!data.marketopen) {
2304
2308
  data.marketopen = '00:00:00';
@@ -2318,7 +2322,7 @@ function Milli_Chart(settings) {
2318
2322
  instr.trades = [];
2319
2323
  instr.hashmap.clear();
2320
2324
  for (i = 0; i < data.trades.length; i++) {
2321
- if (data.trades[i].tradecode & 16) {
2325
+ if (data.trades[i].tradecode & 16) { // canceltrade
2322
2326
  continue;
2323
2327
  }
2324
2328
  item = [];
@@ -2335,7 +2339,7 @@ function Milli_Chart(settings) {
2335
2339
  }
2336
2340
  instr.trades.push(item);
2337
2341
  instr.hashmap.set(item.timestamp, item);
2338
-
2342
+ // we might have recieved trades from push before dataapi
2339
2343
  instr.trades.sort(function(a, b) {
2340
2344
  return a.timestamp - b.timestamp;
2341
2345
  });
@@ -2348,7 +2352,7 @@ function Milli_Chart(settings) {
2348
2352
  instr.history = [];
2349
2353
  for (i = 0; i < data.history.length; i++) {
2350
2354
  item = [];
2351
- if (typeof data.history[i].date !== 'undefined' && data.history[i].closeprice != null) {
2355
+ 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å
2352
2356
  var timestamp = new Date(data.history[i].date + 'T00:00:00Z').getTime();
2353
2357
  item.timestamp = timestamp;
2354
2358
  } else continue;
@@ -2358,7 +2362,7 @@ function Milli_Chart(settings) {
2358
2362
  if (typeof data.history[i].dividend !== 'undefined') item.dividend = data.history[i].dividend;
2359
2363
  instr.history.push(item);
2360
2364
  }
2361
- if (_this.settings.hcurve && instr.history.length > 0) {
2365
+ if (_this.settings.hcurve && instr.history.length > 0) { // varför på all historik, och inte bara på hcurve
2362
2366
  if (!isToday(new Date(instr.history[instr.history.length - 1].timestamp))) {
2363
2367
  var addItem = {};
2364
2368
  MillistreamWidgetApi_AssignObject(instr.history[instr.history.length - 1], addItem);
@@ -2383,7 +2387,7 @@ function Milli_Chart(settings) {
2383
2387
  };
2384
2388
 
2385
2389
  function plotExternalHistoricalData(data) {
2386
-
2390
+ // används för dividend osv
2387
2391
  m_ctx.save();
2388
2392
  var startpoint = { x: 0, y: 0 };
2389
2393
  var endpoint = { x: 0, y: 0 };
@@ -2407,25 +2411,25 @@ function Milli_Chart(settings) {
2407
2411
  currentDate.setMinutes(lastdate.getMinutes());
2408
2412
  currentDate.setSeconds(lastdate.getSeconds());
2409
2413
 
2410
- if (lastdate.toISOString().substring(0, 10) != currentDate.toISOString().substring(0, 10)) {
2414
+ if (lastdate.toISOString().substring(0, 10) != currentDate.toISOString().substring(0, 10)) { // new date
2411
2415
  var tmp = new Date(lastdate.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketclose + 'Z');
2412
2416
  var nextDate = new Date(data[i].timestamp);
2413
- tmp = tmp.getTime() + 86400000 - _this.scaleinfoX.milliPerDay;
2417
+ tmp = tmp.getTime() + 86400000 - _this.scaleinfoX.milliPerDay; // increase to next days starttime
2414
2418
  currentDate = new Date(tmp);
2415
2419
  while (dateDiffInDays(currentDate, nextDate) > 0) {
2416
2420
  if (currentDate.getDay() == 0 || currentDate.getDay() == 6)
2417
2421
  offset += 86400000 / _this.scaleinfoX.timePerPixel;
2418
2422
  else
2419
- offset += ((86400000 - _this.scaleinfoX.milliPerDay) / _this.scaleinfoX.timePerPixel);
2423
+ offset += ((86400000 - _this.scaleinfoX.milliPerDay) / _this.scaleinfoX.timePerPixel); // * dateDiffInDays(lastdate, currentDate);
2420
2424
  currentDate = new Date(currentDate.getTime() + 86400000);
2421
2425
  }
2422
- offset += ((86400000 - _this.scaleinfoX.milliPerDay) / _this.scaleinfoX.timePerPixel);
2426
+ offset += ((86400000 - _this.scaleinfoX.milliPerDay) / _this.scaleinfoX.timePerPixel); // * dateDiffInDays(lastdate, currentDate);
2423
2427
  lastdate = currentDate;
2424
2428
  startpoint.x = Math.round(m_chartspaces.chart.left + ((data[i].timestamp - startDate) / _this.scaleinfoX.timePerPixel)) + 0.5 - offset;
2425
-
2429
+ // TODO: här blir det fel när det är från 00:00: 23:59 men göms av tmpx < startpoint.x
2426
2430
 
2427
2431
  }
2428
-
2432
+ //startpoint.y = Math.round(m_canvas.height - getScaledSetting(m_chartCss.marginBottom) - (((data[i].price * factor) - _this.scaleinfoY.minValue) * _this.scaleinfoY.valuePerPixel)) + 0.5;
2429
2433
  startpoint.y = Math.round(m_chartspaces.chart.height - getScaledSetting(m_chartCss.marginBottom) - (((data[i].price * factor) - _this.scaleinfoY.minValue) * _this.scaleinfoY.valuePerPixel)) + 0.5;
2430
2434
  maxy = maxy > startpoint.y ? maxy : startpoint.y;
2431
2435
 
@@ -2467,19 +2471,19 @@ function Milli_Chart(settings) {
2467
2471
  var endtimeToday = new Date(data[i].timestamp);
2468
2472
  if (endtimeToday.getDay() == 0 || endtimeToday.getDay() == 6) continue;
2469
2473
  if (_this.scaleinfoY.type != 'history') {
2470
- endtimeToday = new Date(endtimeToday.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketclose + 'Z');
2474
+ 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
2471
2475
  }
2472
2476
  if (data[i].timestamp > endtimeToday.getTime()) {
2473
- continue;
2477
+ continue; // dataticks efter stängning ritas inte
2474
2478
  }
2475
2479
  currentDate = new Date(data[i].timestamp);
2476
2480
  currentDate.setHours(lastdate.getHours());
2477
2481
  currentDate.setMinutes(lastdate.getMinutes());
2478
2482
  currentDate.setSeconds(lastdate.getSeconds());
2479
- if (lastdate.toISOString().substring(0, 10) != currentDate.toISOString().substring(0, 10)) {
2483
+ if (lastdate.toISOString().substring(0, 10) != currentDate.toISOString().substring(0, 10)) { // new date
2480
2484
  tmp = new Date(lastdate.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketclose + 'Z');
2481
2485
  var nextDate = new Date(data[i].timestamp);
2482
- tmp = tmp.getTime() + 86400000 - _this.scaleinfoX.milliPerDay;
2486
+ tmp = tmp.getTime() + 86400000 - _this.scaleinfoX.milliPerDay; // increase to next days starttime
2483
2487
 
2484
2488
  currentDate = new Date(tmp);
2485
2489
  while (dateDiffInDays(currentDate, nextDate) > 0) {
@@ -2489,11 +2493,11 @@ function Milli_Chart(settings) {
2489
2493
  offset += ((86400000 - _this.scaleinfoX.milliPerDay) / _this.scaleinfoX.timePerPixel);
2490
2494
  currentDate = new Date(currentDate.getTime() + 86400000);
2491
2495
  }
2492
- offset += ((86400000 - _this.scaleinfoX.milliPerDay) / _this.scaleinfoX.timePerPixel);
2496
+ offset += ((86400000 - _this.scaleinfoX.milliPerDay) / _this.scaleinfoX.timePerPixel); // * dateDiffInDays(lastdate, currentDate);
2493
2497
  lastdate = currentDate;
2494
2498
  startpoint.x = Math.round(m_chartspaces.chart.left + ((data[i].timestamp - startDate) / _this.scaleinfoX.timePerPixel)) + 0.5 - offset;
2495
2499
 
2496
-
2500
+ // TODO: här blir det fel när det är från 00:00: 23:59 men göms av tmpx < startpoint.x
2497
2501
  if (_this.scaleinfoY.type == 'trades' && tmpx < startpoint.x) {
2498
2502
  ret.push(startpoint.x, startpoint.y);
2499
2503
  }
@@ -2529,7 +2533,7 @@ function Milli_Chart(settings) {
2529
2533
  if (line.length == 0) return;
2530
2534
  m_ctx.save();
2531
2535
  m_ctx.beginPath();
2532
- m_ctx.closePath();
2536
+ m_ctx.closePath(); // clear path
2533
2537
  m_ctx.moveTo(line[0].x, line[0].y);
2534
2538
  for (var i = 1; i < line.length; i++) {
2535
2539
  m_ctx.lineTo(line[i].x, line[i].y);
@@ -2560,7 +2564,7 @@ function Milli_Chart(settings) {
2560
2564
  }
2561
2565
  var sma = calcAnalyzisLine(data, 2);
2562
2566
  m_ctx.beginPath();
2563
- m_ctx.closePath();
2567
+ m_ctx.closePath(); // clear path
2564
2568
  m_ctx.moveTo(sma[0].x, sma[0].y);
2565
2569
  for (i = 0; i < sma.length; i++) m_ctx.lineTo(sma[i].x, sma[i].y);
2566
2570
  m_ctx.stroke();
@@ -2568,10 +2572,39 @@ function Milli_Chart(settings) {
2568
2572
  return;
2569
2573
  }
2570
2574
 
2575
+ function plotLower(valuePerPixel, lineLength) {
2576
+ m_ctx.save();
2577
+ m_ctx.strokeStyle = m_instrumentCss[0].color;
2578
+ m_ctx.lineWidth = m_instrumentCss[0].width;
2579
+ var width = Math.round(m_chartspaces.lowerChart.width / (m_datapoints.length + 1) / 2);
2580
+ if (width < 2) width = 2;
2581
+ else if (width > 20) width = 20;
2582
+ m_ctx.lineWidth = width;
2583
+ for (var i = 0; i < m_datapoints.length; i++) {
2584
+ var x = (m_datapoints[i].x + 0.5) * window.devicePixelRatio;
2585
+ m_ctx.lineWidth = width;
2586
+ if (x - width <= m_chartspaces.lowerChart.left) {
2587
+ m_ctx.lineWidth = width / 2;
2588
+ x += m_ctx.lineWidth / 2;
2589
+ } else
2590
+ if (x + width >= m_chartspaces.lowerChart.right) {
2591
+ m_ctx.lineWidth = width / 2;
2592
+ x -= m_ctx.lineWidth / 2 + 1;
2593
+ }
2594
+ m_ctx.beginPath();
2595
+ m_ctx.moveTo(x, m_chartspaces.lowerChart.bottom - 0.5);
2596
+ var y = Math.round(m_chartspaces.lowerChart.bottom - (m_datapoints[i].quantity * valuePerPixel)) - 1;
2597
+ m_ctx.closePath();
2598
+ m_ctx.lineTo(x, y - 0.5);
2599
+ m_ctx.stroke();
2600
+ }
2601
+ m_ctx.restore();
2602
+ }
2603
+
2571
2604
  function plotData(data, instrument) {
2572
2605
  m_ctx.save();
2573
2606
  if (_this.settings.curveOnTop == false)
2574
- m_ctx.globalCompositeOperation = 'destination-over';
2607
+ m_ctx.globalCompositeOperation = 'destination-over'; // dont draw over labels inside the chart
2575
2608
  m_ctx.strokeStyle = m_instrumentCss[instrument].color;
2576
2609
  var factor = _this.instruments[instrument].factor;
2577
2610
  var startpoint = { x: 0, y: 0 };
@@ -2580,7 +2613,6 @@ function Milli_Chart(settings) {
2580
2613
  var len = data.length;
2581
2614
  m_ctx.lineWidth = m_instrumentCss[instrument].width / window.devicePixelRatio;
2582
2615
  m_ctx.beginPath();
2583
-
2584
2616
  var startx = 0;
2585
2617
  var starty = 0;
2586
2618
  var lastdate = new Date(_this.scaleinfoX.startTimeStamp);
@@ -2589,10 +2621,10 @@ function Milli_Chart(settings) {
2589
2621
  var maxy = 0;
2590
2622
  var hCurveLastPoint = null;
2591
2623
  var quantity = 0;
2592
-
2624
+ var nextDate;
2593
2625
  for (var i = 0; i < len; i++) {
2594
- var currentDate;
2595
-
2626
+ var currentDate = new Date(data[i].timestamp);
2627
+ // var lastItem = data[i];
2596
2628
  var tmpx = startpoint.x;
2597
2629
  var tmp;
2598
2630
  if (data[i].timestamp < _this.scaleinfoX.startTimeStamp) {
@@ -2600,42 +2632,48 @@ function Milli_Chart(settings) {
2600
2632
  continue;
2601
2633
  }
2602
2634
  if (data[i].timestamp > _this.scaleinfoX.endTimeStamp) {
2603
- break;
2635
+ break; // continue?
2604
2636
  }
2605
2637
  if (data[i].timestamp > new Date().getTime())
2606
2638
  break;
2607
2639
 
2608
2640
  if (_this.scaleinfoY.type != 'history' && (data[i].timestamp % 86400000 < _this.instruments[0].opentimestamp || data[i].timestamp % 86400000 > _this.instruments[0].closetimestamp)) {
2609
-
2641
+ // stämmer detta kan det bli överlapp vid sommartid/vintertid?
2610
2642
  continue;
2611
2643
  }
2612
2644
  var endtimeToday = new Date(data[i].timestamp);
2613
- if (endtimeToday.getDay() == 0 || endtimeToday.getDay() == 6) continue;
2645
+ 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
2614
2646
  if (_this.scaleinfoY.type != 'history') {
2615
- endtimeToday = new Date(endtimeToday.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketclose + 'Z');
2647
+ 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
2616
2648
  }
2617
2649
  if (data[i].timestamp > endtimeToday.getTime()) {
2618
- continue;
2650
+ continue; // dataticks efter stängning ritas inte
2619
2651
  }
2620
2652
 
2621
2653
  if (_this.scaleinfoY.type == 'history') {
2622
-
2623
-
2654
+ //var point = { price: data[i].price, open: null, x: endpoint.x - 0.5, y: endpoint.y - 0.5, timestamp: data[i].timestamp };
2655
+ //m_datapoints.push(point);
2624
2656
  } else
2625
- if (_this.settings.previousDayClose && addedcloseprice1d == false && m_zoom.mouseup.timestamp == null) {
2626
- currentDate = new Date(data[i].timestamp);
2627
- offset = ((86400000 - _this.scaleinfoX.milliPerDay) / _this.scaleinfoX.timePerPixel) * dateDiffInDays(new Date(startDate), currentDate);
2628
- tmp = new Date(currentDate.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketopen + 'Z');
2629
- endpoint.x = Math.round(m_chartspaces.chart.left + ((tmp.getTime() - startDate) / _this.scaleinfoX.timePerPixel)) + 0.5 - offset;
2630
-
2631
-
2632
- 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;
2633
-
2634
-
2635
-
2636
-
2637
-
2638
-
2657
+ if (_this.settings.previousDayClose && addedcloseprice1d == false && m_zoom.mouseup.timestamp == null) { // only draw closeprice1d on today charts
2658
+ currentDate = new Date(startDate);
2659
+ if (_this.settings.chartlen == '1d' || _this.settings.chartlen == '0d') { // plot the closeprice1d
2660
+ endpoint.y = Math.round(m_chartspaces.chart.height - getScaledSetting(m_chartCss.marginBottom) - (((parseFloat(_this.instruments[instrument].closeprice1d)) - _this.scaleinfoY.minValue) * _this.scaleinfoY.valuePerPixel)) + 0.5;
2661
+ endpoint.x = m_chartspaces.chart.left + 0.5 - offset;
2662
+ } else {
2663
+ if (!isToday(new Date(data[i].timestamp))) {
2664
+ nextDate = new Date(data[i].timestamp);
2665
+ while (dateDiffInDays(currentDate, nextDate) > 0) {
2666
+ if (currentDate.getDay() == 0 || currentDate.getDay() == 6)
2667
+ offset += 86400000 / _this.scaleinfoX.timePerPixel;
2668
+ else
2669
+ offset += ((86400000 - _this.scaleinfoX.milliPerDay) / _this.scaleinfoX.timePerPixel); // * dateDiffInDays(lastdate, currentDate);
2670
+ currentDate = new Date(currentDate.getTime() + 86400000);
2671
+ }
2672
+ tmp = new Date(currentDate.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketopen + 'Z');
2673
+ 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;
2674
+ endpoint.x = Math.round(m_chartspaces.chart.left + ((tmp.getTime() - startDate) / _this.scaleinfoX.timePerPixel)) + 0.5 - offset;
2675
+ }
2676
+ }
2639
2677
  m_ctx.moveTo(endpoint.x, endpoint.y);
2640
2678
  lastdate = new Date(data[i].timestamp);
2641
2679
  addedcloseprice1d = true;
@@ -2646,25 +2684,24 @@ function Milli_Chart(settings) {
2646
2684
  currentDate.setHours(lastdate.getHours());
2647
2685
  currentDate.setMinutes(lastdate.getMinutes());
2648
2686
  currentDate.setSeconds(lastdate.getSeconds());
2649
- if (lastdate.toISOString().substring(0, 10) != currentDate.toISOString().substring(0, 10)) {
2687
+ if (lastdate.toISOString().substring(0, 10) != currentDate.toISOString().substring(0, 10)) { // new date
2650
2688
  tmp = new Date(lastdate.toISOString().substring(0, 10) + 'T' + _this.instruments[0].marketclose + 'Z');
2651
-
2652
- var nextDate = new Date(data[i].timestamp);
2653
- tmp = tmp.getTime() + 86400000 - _this.scaleinfoX.milliPerDay;
2689
+ nextDate = new Date(data[i].timestamp);
2690
+ tmp = tmp.getTime() + 86400000 - _this.scaleinfoX.milliPerDay; // increase to next days starttime
2654
2691
 
2655
2692
  currentDate = new Date(tmp);
2656
2693
  while (dateDiffInDays(currentDate, nextDate) > 0) {
2657
2694
  if (currentDate.getDay() == 0 || currentDate.getDay() == 6)
2658
2695
  offset += 86400000 / _this.scaleinfoX.timePerPixel;
2659
2696
  else
2660
- offset += ((86400000 - _this.scaleinfoX.milliPerDay) / _this.scaleinfoX.timePerPixel);
2697
+ offset += ((86400000 - _this.scaleinfoX.milliPerDay) / _this.scaleinfoX.timePerPixel); // * dateDiffInDays(lastdate, currentDate);
2661
2698
  currentDate = new Date(currentDate.getTime() + 86400000);
2662
2699
  }
2663
- offset += ((86400000 - _this.scaleinfoX.milliPerDay) / _this.scaleinfoX.timePerPixel);
2700
+ offset += ((86400000 - _this.scaleinfoX.milliPerDay) / _this.scaleinfoX.timePerPixel); // * dateDiffInDays(lastdate, currentDate);
2664
2701
  lastdate = currentDate;
2665
2702
  startpoint.x = Math.round(m_chartspaces.chart.left + ((data[i].timestamp - startDate) / _this.scaleinfoX.timePerPixel)) + 0.5 - offset;
2666
2703
 
2667
-
2704
+ // TODO: här blir det fel när det är från 00:00: 23:59 men göms av tmpx < startpoint.x
2668
2705
  if (_this.scaleinfoY.type == 'trades' && tmpx < startpoint.x) {
2669
2706
  m_ctx.lineTo(startpoint.x, startpoint.y);
2670
2707
  }
@@ -2673,6 +2710,7 @@ function Milli_Chart(settings) {
2673
2710
  maxy = maxy > startpoint.y ? maxy : startpoint.y;
2674
2711
 
2675
2712
  startpoint.x = Math.round(m_chartspaces.chart.left + ((data[i].timestamp - _this.scaleinfoX.startDate.getTime()) / _this.scaleinfoX.timePerPixel)) + 0.5;
2713
+
2676
2714
  startpoint.x -= offset;
2677
2715
  quantity += data[i].quantity;
2678
2716
  if (startpoint.x != endpoint.x || startpoint.y != endpoint.y) {
@@ -2693,7 +2731,7 @@ function Milli_Chart(settings) {
2693
2731
  if (tmpx < startpoint.x) {
2694
2732
  if (_this.settings.hcurve) m_ctx.lineTo(startpoint.x, endpoint.y);
2695
2733
  m_ctx.lineTo(startpoint.x, startpoint.y);
2696
-
2734
+ //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"
2697
2735
 
2698
2736
  if (instrument == 0) {
2699
2737
  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 };
@@ -2710,7 +2748,7 @@ function Milli_Chart(settings) {
2710
2748
  m_datapoints.push(point);
2711
2749
  if (_this.settings.hcurve && _this.scaleinfoY.type == 'history') {
2712
2750
  if (isToday(currentDate)) {
2713
-
2751
+ // only 1 point in hcurve chart, draw line from start of chart to end date
2714
2752
  m_ctx.moveTo(m_chartspaces.chart.left, startpoint.y);
2715
2753
  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 };
2716
2754
  m_datapoints.push(point);
@@ -2718,12 +2756,12 @@ function Milli_Chart(settings) {
2718
2756
  m_datapoints.push(point);
2719
2757
  startx = m_chartspaces.chart.left;
2720
2758
  starty = startpoint.y;
2721
-
2759
+ // last point so break out and store startx and starty from fake point
2722
2760
  break;
2723
2761
  } else if (hCurveLastPoint) {
2724
-
2725
-
2726
-
2762
+ /* var y = Math.round(m_canvas.height - getScaledSetting(m_chartCss.marginBottom) - (((hCurveLastPoint.price * factor) - _this.scaleinfoY.minValue) * _this.scaleinfoY.valuePerPixel)) + 0.5;
2763
+ m_ctx.moveTo(m_chartspaces.chart.left, y);
2764
+ m_ctx.lineTo(startpoint.x, y);*/
2727
2765
  }
2728
2766
  }
2729
2767
  quantity = 0;
@@ -2736,7 +2774,7 @@ function Milli_Chart(settings) {
2736
2774
  endpoint.y = startpoint.y;
2737
2775
  }
2738
2776
  if (data[i].dividend) {
2739
-
2777
+ //console.log('div', data[i]);
2740
2778
  }
2741
2779
  }
2742
2780
  m_dataPoints.arr.sort(function(a, b) {
@@ -2760,7 +2798,7 @@ function Milli_Chart(settings) {
2760
2798
  m_ctx.fill();
2761
2799
  } else
2762
2800
  m_ctx.closePath();
2763
-
2801
+ // 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???
2764
2802
  if (instrument == 0) {
2765
2803
  drawPriceIndicator();
2766
2804
  drawClosePriceIndicator();
@@ -2769,13 +2807,13 @@ function Milli_Chart(settings) {
2769
2807
  m_ctx.restore();
2770
2808
  }
2771
2809
 
2772
-
2773
-
2774
-
2775
-
2776
-
2777
-
2778
-
2810
+ /* function drawCompare(resp) {
2811
+ parseData(resp[0], 1);
2812
+ _this.drawChart();
2813
+ requestStreaming();
2814
+ return;
2815
+ }
2816
+ */
2779
2817
 
2780
2818
  _this.setChartLength = function(len) {
2781
2819
  _this.settings.chartlen = len;
@@ -2907,7 +2945,7 @@ function Milli_Chart(settings) {
2907
2945
  };
2908
2946
  req.open("GET", url, true);
2909
2947
  req.onerror = function(error) {
2910
- () => {};
2948
+ console.log('Fetch data error', error);
2911
2949
  };
2912
2950
  req.send();
2913
2951
  }
@@ -2915,13 +2953,13 @@ function Milli_Chart(settings) {
2915
2953
  _this.refreshData = function() {
2916
2954
  _this.instruments.forEach(function(c, pos) {
2917
2955
  if (c.insref != 0) {
2918
- fetchTrades(c.insref);
2956
+ if (_this.settings.intradaylen) fetchTrades(c.insref);
2919
2957
  fetchHistory(c.insref);
2920
2958
  }
2921
2959
  });
2922
-
2960
+ //fetch data and redraw ( for no push charts)
2923
2961
  };
2924
-
2962
+ // Compare functions
2925
2963
  _this.removeAllCompares = function() {
2926
2964
  if (_this.instruments.length == 1) return;
2927
2965
  for (var i = 0; i < 3; i++)
@@ -2968,21 +3006,23 @@ function Milli_Chart(settings) {
2968
3006
 
2969
3007
  _this.instruments[pos] = instr;
2970
3008
 
2971
- fetchTrades(insref);
3009
+ if (_this.settings.intradaylen) fetchTrades(insref);
2972
3010
  fetchHistory(insref);
2973
3011
  return 1;
2974
3012
  };
2975
-
2976
-
3013
+ // Size functions
2977
3014
  function setChartSize() {
2978
3015
  var offset = 0;
3016
+ // set canvas size to 0 so it does not prevent the div to resize
3017
+ _this.settings.target.style.height = '0px';
3018
+ _this.settings.target.style.width = '0px';
2979
3019
  if (_this.settings.target.parentNode.classList.contains('chartcontainer')) {
2980
3020
  offset = _this.settings.target.getBoundingClientRect().top - _this.settings.target.parentNode.getBoundingClientRect().top;
2981
3021
  }
2982
3022
  _this.settings.target.style.height = (_this.settings.target.parentNode.offsetHeight - offset) + 'px';
2983
3023
  _this.settings.target.style.width = _this.settings.target.parentNode.offsetWidth + 'px';
2984
-
2985
-
3024
+ //_this.settings.target.style.height = (_this.settings.target.parentNode.offsetHeight - offset) * window.devicePixelRatio + 'px';
3025
+ //_this.settings.target.style.width = _this.settings.target.parentNode.offsetWidth * window.devicePixelRatio + 'px';
2986
3026
  m_canvas.setRect(_this.settings.target.offsetHeight, _this.settings.target.offsetWidth);
2987
3027
  }
2988
3028
 
@@ -2991,7 +3031,7 @@ function Milli_Chart(settings) {
2991
3031
  m_resizing.height = m_canvas.height;
2992
3032
  };
2993
3033
 
2994
- _this.resize = function(e, ui) {
3034
+ _this.resizing = function(e, ui) {
2995
3035
  var diff = (m_resizing.height - m_canvas.height) / m_canvas.height * 100;
2996
3036
  if (Math.abs(diff) > 1) {
2997
3037
  setChartSize();
@@ -3002,8 +3042,8 @@ function Milli_Chart(settings) {
3002
3042
  diff = (m_resizing.width - m_canvas.width) / m_canvas.width * 100;
3003
3043
  if (Math.abs(diff) > 1) {
3004
3044
  setChartSize();
3005
-
3006
-
3045
+ //m_canvas.height = Math.floor(_this.settings.target.offsetHeight * window.devicePixelRatio);
3046
+ //m_canvas.width = Math.floor(_this.settings.target.offsetWidth * window.devicePixelRatio);
3007
3047
  m_resizing.width = m_canvas.width;
3008
3048
  m_resizing.height = m_canvas.height;
3009
3049
  _this.drawChart();
@@ -3035,11 +3075,11 @@ function Milli_Chart(settings) {
3035
3075
  m_canvas = MillistreamWidgetApi_addElement(_this, 'canvas', 'millistream-chart-canvas', _this.settings.target);
3036
3076
  m_ctx = m_canvas.getContext("2d");
3037
3077
  setChartSize();
3038
- m_canvas.addEventListener('mousemove', onMouseMove, false);
3078
+ m_canvas.addEventListener('mousemove', onMouseMove, false); // disable while loading and enable on drawReady
3039
3079
  m_canvas.addEventListener('mouseout', onMouseOut, false);
3040
3080
  m_canvas.style.cursor = "crosshair";
3041
3081
  m_canvas.onmousedown = (function(evt) {
3042
- if (!evt.which == 1) return;
3082
+ if (evt.which != 1) return; // ignore right and middle
3043
3083
  if (_this.settings.enablezoom == false) return;
3044
3084
  if (m_datapoints.length == 0) return;
3045
3085
  var rect = m_canvas.getBoundingClientRect();
@@ -3065,7 +3105,7 @@ function Milli_Chart(settings) {
3065
3105
  clearZoom();
3066
3106
  return;
3067
3107
  }
3068
- if (Math.abs(x - m_zoom.mousedown.pos) > 5) {
3108
+ if (Math.abs(x - m_zoom.mousedown.pos) > 5) { // only handle zoom with 5 pixels width
3069
3109
  var i;
3070
3110
  for (i = m_datapoints.length - 1; i > 0; i--) {
3071
3111
  if (x >= m_datapoints[i].x) {
@@ -3082,7 +3122,7 @@ function Milli_Chart(settings) {
3082
3122
  m_zoom.mousedown.pos = 0;
3083
3123
  m_zoom.mousedown.i = 0;
3084
3124
  if (m_zoom.mousedown.oldtimestamp != null) {
3085
- m_zoom.mousedown.timestamp = m_zoom.mousedown.oldtimestamp;
3125
+ m_zoom.mousedown.timestamp = m_zoom.mousedown.oldtimestamp; // so we do not unzoom if zoomed
3086
3126
  m_zoom.mousedown.oldtimestamp = null;
3087
3127
  } else
3088
3128
  m_zoom.mousedown.timestamp = null;
@@ -3129,12 +3169,15 @@ function Milli_Chart(settings) {
3129
3169
  if (instr.pricetype == 'price' || instr.pricetype == 'nav') {
3130
3170
  if (typeof json['148'] !== 'undefined') {
3131
3171
  instr.closeprice1d = parseFloat(json['148']);
3172
+ update = true;
3132
3173
  }
3133
3174
  } else
3134
3175
  if (typeof json['262'] !== 'undefined') {
3135
- instr.closeprice1d = parseFloat(json['148']);
3176
+ instr.closeprice1d = parseFloat(json['262']);
3177
+ update = true;
3136
3178
  }
3137
3179
  }
3180
+ var timestamp;
3138
3181
  if (mref == 'quote') {
3139
3182
  if (instr.history.length == 0) return;
3140
3183
  if (json['3'] && !isToday(new Date(json['3']))) return;
@@ -3143,9 +3186,12 @@ function Milli_Chart(settings) {
3143
3186
  instr.quotedate = new Date(json['3']).getTime();
3144
3187
  instr.quotedate -= instr.quotedate % 86400000;
3145
3188
  }
3189
+ if (json['4']) {
3190
+ instr.quotetime = ((parseInt(json[4]) * 3600) + (parseInt(json[4].substring(3, 5)) * 60) + parseInt(json[4].substring(6, 8))) * 1000;
3191
+ }
3146
3192
  var price = undefined;
3147
3193
  var quantity = undefined;
3148
- var timestamp = new Date().getTime();
3194
+ timestamp = new Date().getTime();
3149
3195
  timestamp -= timestamp % 86400000;
3150
3196
  var obj = instr.history[instr.history.length - 1];
3151
3197
  if (instr.pricetype == 'yield') {
@@ -3172,31 +3218,31 @@ function Milli_Chart(settings) {
3172
3218
  if (_this.scaleinfoY.type == 'history') update = true;
3173
3219
  } else {
3174
3220
  if (json['3'] && json['36'] && (json['12'] || json['201'])) {
3175
- var timestamp = new Date(json['3'] + 'T' + json['36'].substring(0, 6) + '00' + 'Z').getTime();
3221
+ timestamp = new Date(json['3'] + 'T' + json['36'].substring(0, 6) + '00' + 'Z').getTime();
3176
3222
  var data = instr.hashmap.get(timestamp);
3177
3223
  if (typeof data === 'undefined') {
3178
3224
  data = {};
3179
-
3225
+ //data.tradereference = json['14'];
3180
3226
  data.timestamp = timestamp;
3181
3227
  calcAnalyizis = true;
3182
3228
  if (instr.pricetype == 'price') {
3183
3229
  update = true;
3184
- data.price = parseFloat(json['12']);
3185
- data.open = parseFloat(json['12']);
3186
- data.high = parseFloat(json['12']);
3187
- data.low = parseFloat(json['12']);
3230
+ data.price = parseFloat(json['12']); // eller 201 för tradeyield
3231
+ data.open = parseFloat(json['12']); // eller 201 för tradeyield
3232
+ data.high = parseFloat(json['12']); // eller 201 för tradeyield
3233
+ data.low = parseFloat(json['12']); // eller 201 för tradeyield
3188
3234
  data.quantity = typeof json['13'] === 'undefined' ? 0 : parseInt(json['13']);
3189
- } else if (instr.pricetype == 'price') {
3190
- data.price = parseFloat(json['201']);
3191
- data.open = parseFloat(json['201']);
3192
- data.high = parseFloat(json['201']);
3193
- data.low = parseFloat(json['201']);
3235
+ } else if (instr.pricetype == 'yield') {
3236
+ data.price = parseFloat(json['201']); // eller 201 för tradeyield
3237
+ data.open = parseFloat(json['201']); // eller 201 för tradeyield
3238
+ data.high = parseFloat(json['201']); // eller 201 för tradeyield
3239
+ data.low = parseFloat(json['201']); // eller 201 för tradeyield
3194
3240
  data.quantity = typeof json['13'] === 'undefined' ? 0 : parseInt(json['13']);
3195
3241
  update = true;
3196
3242
  }
3197
3243
  if (update) {
3198
3244
  if (instr.trades.length != 0 && data.timestamp < instr.trades[instr.trades.length - 1].timestamp) {
3199
-
3245
+ // TODO console.log("pushtrade is older than last trade ignoring, should file it on correct postition");
3200
3246
  } else
3201
3247
  instr.hashmap.set(data.timestamp, data);
3202
3248
  instr.trades.push(data);
@@ -3205,24 +3251,24 @@ function Milli_Chart(settings) {
3205
3251
  if (instr.pricetype == 'price') {
3206
3252
  if (data.price != parseFloat(json['12']))
3207
3253
  calcAnalyizis = true;
3208
- data.price = parseFloat(json['12']);
3254
+ data.price = parseFloat(json['12']); // eller 201 för tradeyield
3209
3255
  data.quantity += typeof json['13'] === 'undefined' ? 0 : parseInt(json['13']);
3210
3256
  if (_this.scaleinfoY.type == 'trades') update = true;
3211
3257
  } else {
3212
- if (instr.pricetype == 'price') {
3258
+ if (instr.pricetype == 'yield') {
3213
3259
  if (data.price != parseFloat(json['201']))
3214
3260
  calcAnalyizis = true;
3215
- data.price = parseFloat(json['201']);
3261
+ data.price = parseFloat(json['201']); // eller 201 för tradeyield
3216
3262
  data.quantity += typeof json['13'] === 'undefined' ? 0 : parseInt(json['13']);
3217
3263
  if (_this.scaleinfoY.type == 'trades') update = true;
3218
3264
  }
3219
-
3265
+ // TODo: updatera med quantity, open , high,low osv?
3220
3266
  }
3221
3267
  }
3222
3268
  }
3223
3269
  if (calcAnalyizis && insref == _this.instruments[0].insref) {
3224
3270
  for (var i = 0; i < _this.settings.indicators.length; i++) {
3225
-
3271
+ //for (const [key, a] of m_analyzisMethod.entries()) {
3226
3272
  switch (_this.settings.indicators[i].method) {
3227
3273
  case 'sma':
3228
3274
  _this.settings.indicators[i].trades = [];
@@ -3237,7 +3283,7 @@ function Milli_Chart(settings) {
3237
3283
  _this.settings.indicators[i].trades = bollingerBands(_this.instruments[0].trades, _this.settings.indicators[i].method_length, _this.settings.indicators[i].stddev | 2);
3238
3284
  break;
3239
3285
  default:
3240
-
3286
+ // draw custom added?
3241
3287
  break;
3242
3288
  }
3243
3289
  }
@@ -3246,18 +3292,19 @@ function Milli_Chart(settings) {
3246
3292
  _this.drawChart();
3247
3293
  }
3248
3294
  return;
3249
- };
3250
- }
3295
+ }
3296
+ };
3251
3297
 
3252
-
3298
+ // used by trader
3253
3299
  _this.exportData = function() {
3254
3300
  let ret = [];
3255
-
3301
+ var i;
3302
+ var date, datestr;
3256
3303
  if (_this.scaleinfoY.type == 'trades') {
3257
3304
  if (_this.instruments.length > 0) {
3258
- for (var i = 0; i < _this.instruments[0].trades.length; i++) {
3259
- var date = new Date(_this.instruments[0].trades[i].timestamp - new Date().getTimezoneOffset() * 60000);
3260
- var datestr = date.toISOString();
3305
+ for (i = 0; i < _this.instruments[0].trades.length; i++) {
3306
+ date = new Date(_this.instruments[0].trades[i].timestamp - new Date().getTimezoneOffset() * 60000); // tz_offset in minutes
3307
+ datestr = date.toISOString();
3261
3308
 
3262
3309
  ret.push([datestr.substring(0, 10), datestr.substring(11, 23), _this.instruments[0].trades[i].price, _this.instruments[0].trades[i].quantity]);
3263
3310
  }
@@ -3269,9 +3316,9 @@ function Milli_Chart(settings) {
3269
3316
  ];
3270
3317
  } else {
3271
3318
  if (_this.instruments.length > 0) {
3272
- for (var i = 0; i < _this.instruments[0].history.length; i++) {
3273
- var date = new Date(_this.instruments[0].history[i].timestamp);
3274
- var datestr = date.toISOString();
3319
+ for (i = 0; i < _this.instruments[0].history.length; i++) {
3320
+ date = new Date(_this.instruments[0].history[i].timestamp);
3321
+ datestr = date.toISOString();
3275
3322
 
3276
3323
  ret.push([datestr.substring(0, 10), "", _this.instruments[0].history[i].price, _this.instruments[0].history[i].quantity]);
3277
3324
  }
@@ -3282,10 +3329,10 @@ function Milli_Chart(settings) {
3282
3329
  ...ret
3283
3330
  ];
3284
3331
  }
3285
- }
3332
+ };
3286
3333
 
3287
3334
  _this.destroyWidget = function() {
3288
-
3335
+ // if we have subscriptions send in an empty array to unsubscribe all and release it
3289
3336
  if (MillistreamWidgetApi_isObjectEmpty(_this.unsubscriptions) == false)
3290
3337
  _this.requestid = _this.settings.streaming.MillistreamWidgetStreamingApi_subscribeInstruments(_this, _this.requestid, []);
3291
3338
  return 0;
@@ -3309,23 +3356,25 @@ function Milli_Chart(settings) {
3309
3356
  }
3310
3357
 
3311
3358
  function fetchHistory(instrument) {
3312
- var oldfields = _this.settings.fields;
3313
- _this.settings.fields = [...['name', 'tradecurrency', 'date', 'closeprice', 'closequantity', 'marketopen', 'marketclose'], ...oldfields];
3314
- 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');
3315
- if (typeof _this.settings.pricetype !== 'undefined') url += '&pricingtype=' + _this.settings.pricetype;
3316
- if (_this.settings.adjusted == true) url += '&adjusted=1';
3317
- _this.settings.fields = oldfields;
3318
- if (_this.settings.xhr) {
3319
- getXhrJson(url);
3320
- } else {
3321
- millistream_data_api.fetch(url, function(data) {
3322
- _this.buildwidget(data);
3323
- });
3359
+ if (_this.settings.historylen) {
3360
+ var oldfields = _this.settings.fields;
3361
+ _this.settings.fields = [...['name', 'tradecurrency', 'date', 'closeprice', 'closequantity', 'marketopen', 'marketclose'], ...oldfields];
3362
+ 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');
3363
+ if (typeof _this.settings.pricetype !== 'undefined') url += '&pricingtype=' + _this.settings.pricetype;
3364
+ if (_this.settings.adjusted == true) url += '&adjusted=1';
3365
+ _this.settings.fields = oldfields;
3366
+ if (_this.settings.xhr) {
3367
+ getXhrJson(url);
3368
+ } else {
3369
+ millistream_data_api.fetch(url, function(data) {
3370
+ _this.buildwidget(data);
3371
+ });
3372
+ }
3324
3373
  }
3325
3374
  }
3326
3375
 
3327
3376
  _this.drawWidget = function() {
3328
-
3377
+ // remove standard fields from array, they will be requested anyway
3329
3378
  _this.settings.fields = _this.settings.fields.filter(function(obj) {
3330
3379
  return ['name', 'tradecurrency', 'time', 'date', 'tradeprice', 'tradequantity', 'marketopen', 'marketclose', 'closeprice1d', 'closeprice', 'closequantity'].indexOf(obj) == -1;
3331
3380
  });
@@ -3351,7 +3400,7 @@ function Milli_Chart(settings) {
3351
3400
  var e = new Date();
3352
3401
  var days = 0;
3353
3402
  var newlen = 0;
3354
- while (days < _this.settings.intradaylen - 1) {
3403
+ while (days < _this.settings.intradaylen - 1) { // include today
3355
3404
  d -= 86400000;
3356
3405
  e.setTime(d);
3357
3406
  if (e.getDay() != 0 && e.getDay() != 6)
@@ -3394,7 +3443,6 @@ function Milli_Chart(settings) {
3394
3443
 
3395
3444
  (function updatePixelRatio() {
3396
3445
  matchMedia(`(resolution: ${window.devicePixelRatio}dppx)`).addEventListener('change', updatePixelRatio, { once: true });
3397
- () => {};
3398
3446
  _this.drawChart();
3399
3447
  })();
3400
3448
 
@@ -3405,7 +3453,638 @@ function Milli_Chart(settings) {
3405
3453
  }
3406
3454
  });
3407
3455
  }
3408
- var milli_data_api_url = 'https://stage.millistream.com/widgets/3.0.3/data/milli_widget_dataapi.php?';
3456
+ function Milli_OptionsList(settings) {
3457
+ let _this = this;
3458
+ let requestid = null;
3459
+
3460
+ _this.settings = {
3461
+ autodraw: true,
3462
+ //fields: ['insref','symbol','derivativeindicator','diff1d','diff1dprc','openinterest', 'quantity', 'bidprice', 'askprice', 'lastprice','strikeprice','strikedate','isin','instrumenttype','expirationtype','dte'],
3463
+ fields: ['openinterest', 'quantity', 'bidprice', 'askprice', 'lastprice'],
3464
+ instrument: 772,
3465
+ instrumenttype: [5],
3466
+ instrumentsubtype: [0],
3467
+ messagetypes: 2,
3468
+ num_decimals: 2,
3469
+ onreadyCallback: null,
3470
+ streaming: false,
3471
+ target: null,
3472
+ flash: true,
3473
+ controlcolumn: 0,
3474
+ stylecolumn: null,
3475
+ strikedatefilter: [],
3476
+ expirationtypefilter: [],
3477
+ custom_columns: {},
3478
+ sortorder: 'asc',
3479
+ strikedateHeader: true,
3480
+ hidePuts: false
3481
+ };
3482
+ MillistreamWidgetApi_AssignObject(MillistreamWidgetSettings, _this.settings);
3483
+
3484
+ if (settings) {
3485
+ MillistreamWidgetApi_AssignObject(settings, _this.settings);
3486
+ }
3487
+
3488
+ _this.unsubscriptions = {};
3489
+ let m_instruments = new Map();
3490
+ let m_cellMap = new Map();
3491
+ let m_currentinsrefs = [];
3492
+ let m_pushfields = [];
3493
+ let m_strikes = [];
3494
+
3495
+ let m_strikepricedecimals = 2;
3496
+
3497
+ let m_lang_en = {
3498
+ askprice: 'Ask',
3499
+ bidprice: 'Bid',
3500
+ askquantity: 'Askquantity',
3501
+ bidquantity: 'Bidquantity',
3502
+ calls: 'CALLS',
3503
+ date: 'Date',
3504
+ dayhighprice: 'High',
3505
+ daylowprice: 'Low',
3506
+ diff1d: '+/-',
3507
+ diff1dprc: '%',
3508
+ lastprice: 'Last',
3509
+ openinterest: 'OI',
3510
+ quantity: 'Quantity',
3511
+ puts: 'PUTS',
3512
+ strikedate: 'Strike date',
3513
+ strikeprice: 'Strike price',
3514
+ symbol: 'Symbol',
3515
+ time: 'Time',
3516
+ rho: 'Rho',
3517
+ theta: 'Theta',
3518
+ delta: 'Delta',
3519
+ vega: 'Vega',
3520
+ gamma: 'Gamma',
3521
+ iv: 'IV',
3522
+ ivask: 'Ask IV',
3523
+ ivbid: 'Bid IV',
3524
+ weeklytype: '(w)',
3525
+ dte: 'DTE',
3526
+ strikes: 'Strikes'
3527
+ };
3528
+
3529
+ let m_lang_sv = {
3530
+ askprice: 'Sälj',
3531
+ bidprice: 'Köp',
3532
+ askquantity: 'Säljvolym',
3533
+ bidquantity: 'Köpvolym',
3534
+ calls: 'Köpoptioner',
3535
+ date: 'Datum',
3536
+ dayhighprice: 'Högst',
3537
+ daylowprice: 'Lägst',
3538
+ diff1d: '+/-',
3539
+ diff1dprc: '%',
3540
+ lastprice: 'Senast',
3541
+ openinterest: 'ÖB',
3542
+ puts: 'Säljoptioner',
3543
+ quantity: 'Volym',
3544
+ strikedate: 'Lösendag',
3545
+ strikeprice: 'Lösenpris',
3546
+ symbol: 'Kortnamn',
3547
+ time: 'Tid',
3548
+ rho: 'Rho',
3549
+ theta: 'Theta',
3550
+ delta: 'Delta',
3551
+ vega: 'Vega',
3552
+ gamma: 'Gamma',
3553
+ iv: 'IV',
3554
+ ivask: 'Sälj IV',
3555
+ ivbid: 'Köp IV',
3556
+ weeklytype: '(v)',
3557
+ dte: 'DTE',
3558
+ strikes: 'Lösenpris'
3559
+ };
3560
+
3561
+ _this.destroyWidget = function() {
3562
+ // if we have subscriptions send in an empty array to unsubscribe all and release it
3563
+ if (MillistreamWidgetApi_isObjectEmpty(_this.unsubscriptions) == false)
3564
+ _this.requestid = _this.settings.streaming.MillistreamWidgetStreamingApi_subscribeInstruments(_this, _this.requestid, []);
3565
+ return 0;
3566
+ };
3567
+
3568
+ _this.get_lang_text = function(string) {
3569
+ if (_this.settings.custom_lang && _this.settings.custom_lang[string]) return _this.settings.custom_lang[string];
3570
+ switch (_this.settings.language) {
3571
+ case 'sv':
3572
+ return m_lang_sv[string];
3573
+ case 'en':
3574
+ return m_lang_en[string];
3575
+ default:
3576
+ return string;
3577
+ }
3578
+ };
3579
+
3580
+ function add_custom_element(el, cl, parent, type, name, onclick, insref) {
3581
+ let element = document.createElement(el);
3582
+ if (cl) element.setAttribute("class", cl);
3583
+ if (parent) parent.appendChild(element);
3584
+ if (onclick) {
3585
+ element.onclick = (function(e) {
3586
+ _this.fire_custom_onclick(onclick, e, insref);
3587
+ });
3588
+ }
3589
+ if (type) element.type = type;
3590
+ if (name) element.value = name;
3591
+ return element;
3592
+ }
3593
+
3594
+ _this.fire_custom_onclick = function(onclick, e, insref) {
3595
+ let instr = m_instruments.get(insref);
3596
+ let obj = {};
3597
+ obj.event = e;
3598
+ obj.source = _this;
3599
+
3600
+ _this.settings.link_field.forEach(function(element) {
3601
+ let info = MillistreamWidgetApi_getColumnInfo(_this, element);
3602
+ if (typeof instr[info[0]] !== 'undefined') obj[element] = instr[info[0]]; // kolla om vi har push
3603
+ else if (typeof instr[element] !== 'undefined') obj[element] = instr[element];
3604
+ });
3605
+ onclick(obj);
3606
+ };
3607
+
3608
+
3609
+ _this.getStrikeDates = function() {
3610
+ return m_strikedates;
3611
+ };
3612
+
3613
+ function getNumDecimals(widget, value) {
3614
+ if (value == null) return 0;
3615
+ let parts = value.toString().split('.');
3616
+ if (parts.length == 2) {
3617
+ while (parts[1].charAt(parts[1].length - 1) == "0") { // remove trailing zeros
3618
+ parts[1] = parts[1].slice(0, -1);
3619
+ }
3620
+ return parts[1].length;
3621
+ }
3622
+ return 0;
3623
+ }
3624
+
3625
+ function sortOptions(resp) {
3626
+ let decimals = 0;
3627
+ let expirys = [];
3628
+
3629
+ for (i = 0; i < resp.instruments.length; i++) {
3630
+ let dec = getNumDecimals(_this, resp.instruments[i].strikeprice);
3631
+ decimals = decimals > dec ? decimals : dec;
3632
+
3633
+ m_instruments.set(resp.instruments[i].insref, resp.instruments[i]);
3634
+ let strike = null;
3635
+ if (typeof expirys[resp.instruments[i].strikedate] === 'undefined') {
3636
+ expirys[resp.instruments[i].strikedate] = 1;
3637
+ let strikedata = {};
3638
+ strikedata.strikedate = resp.instruments[i].strikedate;
3639
+ strikedata.expirationtype = resp.instruments[i].expirationtype;
3640
+ /*let date = new Date(resp.instruments[i].strikedate);
3641
+ let opts;
3642
+ switch (_this.settings.language) {
3643
+ case 'sv':
3644
+ opts = { day: 'numeric', month: 'short' };
3645
+ date = date.toLocaleDateString('sv-SE', opts);
3646
+ let parts = date.split(' ');
3647
+ date = parts[0] + ' ' + parts[1].substring(0, 3);
3648
+ break;
3649
+ default:
3650
+ opts = { month: 'short', day: 'numeric' };
3651
+ date = date.toLocaleDateString('en-US', opts);
3652
+ break;
3653
+ }
3654
+ //strikedata.date = date;*/
3655
+ strikedata.dte = resp.instruments[i].dte;
3656
+ m_strikedates.push(strikedata);
3657
+ }
3658
+ let f = 0;
3659
+ if (resp.instruments[i].strikeprice != null) {
3660
+ for (let s = 0; s < m_strikes.length; s++) {
3661
+ if (m_strikes[s].strikedate == resp.instruments[i].strikedate && m_strikes[s].strikeprice == resp.instruments[i].strikeprice) {
3662
+ strike = m_strikes[s];
3663
+ break;
3664
+ }
3665
+ }
3666
+ } else f = 1;
3667
+
3668
+ if (strike == null) {
3669
+ m_strikes.push({
3670
+ strikedate: resp.instruments[i].strikedate,
3671
+ strikeprice: resp.instruments[i].strikeprice,
3672
+ calls: null,
3673
+ puts: null,
3674
+ future: f
3675
+ });
3676
+ if (resp.instruments[i].expirationtype) m_strikes[m_strikes.length - 1].expirationtype = parseInt(resp.instruments[i].expirationtype);
3677
+ strike = m_strikes[m_strikes.length - 1];
3678
+ }
3679
+ if (resp.instruments[i].derivativeindicator == 0 || resp.instruments[i].derivativeindicator == 3) { // calls and futures
3680
+ strike.calls = resp.instruments[i];
3681
+ } else if (resp.instruments[i].derivativeindicator == 1) { // puts
3682
+ strike.puts = resp.instruments[i];
3683
+ }
3684
+ }
3685
+ m_strikepricedecimals = decimals == 1 ? 2 : decimals;
3686
+ m_strikedates.sort(function(a, b) {
3687
+ return a.strikedate.replace(/-/g, '') - b.strikedate.replace(/-/g, '');
3688
+ });
3689
+ m_strikes.sort(function(a, b) {
3690
+ if (a.strikedate == b.strikedate) {
3691
+ if (a.future == 1 || b.future == 1) {
3692
+ return (b.future - a.future);
3693
+ }
3694
+ return (a.strikeprice - b.strikeprice) * (_this.settings.sortorder == 'asc' ? 1 : -1);
3695
+ }
3696
+ return a.strikedate.replace(/-/g, '') - b.strikedate.replace(/-/g, '');
3697
+ });
3698
+ }
3699
+ _this.applyFilter = function() {
3700
+ check_which_strikes_to_show();
3701
+ };
3702
+
3703
+ function check_which_strikes_to_show() {
3704
+ if (m_strikes.length == 0)
3705
+ return;
3706
+ let strikedate = m_strikes[0].strikedate;
3707
+ let pos = 0;
3708
+ let newinsrefs = [];
3709
+ let s, h1, h2, i;
3710
+ for (i = 0; i < m_strikes.length; i++) {
3711
+ if (m_strikes[i].strikedate != strikedate) {
3712
+ if (_this.settings.strikedateHeader) {
3713
+ h1 = m_strikes[pos].row.parentNode.rows[m_strikes[pos].row.rowIndex - 1];
3714
+ h2 = m_strikes[pos].row.parentNode.rows[m_strikes[pos].row.rowIndex - 2];
3715
+ }
3716
+ if ((_this.settings.strikedatefilter.length != 0 && _this.settings.strikedatefilter.indexOf(strikedate) == -1) || (_this.settings.expirationtypefilter.length != 0 && _this.settings.expirationtypefilter.indexOf(m_strikes[i - 1].expirationtype) == -1) || typeof m_strikes[i].expirationtype === 'undefined') {
3717
+ if (_this.settings.strikedateHeader) {
3718
+ h1.style.display = 'none';
3719
+ h2.style.display = 'none';
3720
+ }
3721
+ for (s = pos; s < i; s++) {
3722
+ m_strikes[s].row.style.display = 'none';
3723
+ }
3724
+ } else {
3725
+ if (_this.settings.strikedateHeader) {
3726
+ h1.style.display = 'table-row';
3727
+ h2.style.display = 'table-row';
3728
+ }
3729
+ for (s = pos; s < i; s++) {
3730
+ m_strikes[s].row.style.display = 'table-row';
3731
+ if (m_strikes[s].calls != null) newinsrefs.push(parseInt(m_strikes[s].calls.insref));
3732
+ if (m_strikes[s].puts != null) newinsrefs.push(parseInt(m_strikes[s].puts.insref));
3733
+ }
3734
+ }
3735
+ pos = i;
3736
+ strikedate = m_strikes[i].strikedate;
3737
+ }
3738
+ }
3739
+ if (i != 0) {
3740
+ if (_this.settings.strikedateHeader) {
3741
+ h1 = m_strikes[pos].row.parentNode.rows[m_strikes[pos].row.rowIndex - 1];
3742
+ h2 = m_strikes[pos].row.parentNode.rows[m_strikes[pos].row.rowIndex - 2];
3743
+ }
3744
+ for (s = pos; s < i; s++) {
3745
+ if ((_this.settings.strikedatefilter.length != 0 && _this.settings.strikedatefilter.indexOf(m_strikes[s].strikedate) == -1) || (_this.settings.expirationtypefilter.length == 0 && _this.settings.expirationtypefilter.indexOf(m_strikes[s].expirationtype) != -1)) {
3746
+ if (_this.settings.strikedateHeader) {
3747
+ h1.style.display = 'none';
3748
+ h2.style.display = 'none';
3749
+ }
3750
+ for (s = pos; s < i; s++) {
3751
+ m_strikes[s].row.style.display = 'none';
3752
+ }
3753
+ continue;
3754
+ } else {
3755
+ if (_this.settings.strikedateHeader) {
3756
+ h1.style.display = 'table-row';
3757
+ h2.style.display = 'table-row';
3758
+ }
3759
+ }
3760
+ m_strikes[s].row.style.display = 'table-row';
3761
+ if (m_strikes[s].calls != null) newinsrefs.push(parseInt(m_strikes[s].calls.insref));
3762
+ if (m_strikes[s].puts != null) newinsrefs.push(parseInt(m_strikes[s].puts.insref));
3763
+ }
3764
+ }
3765
+
3766
+ if (_this.settings.streaming != false) {
3767
+ const sortedinsrefs = newinsrefs.slice().sort();
3768
+ let comp = (m_currentinsrefs.length === sortedinsrefs.length && m_currentinsrefs.slice().sort().every(function(value, index) {
3769
+ return value === sortedinsrefs[index];
3770
+ }));
3771
+ if (comp == false) {
3772
+ m_currentinsrefs = sortedinsrefs;
3773
+ _this.requestid = _this.settings.streaming.MillistreamWidgetStreamingApi_subscribeInstruments(_this, _this.requestid, m_currentinsrefs);
3774
+ }
3775
+ }
3776
+ }
3777
+
3778
+ _this.streamingCallback = function(insref, mref, json) {
3779
+ let keys = Object.keys(json);
3780
+ for (let s = 0; s < keys.length; s++) {
3781
+ if (m_pushfields.indexOf(parseInt(keys[s])) == -1) {
3782
+ continue; // not needed for display or link
3783
+ }
3784
+ let cellMap = m_cellMap.get(insref + ':' + keys[s]);
3785
+ if (cellMap) {
3786
+ let info = MillistreamWidgetApi_getColumnInfo(_this, keys[s]);
3787
+ _this.settings.stylecolumn = cellMap.stylecolumn;
3788
+ _this.settings.controlcolumn = cellMap.controlcolumn;
3789
+ print_field(_this, cellMap.element, info[0], json[info[0]], _this.settings.num_decimals);
3790
+ }
3791
+ }
3792
+ };
3793
+
3794
+ function buildlist(resp) {
3795
+ m_cellMap.clear();
3796
+ m_instruments.clear();
3797
+ m_strikedates = [];
3798
+ m_strikeprices = [];
3799
+ sortOptions(resp);
3800
+ if (typeof _this.settings.onData !== 'undefined') _this.settings.onData();
3801
+
3802
+ if (m_strikedates.length != 0) {
3803
+ let table = MillistreamWidgetApi_addElement(_this, 'table', 'millistream-optionslist-table', _this.settings.target);
3804
+ let pos = 0;
3805
+ let info;
3806
+ let callheader = null;
3807
+ let putheader = null;
3808
+ let tbody = MillistreamWidgetApi_addElement(_this, 'tbody', null, table);
3809
+ let i;
3810
+ for (i = 0; i < _this.settings.fields.length; i++) {
3811
+ let f = MillistreamWidgetApi_getColumnInfo(_this, _this.settings.fields[i]);
3812
+ if (-1 == m_pushfields.indexOf(f[0])) m_pushfields.push(f[0]);
3813
+ }
3814
+ if (m_strikedates.length == 0) return;
3815
+ for (let s = 0; s < m_strikedates.length; s++) {
3816
+ let display = '';
3817
+ let tr;
3818
+ if (_this.settings.strikedateHeader) {
3819
+ tr = MillistreamWidgetApi_addElement(_this, 'tr', null, tbody);
3820
+ tr.setAttribute('data-strikedate', m_strikedates[s].strikedate);
3821
+ if (_this.settings.strikedatefilter.length != 0 && _this.settings.strikedatefilter.indexOf(m_strikedates[s].strikedate) == -1) {
3822
+ tr.style.display = 'none';
3823
+ display = 'none';
3824
+ }
3825
+ callheader = MillistreamWidgetApi_addElement(_this, 'th', 'millistream-optionslist-header-calls' + ' millistream-string', tr, null, null);
3826
+ putheader = MillistreamWidgetApi_addElement(_this, 'th', 'millistream-optionslist-header-puts' + ' millistream-string', tr, null, null);
3827
+ } else if (_this.settings.strikedatefilter.length != 0 && _this.settings.strikedatefilter.indexOf(m_strikedates[s].strikedate) == -1) {
3828
+ display = 'none';
3829
+ }
3830
+ tr = MillistreamWidgetApi_addElement(_this, 'tr', 'millistream-optionslist-options-table-header', tbody);
3831
+
3832
+ let cpos, added_columns = 0;
3833
+
3834
+ if (display == 'none') tr.style.display = 'none';
3835
+ for (i = 0; i < _this.settings.fields.length; i++) {
3836
+ for (cpos in _this.settings.custom_columns) {
3837
+ if (cpos == added_columns) {
3838
+ MillistreamWidgetApi_addElement(_this, 'th', 'millistream-optionslist-table-th', tr, null, _this.settings.custom_columns[cpos].name);
3839
+ added_columns++;
3840
+ }
3841
+ }
3842
+ info = MillistreamWidgetApi_getColumnInfo(_this, _this.settings.fields[i]);
3843
+ th = MillistreamWidgetApi_addElement(_this, 'th', 'millistream-optionslist-table-th millistream-' + info[1] + ' millistream-' + _this.settings.fields[i], tr, null, info[3]);
3844
+ added_columns++;
3845
+ }
3846
+ for (cpos in _this.settings.custom_columns) {
3847
+ if (cpos == added_columns) {
3848
+ MillistreamWidgetApi_addElement(_this, 'th', 'millistream-optionslist-table-th', tr, null, this.settings.custom_columns[cpos].name);
3849
+ added_columns++;
3850
+ }
3851
+ }
3852
+ th = MillistreamWidgetApi_addElement(_this, 'th', 'millistream-optionslist-table-th millistream-optionslist-yheader millistream-sortable-cursor millistream-sorting-' + _this.settings.sortorder, tr);
3853
+ th.innerHTML = _this.get_lang_text('strikes');
3854
+ th.onclick = (function(e) {
3855
+ _this.settings.sortorder = _this.settings.sortorder == 'asc' ? 'desc' : 'asc';
3856
+ let tmp = [];
3857
+ let first = 0; // ignore first header and future
3858
+ while (first < table.childNodes[0].childNodes.length) {
3859
+ if (table.childNodes[0].childNodes[first].childNodes[0].nodeName == 'TH') {
3860
+ let offset = 0;
3861
+ if (!table.childNodes[0].childNodes[first].classList.contains('millistream-optionslist-options-table-header'))
3862
+ offset = 1;
3863
+ table.childNodes[0].childNodes[first + offset].cells[e.srcElement.cellIndex].classList.remove('millistream-sorting-' + (_this.settings.sortorder == 'asc' ? 'desc' : 'asc'));
3864
+ table.childNodes[0].childNodes[first + offset].cells[e.srcElement.cellIndex].classList.add('millistream-sorting-' + _this.settings.sortorder);
3865
+ for (s = 0; s < tmp.length; s++) {
3866
+ table.childNodes[0].insertBefore(tmp[s], table.childNodes[0].childNodes[first + offset]);
3867
+ }
3868
+ first = first + tmp.length + 1 + offset;
3869
+ tmp = [];
3870
+ }
3871
+ tmp.push(table.childNodes[0].childNodes[first]);
3872
+ table.childNodes[0].removeChild(table.childNodes[0].childNodes[first]);
3873
+ }
3874
+ if (tmp.length > 0) {
3875
+ for (s = 0; s < tmp.length; s++) {
3876
+ table.childNodes[0].insertBefore(tmp[s], table.childNodes[0].childNodes[first]);
3877
+ }
3878
+ }
3879
+ m_strikes.sort(function(a, b) {
3880
+ if (a.strikedate == b.strikedate) {
3881
+ return (a.strikeprice - b.strikeprice) * (_this.settings.sortorder == 'asc' ? 1 : -1);
3882
+ }
3883
+ return a.strikedate.replace(/-/g, '') - b.strikedate.replace(/-/g, '');
3884
+ });
3885
+ });
3886
+
3887
+ cpos = 0;
3888
+ //added_columns = 0;
3889
+ if (_this.settings.hidePuts == false) {
3890
+ for (i = _this.settings.fields.length - 1; i >= 0; i--) {
3891
+ // flip bid and ask for puts
3892
+ if (_this.settings.fields[i] == 'bidprice' && _this.settings.fields[i].indexOf('askprice') != 0) {
3893
+ info = MillistreamWidgetApi_getColumnInfo(_this, 'askprice');
3894
+ MillistreamWidgetApi_addElement(_this, 'th', 'millistream-optionslist-table-th millistream-' + info[1] + ' millistream-askprice', tr, null, info[3]);
3895
+ } else
3896
+ if (_this.settings.fields[i] == 'askprice' && _this.settings.fields[i].indexOf('bidprice') != 0) {
3897
+ info = MillistreamWidgetApi_getColumnInfo(_this, 'bidprice');
3898
+ MillistreamWidgetApi_addElement(_this, 'th', 'millistream-optionslist-table-th millistream-' + info[1] + ' millistream-bidprice', tr, null, info[3]);
3899
+ } else {
3900
+ info = MillistreamWidgetApi_getColumnInfo(_this, _this.settings.fields[i]);
3901
+ MillistreamWidgetApi_addElement(_this, 'th', 'millistream-optionslist-table-th millistream-' + info[1] + ' millistream-' + _this.settings.fields[i], tr, null, info[3]);
3902
+ }
3903
+ for (cpos in _this.settings.custom_columns) {
3904
+ if (cpos == i + 1) {
3905
+ MillistreamWidgetApi_addElement(_this, 'th', 'millistream-optionslist-table-th', tr, null, _this.settings.custom_columns[cpos].name);
3906
+ added_columns++;
3907
+ }
3908
+ }
3909
+ added_columns++;
3910
+ }
3911
+ for (cpos in _this.settings.custom_columns) {
3912
+ if (cpos == i + 1) {
3913
+ MillistreamWidgetApi_addElement(_this, 'th', 'millistream-optionslist-table-th', tr, null, _this.settings.custom_columns[cpos].name);
3914
+ added_columns++;
3915
+ }
3916
+ }
3917
+ }
3918
+ let numcalls = 0;
3919
+ let numputs = 0;
3920
+ let td;
3921
+ let x;
3922
+ for (i = pos; i < m_strikes.length; i++) {
3923
+ let cellMap;
3924
+ if (m_strikeprices.indexOf(m_strikes[i].strikeprice) == -1) m_strikeprices.push(m_strikes[i].strikeprice);
3925
+ if (m_strikes[i].strikedate == m_strikedates[s].strikedate) {
3926
+ added_columns = 0;
3927
+ let otr = MillistreamWidgetApi_addElement(_this, 'tr', 'millistream-optionlist-row', tbody);
3928
+ otr.onclick = function(e) {
3929
+ if (typeof _this.settings.onRowClick === 'function') {
3930
+ if (e.srcElement.nodeName == 'TD') {
3931
+ if (e.srcElement.cellIndex < _this.settings.fields.length + Object.keys(_this.settings.custom_columns).length) {
3932
+ if (e.srcElement.parentNode.getAttribute('call') !== null)
3933
+ _this.settings.onRowClick(e.srcElement.parentNode.getAttribute('call'));
3934
+ } else
3935
+ if (e.srcElement.cellIndex > _this.settings.fields.length + Object.keys(_this.settings.custom_columns).length) {
3936
+ if (e.srcElement.parentNode.getAttribute('put') !== null)
3937
+ _this.settings.onRowClick(e.srcElement.parentNode.getAttribute('put'));
3938
+ }
3939
+ return;
3940
+ }
3941
+ }
3942
+ };
3943
+ if (display == 'none') otr.style.display = 'none';
3944
+ m_strikes[i].row = otr;
3945
+ if (m_strikes[i].calls) numcalls++;
3946
+ for (x = 0; x < _this.settings.fields.length; x++) {
3947
+ for (cpos in _this.settings.custom_columns) {
3948
+ if (cpos == added_columns) {
3949
+ td = MillistreamWidgetApi_addTableCell2(_this, null, 'millistream-optionslist-call-cell', otr);
3950
+ if (m_strikes[i].calls && (typeof _this.settings.custom_columns[cpos].condition !== 'function' || _this.settings.custom_columns[cpos].condition(m_strikes[i].calls))) {
3951
+ if (_this.settings.custom_columns[cpos].instruments && -1 != _this.settings.custom_columns[cpos].instruments.indexOf(m_strikes[i].insref)) {
3952
+ add_custom_element(_this.settings.custom_columns[cpos].element, _this.settings.custom_columns[cpos].alternate_class, td, _this.settings.custom_columns[cpos].type, _this.settings.custom_columns[cpos].name, _this.settings.custom_columns[cpos].onclick, m_strikes[i].calls.insref);
3953
+ } else {
3954
+ add_custom_element(_this.settings.custom_columns[cpos].element, _this.settings.custom_columns[cpos].class, td, _this.settings.custom_columns[cpos].type, _this.settings.custom_columns[cpos].name, _this.settings.custom_columns[cpos].onclick, m_strikes[i].calls.insref);
3955
+ }
3956
+ }
3957
+ added_columns++;
3958
+ }
3959
+ }
3960
+
3961
+ info = MillistreamWidgetApi_getColumnInfo(_this, _this.settings.fields[x]);
3962
+ td = MillistreamWidgetApi_addTableCell2(_this, _this.settings.fields[x], 'millistream-' + info[1] + ' millistream-optionslist-call-cell ' + ' millistream-' + _this.settings.fields[x], otr, m_strikes[i].calls);
3963
+ if (m_strikes[i].calls) {
3964
+ otr.setAttribute('call', m_strikes[i].calls.insref);
3965
+ cellMap = {
3966
+ insref: m_strikes[i].calls.insref,
3967
+ element: td,
3968
+ stylecolumn: _this.settings.stylecolumn,
3969
+ controlcolumn: _this.settings.controlcolumn
3970
+ };
3971
+ m_cellMap.set(cellMap.insref + ':' + info[0], cellMap);
3972
+ }
3973
+ added_columns++;
3974
+ }
3975
+ for (cpos in _this.settings.custom_columns) {
3976
+ if (cpos == added_columns) {
3977
+ td = MillistreamWidgetApi_addTableCell2(_this, null, 'millistream-optionslist-call-cell', otr);
3978
+ if (m_strikes[i].calls) {
3979
+ if (_this.settings.custom_columns[cpos].instruments && -1 != _this.settings.custom_columns[cpos].instruments.indexOf(m_strikes[i].insref)) {
3980
+ add_custom_element(_this.settings.custom_columns[cpos].element, _this.settings.custom_columns[cpos].alternate_class, td, _this.settings.custom_columns[cpos].type, _this.settings.custom_columns[cpos].name, _this.settings.custom_columns[cpos].onclick, m_strikes[i].calls.insref);
3981
+ } else {
3982
+ add_custom_element(_this.settings.custom_columns[cpos].element, _this.settings.custom_columns[cpos].class, td, _this.settings.custom_columns[cpos].type, _this.settings.custom_columns[cpos].name, _this.settings.custom_columns[cpos].onclick, m_strikes[i].calls.insref);
3983
+ }
3984
+ }
3985
+ added_columns++;
3986
+ }
3987
+ }
3988
+ // add strike column
3989
+ td = MillistreamWidgetApi_addElement(_this, 'td', 'millistream-optionslist-yheader millistream-numeric', otr);
3990
+ td.innerHTML = m_strikes[i].strikeprice == null ? 'Fut | Fwd' : formatNiceNumber(m_strikes[i].strikeprice, _this.settings.thousandseparator, _this.settings.decimalseparator, m_strikepricedecimals);
3991
+
3992
+ if (m_strikes[i].puts) numputs++;
3993
+ let field = null;
3994
+ if (_this.settings.hidePuts == false) {
3995
+ for (x = _this.settings.fields.length - 1; x >= 0; x--) {
3996
+ // flip bid and ask for puts
3997
+
3998
+ field = _this.settings.fields[x];
3999
+ if (_this.settings.fields[x] == 'bidprice' && _this.settings.fields[x].indexOf('askprice') != 0) {
4000
+ info = MillistreamWidgetApi_getColumnInfo(_this, 'askprice');
4001
+ field = 'askprice';
4002
+ } else
4003
+ if (_this.settings.fields[x] == 'askprice' && _this.settings.fields[x].indexOf('bidprice') != 0) {
4004
+ info = MillistreamWidgetApi_getColumnInfo(_this, 'bidprice');
4005
+ field = 'bidprice';
4006
+ } else
4007
+ info = MillistreamWidgetApi_getColumnInfo(_this, _this.settings.fields[x]);
4008
+
4009
+ td = MillistreamWidgetApi_addTableCell2(_this, field, 'millistream-' + info[1] + ' millistream-optionslist-put-cell ' + ' millistream-' + field, otr, m_strikes[i].puts);
4010
+ if (m_strikes[i].puts) {
4011
+ otr.setAttribute('put', m_strikes[i].puts.insref);
4012
+ cellMap = {
4013
+ insref: m_strikes[i].puts.insref,
4014
+ element: td,
4015
+ stylecolumn: _this.settings.stylecolumn == null ? null : _this.settings.stylecolumn.map(x => added_columns + _this.settings.fields.length - x + 2),
4016
+ controlcolumn: _this.settings.controlcolumn == null ? null : added_columns + _this.settings.fields.length - _this.settings.controlcolumn + 2,
4017
+ };
4018
+ m_cellMap.set(cellMap.insref + ':' + info[0], cellMap);
4019
+ }
4020
+ for (cpos in _this.settings.custom_columns) {
4021
+ if (cpos == x + 1) {
4022
+ td = MillistreamWidgetApi_addTableCell2(_this, null, 'millistream-optionslist-put-cell', otr);
4023
+ if (m_strikes[i].puts && (typeof _this.settings.custom_columns[cpos].condition !== 'function' || _this.settings.custom_columns[cpos].condition(m_strikes[i].puts))) {
4024
+ if (_this.settings.custom_columns[cpos].instruments && -1 != _this.settings.custom_columns[cpos].instruments.indexOf(m_strikes[i].insref)) {
4025
+ add_custom_element(_this.settings.custom_columns[cpos].element, _this.settings.custom_columns[cpos].alternate_class, td, _this.settings.custom_columns[cpos].type, _this.settings.custom_columns[cpos].name, _this.settings.custom_columns[cpos].onclick, m_strikes[i].puts.insref);
4026
+ } else {
4027
+ add_custom_element(_this.settings.custom_columns[cpos].element, _this.settings.custom_columns[cpos].class, td, _this.settings.custom_columns[cpos].type, _this.settings.custom_columns[cpos].name, _this.settings.custom_columns[cpos].onclick, m_strikes[i].puts.insref);
4028
+ }
4029
+ }
4030
+ added_columns++;
4031
+ }
4032
+ }
4033
+ }
4034
+ for (cpos in _this.settings.custom_columns) {
4035
+ if (cpos == x + 1) {
4036
+ td = MillistreamWidgetApi_addTableCell2(_this, null, 'millistream-optionslist-put-cell', otr);
4037
+ if (m_strikes[i].puts && (typeof _this.settings.custom_columns[cpos].condition !== 'function' || _this.settings.custom_columns[cpos].condition(m_strikes[i].puts))) {
4038
+ if (_this.settings.custom_columns[cpos].instruments && -1 != _this.settings.custom_columns[cpos].instruments.indexOf(m_strikes[i].insref)) {
4039
+ add_custom_element(_this.settings.custom_columns[cpos].element, _this.settings.custom_columns[cpos].alternate_class, td, _this.settings.custom_columns[cpos].type, _this.settings.custom_columns[cpos].name, _this.settings.custom_columns[cpos].onclick, m_strikes[i].puts.insref);
4040
+ } else {
4041
+ add_custom_element(_this.settings.custom_columns[cpos].element, _this.settings.custom_columns[cpos].class, td, _this.settings.custom_columns[cpos].type, _this.settings.custom_columns[cpos].name, _this.settings.custom_columns[cpos].onclick, m_strikes[i].puts.insref);
4042
+ }
4043
+ }
4044
+ added_columns++;
4045
+ }
4046
+ }
4047
+ }
4048
+ } else break;
4049
+ }
4050
+ if (_this.settings.strikedateHeader) {
4051
+ callheader.innerHTML = _this.get_lang_text('calls') + ' · ' + m_strikedates[s].strikedate + ' ' + (m_strikedates[s].expirationtype == '2' ? _this.get_lang_text('weeklytype') : ' ') + ' · ' + m_strikedates[s].dte + ' ' + _this.get_lang_text('dte') + ' · ' + numcalls + ' strikes';
4052
+ console.log(callheader.innerHTML);
4053
+ callheader.colSpan = _this.settings.fields.length + 1 + Object.keys(_this.settings.custom_columns).length;
4054
+ putheader.innerHTML = _this.get_lang_text('puts') + ' · ' + m_strikedates[s].strikedate + ' ' + (m_strikedates[s].expirationtype == '2' ? _this.get_lang_text('weeklytype') : ' ') + ' · ' + m_strikedates[s].dte + ' ' + _this.get_lang_text('dte') + ' · ' + numputs + ' strikes';
4055
+ putheader.colSpan = _this.settings.fields.length + Object.keys(_this.settings.custom_columns).length;
4056
+ }
4057
+ pos = i;
4058
+ }
4059
+ check_which_strikes_to_show();
4060
+ }
4061
+ if (_this.settings.onreadyCallback) _this.settings.onreadyCallback();
4062
+ }
4063
+
4064
+
4065
+ _this.drawWidget = function() {
4066
+
4067
+ if (MillistreamWidgetApi_isObjectEmpty(_this.unsubscriptions) == false)
4068
+ _this.requestid = _this.settings.streaming.MillistreamWidgetStreamingApi_subscribeInstruments(_this, _this.requestid, []);
4069
+
4070
+ if (_this.settings.target) {
4071
+ _this.settings.target.innerHTML = '';
4072
+ }
4073
+
4074
+ m_strikes = [];
4075
+ m_pushfields = [];
4076
+ m_currentinsrefs = [];
4077
+ m_cellMap = new Map();
4078
+
4079
+ let url = MillistreamWidgetApi_buildQuery(_this, 'optionslist');
4080
+ millistream_data_api.fetch(url, function(data) {
4081
+ buildlist(data);
4082
+ });
4083
+ };
4084
+ if (this.settings.autodraw == true) this.drawWidget();
4085
+
4086
+ }
4087
+ var milli_data_api_url = 'https://stage.millistream.com/widgets/3.0.4/data/milli_widget_dataapi.php?';
3409
4088
 
3410
4089
  var millistream_data_api = {
3411
4090
  callbackcounter: 0,
@@ -3453,14 +4132,14 @@ function MillistreamWidgetApi_buildQuery(widget, type) {
3453
4132
  if (typeof widget.settings.instrumenttype !== 'object') {
3454
4133
  throw new Error(widget.constructor.name + ': instrumenttype is not valid');
3455
4134
  }
3456
-
4135
+ //if (widget.settings.instrument == null) // removed 2021-10-12 for "mylist" functionality
3457
4136
  url += '&instrumenttypes=' + widget.settings.instrumenttype.join();
3458
4137
  }
3459
4138
  if (widget.settings.instrumentsubtype != null) {
3460
4139
  if (typeof widget.settings.instrumentsubtype !== 'object') {
3461
4140
  throw new Error(widget.constructor.name + ': instrumentsubtype is not valid');
3462
4141
  }
3463
-
4142
+ //if (widget.settings.instrument == null) // removed 2021-10-12 for "mylist" functionality
3464
4143
  url += '&instrumentsubtypes=' + widget.settings.instrumentsubtype.join();
3465
4144
  }
3466
4145
  if (widget.settings.derivativeindicator != null) {
@@ -3570,10 +4249,10 @@ function MillistreamWidgetApi_buildQuery(widget, type) {
3570
4249
  }
3571
4250
  }
3572
4251
  if (typeof widget.settings.headerinterval === 'string' && widget.settings.headerinterval == 'instrumenttype') {
3573
- if (widget.settings.fields.indexOf('instrumenttype') == -1) {
4252
+ if (widget.settings.fields.indexOf('instrumenttype') == -1 && widget.settings.link_field.indexOf('instrumenttype') == -1) {
3574
4253
  url += ',instrumenttype';
3575
4254
  }
3576
- if (widget.settings.fields.indexOf('instrumentsubtype') == -1) {
4255
+ if (widget.settings.fields.indexOf('instrumentsubtype') == -1 && widget.settings.link_field.indexOf('instrumentsubtype') == -1) {
3577
4256
  url += ',instrumentsubtype';
3578
4257
  }
3579
4258
  }
@@ -3696,7 +4375,7 @@ function MillistreamWidgetApi_buildQuery(widget, type) {
3696
4375
  if (typeof widget.settings.fundcompany !== 'object' && widget.settings.fundcompany !== null) throw new Error(widget.constructor.name + ': fundcompany is not valid');
3697
4376
  url += '&fundcompany=' + widget.settings.fundcompany.join(',');
3698
4377
  }
3699
- if (typeof widget.settings.expirationtype !== 'undefined') {
4378
+ if (typeof widget.settings.expirationtype !== 'undefined' && widget.settings.expirationtype != null) {
3700
4379
  if (typeof widget.settings.expirationtype !== 'number' && widget.settings.expirationtype !== null) throw new Error(widget.constructor.name + ': expirationtype is not valid');
3701
4380
  url += '&expirationtype=' + widget.settings.expirationtype;
3702
4381
  }
@@ -3747,7 +4426,7 @@ function MillistreamWidgetApi_buildQuery(widget, type) {
3747
4426
  if (typeof widget.settings.xhr !== 'undefined' && widget.settings.xhr == true) {
3748
4427
  url += '&xhr=1';
3749
4428
  }
3750
-
4429
+ console.log(url);
3751
4430
  return url;
3752
4431
  }
3753
4432
 
@@ -3809,12 +4488,12 @@ function MillistreamWidgetApi_addPagination(widget) {
3809
4488
  li.onclick = function() {
3810
4489
  MillistreamWidgetApi_getPaginationPage(widget, 'next');
3811
4490
  };
3812
- if (widget.pagination.numPages < max + 1) li.style.display = 'none';
4491
+ if (widget.pagination.numPages < max + 1) li.style.display = 'none'; // dont show if less than 6 pages
3813
4492
  li = MillistreamWidgetApi_addElement(widget, 'li', 'millistream-list-pagination-li', widget.pagination.ul, null, '>>');
3814
4493
  li.onclick = function() {
3815
4494
  MillistreamWidgetApi_getPaginationPage(widget, 'last');
3816
4495
  };
3817
- if (widget.pagination.numPages < max + 1) li.style.display = 'none';
4496
+ if (widget.pagination.numPages < max + 1) li.style.display = 'none'; // dont show if less than 6 pages
3818
4497
  }
3819
4498
  } else
3820
4499
  if (widget.settings.pagination > 0 && widget.pagination.numPages < 2) {
@@ -3882,11 +4561,11 @@ function MillistreamWidgetApi_getPaginationPage(widget, page) {
3882
4561
  startno = 1;
3883
4562
  } else
3884
4563
  if (widget.pagination.selectedPage > widget.pagination.numPages - 2) {
3885
- startno = widget.pagination.numPages - (max - 1);
4564
+ startno = widget.pagination.numPages - (max - 1); //4;
3886
4565
 
3887
4566
  } else {
3888
4567
  startno = widget.pagination.selectedPage - 2 < 1 ? 1 : widget.pagination.selectedPage - (max - Math.ceil(max / 2));
3889
-
4568
+ //startno = widget.pagination.selectedPage - 1;
3890
4569
  }
3891
4570
  for (i = 2; i < items.length - 2; i++) {
3892
4571
  items[i].innerHTML = (startno);
@@ -3925,15 +4604,15 @@ function MillistreamWidgetApi_getElementHeight(el) {
3925
4604
  return rect.height + s;
3926
4605
  }
3927
4606
 
3928
-
4607
+ // Push blipp funktioner
3929
4608
  function MillistreamWidgetApi_clearFlash(el) {
3930
-
4609
+ //internal and external
3931
4610
  el.classList.remove('millistream-flash-up');
3932
4611
  el.classList.remove('millistream-flash-down');
3933
4612
  }
3934
4613
 
3935
4614
  function milli_clearValuedFlash(widget, el, oldValue) {
3936
-
4615
+ // internal borde gå att bygga bort
3937
4616
  var currentValue = MillistreamWidgetApi_getElementNumber(widget, el);
3938
4617
  if (currentValue == oldValue || currentValue == 0) {
3939
4618
  MillistreamWidgetApi_clearFlash(el);
@@ -3941,7 +4620,7 @@ function milli_clearValuedFlash(widget, el, oldValue) {
3941
4620
  }
3942
4621
 
3943
4622
  function MillistreamWidgetApi_flashElement(widget, el, newValue, oldValue) {
3944
-
4623
+ // internal
3945
4624
  if (newValue == oldValue) return;
3946
4625
  MillistreamWidgetApi_clearFlash(el);
3947
4626
  if (newValue == '' || !newValue) return;
@@ -3960,11 +4639,14 @@ function MillistreamWidgetApi_flashElement(widget, el, newValue, oldValue) {
3960
4639
  }
3961
4640
 
3962
4641
 
3963
-
4642
+ // numeriska funktioner
3964
4643
  function MillistreamWidgetApi_isNumber(widget, testsubject) {
3965
4644
  if (!testsubject) return;
3966
- var n = testsubject.replace(widget.settings.decimalseparator, '.').split(widget.settings.thousandseparator).join('');
3967
- return !isNaN(parseFloat(n)) && isFinite(n);
4645
+ if(isNaN(testsubject)) {
4646
+ var n = testsubject.replace(widget.settings.decimalseparator, '.').split(widget.settings.thousandseparator).join('');
4647
+ return !isNaN(parseFloat(n)) && isFinite(n);
4648
+ }
4649
+ return !isNaN(parseFloat(testsubject)) && isFinite(testsubject);
3968
4650
  }
3969
4651
 
3970
4652
  function MillistreamWidgetApi_getNumDecimals(widget, value, current, validfields) {
@@ -3973,7 +4655,7 @@ function MillistreamWidgetApi_getNumDecimals(widget, value, current, validfields
3973
4655
  if (value == null || MillistreamWidgetApi_isNumber(widget, value) == false) return current;
3974
4656
  var parts = value.toString().split('.');
3975
4657
  if (parts.length == 2) {
3976
- while (parts[1].charAt(parts[1].length - 1) == "0") {
4658
+ while (parts[1].charAt(parts[1].length - 1) == "0") { // remove trailing zeros
3977
4659
  parts[1] = parts[1].slice(0, -1);
3978
4660
  }
3979
4661
  return current > parts[1].length ? current : parts[1].length;
@@ -3982,7 +4664,7 @@ function MillistreamWidgetApi_getNumDecimals(widget, value, current, validfields
3982
4664
  }
3983
4665
 
3984
4666
  function MillistreamWidgetApi_getElementNumber(widget, el) {
3985
-
4667
+ // internal and Orderbook
3986
4668
  var res = parseFloat(el.innerHTML.replace(widget.settings.decimalseparator, '.').split(widget.settings.thousandseparator).join(''));
3987
4669
  if (!isNaN(parseFloat(res)) && isFinite(res)) return res;
3988
4670
  return 0;
@@ -4013,7 +4695,7 @@ function MillistreamWidgetApi_colorCell(widget, element, info) {
4013
4695
  MillistreamWidgetApi_setCellColor(widget, element, v);
4014
4696
  }
4015
4697
  } else
4016
- if (widget.settings.controlcolumn || widget.settings.controlcolumn == 0) {
4698
+ if (widget.settings.controlcolumn || widget.settings.controlcolumn == 0) { // works for tables
4017
4699
  if (widget.settings.stylecolumn === null) return;
4018
4700
  var tr = element.parentNode;
4019
4701
  while (tr.tagName.toLowerCase() != 'tr') {
@@ -4022,13 +4704,13 @@ function MillistreamWidgetApi_colorCell(widget, element, info) {
4022
4704
  if (tr.cells.length > widget.settings.controlcolumn) {
4023
4705
  v = MillistreamWidgetApi_getElementNumber(widget, tr.cells[widget.settings.controlcolumn]);
4024
4706
  var el;
4025
- if (widget.settings.stylecolumn && widget.settings.stylecolumn[0] == -1) {
4026
- el = tr;
4707
+ if (widget.settings.stylecolumn && widget.settings.stylecolumn[0] == -1) { // color row
4708
+ el = tr; //element.parentNode;
4027
4709
  MillistreamWidgetApi_setCellColor(widget, tr, v);
4028
4710
 
4029
4711
  } else {
4030
4712
  for (var s = 0; s < widget.settings.stylecolumn.length; s++) {
4031
- el = tr.cells[widget.settings.stylecolumn[s]];
4713
+ el = tr.cells[widget.settings.stylecolumn[s]]; //element.parentNode.cells[widget.stylecolumn[s]];
4032
4714
  if (el) {
4033
4715
  MillistreamWidgetApi_setCellColor(widget, el, v);
4034
4716
  }
@@ -4036,17 +4718,17 @@ function MillistreamWidgetApi_colorCell(widget, element, info) {
4036
4718
  }
4037
4719
  }
4038
4720
  } else
4039
- if (widget.settings.positiveclass && widget.settings.negativeclass) {
4721
+ if (widget.settings.positiveclass && widget.settings.negativeclass) { // non table elements
4040
4722
  v = MillistreamWidgetApi_getElementNumber(widget, element);
4041
4723
  MillistreamWidgetApi_setCellColor(widget, element, v);
4042
4724
  }
4043
4725
  }
4044
4726
 
4045
4727
  function print_field(widget, element, field, value, overridedecimals) {
4046
-
4728
+ // internal and external
4047
4729
  var f = parseInt(field);
4048
4730
  var info = MillistreamWidgetApi_getColumnInfo(widget, f.toString());
4049
- if (typeof value === 'undefined' || value == null || (!value && isNaN(value) == true)) {
4731
+ if (typeof value === 'undefined' || value == null || (!value && isNaN(value) == true)) { // kolla field?
4050
4732
  if (info[4] & 16) {
4051
4733
  value = '0.0';
4052
4734
  } else {
@@ -4092,7 +4774,7 @@ function print_field(widget, element, field, value, overridedecimals) {
4092
4774
  else
4093
4775
  element.innerHTML = formatFactorNumber(value, widget.settings.factor, widget.settings.num_decimals, widget.settings.thousandseparator, widget.settings.decimalseparator);
4094
4776
  } else if (info[4] & 4)
4095
- element.innerHTML = formatNiceNumber(value, widget.settings.thousandseparator, widget.settings.decimalseparator, 0);
4777
+ element.innerHTML = formatNiceNumber(value, widget.settings.thousandseparator, widget.settings.decimalseparator, 0); // no decimals
4096
4778
  else if (info[4] & 1 && overridedecimals)
4097
4779
  element.innerHTML = formatNiceNumber(value, widget.settings.thousandseparator, widget.settings.decimalseparator, overridedecimals || widget.settings.num_decimals);
4098
4780
  else {
@@ -4110,8 +4792,8 @@ function print_field(widget, element, field, value, overridedecimals) {
4110
4792
  }
4111
4793
 
4112
4794
  function MillistreamWidgetApi_getColumnInfo(widget, name) {
4113
-
4114
-
4795
+ // internal and external
4796
+ // 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
4115
4797
  switch (name) {
4116
4798
  case '222':
4117
4799
  case 'accountsreceivable':
@@ -4202,7 +4884,7 @@ function MillistreamWidgetApi_getColumnInfo(widget, name) {
4202
4884
  return [232, 'numeric', 'right', widget.get_lang_text(name) || name, 8];
4203
4885
  case '404':
4204
4886
  case 'd1':
4205
- return [404, 'date', 'right', widget.get_lang_text(name) || name, 0];
4887
+ return [404, 'date', 'right', widget.get_lang_text(name) || name, 0]; // Security type
4206
4888
  case '3':
4207
4889
  case 'date':
4208
4890
  return [3, 'date', 'right', widget.get_lang_text(name) || name, 0];
@@ -4456,10 +5138,10 @@ function MillistreamWidgetApi_getColumnInfo(widget, name) {
4456
5138
  return [229, 'numeric', 'right', widget.get_lang_text(name) || name, 8];
4457
5139
  case '395':
4458
5140
  case 'n2':
4459
- return [395, 'numeric', 'left', widget.get_lang_text(name) || name, 0];
5141
+ return [395, 'numeric', 'left', widget.get_lang_text(name) || name, 0]; // Security type
4460
5142
  case '396':
4461
5143
  case 'n3':
4462
- return [396, 'numeric', 'left', widget.get_lang_text(name) || name, 0];
5144
+ return [396, 'numeric', 'left', widget.get_lang_text(name) || name, 0]; // Security type
4463
5145
  case '22':
4464
5146
  case 'name':
4465
5147
  return [22, 'string', 'left', widget.get_lang_text(name) || name, 0];
@@ -4471,10 +5153,10 @@ function MillistreamWidgetApi_getColumnInfo(widget, name) {
4471
5153
  return [138, 'numeric', 'right', widget.get_lang_text(name) || name, 8];
4472
5154
  case '48':
4473
5155
  case 'newsid':
4474
- return [48, 'string', 'left', 'newsid', 0];
5156
+ return [48, 'string', 'left', 'newsid', 0]; // hardoded should not be used by any display
4475
5157
  case 'newstype':
4476
5158
  case '86':
4477
- return [86, 'string', 'left', 'newstype', 0];
5159
+ return [86, 'string', 'left', 'newstype', 0]; // hardoded should not be used by any display
4478
5160
  case '219':
4479
5161
  case 'noncurrentasset':
4480
5162
  return [219, 'numeric', 'right', widget.get_lang_text(name) || name, 8];
@@ -4534,13 +5216,13 @@ function MillistreamWidgetApi_getColumnInfo(widget, name) {
4534
5216
  return [98, 'string', 'left', widget.get_lang_text(name) || name, 0];
4535
5217
  case '180':
4536
5218
  case 's3':
4537
- return [180, 'string', 'left', widget.get_lang_text(name) || name, 0];
5219
+ return [180, 'string', 'left', widget.get_lang_text(name) || name, 0]; // Position
4538
5220
  case '181':
4539
5221
  case 's4':
4540
- return [181, 'string', 'left', widget.get_lang_text(name) || name, 0];
5222
+ return [181, 'string', 'left', widget.get_lang_text(name) || name, 0]; // Position
4541
5223
  case '393':
4542
5224
  case 's10':
4543
- return [393, 'string', 'left', widget.get_lang_text(name) || name, 0];
5225
+ return [393, 'string', 'left', widget.get_lang_text(name) || name, 0]; // comment
4544
5226
  case '127':
4545
5227
  case 'sales':
4546
5228
  return [127, 'numeric', 'right', widget.get_lang_text(name) || name, 8];
@@ -4577,7 +5259,7 @@ function MillistreamWidgetApi_getColumnInfo(widget, name) {
4577
5259
  case '227':
4578
5260
  case 'totalassets':
4579
5261
  return [227, 'numeric', 'right', widget.get_lang_text(name) || name, 8];
4580
- case '1023':
5262
+ case '1023': // TODO, define this with correct value
4581
5263
  case 'totalnumberofshares':
4582
5264
  return [1023, 'numeric', 'right', widget.get_lang_text(name) || name, 8];
4583
5265
  case '233':
@@ -4626,7 +5308,7 @@ function MillistreamWidgetApi_getColumnInfo(widget, name) {
4626
5308
  case 'vega':
4627
5309
  return [703, 'numeric', 'right', widget.get_lang_text(name) || name, 0];
4628
5310
 
4629
-
5311
+ // brokerstats
4630
5312
  case '3000':
4631
5313
  case 'boughtquantity':
4632
5314
  return [3000, 'numeric', 'right', widget.get_lang_text(name) || name, 4];
@@ -4814,7 +5496,7 @@ function MillistreamWidgetApi_getColumnInfo(widget, name) {
4814
5496
  case '3060':
4815
5497
  case 'soldturnoverytd':
4816
5498
  return [3060, 'numeric', 'left', widget.get_lang_text(name) || name, 4];
4817
-
5499
+ // key ratios egen definerade
4818
5500
  case 'per_last':
4819
5501
  case '3100':
4820
5502
  return [3100, 'numeric', 'right', widget.get_lang_text(name) || name, 0];
@@ -4935,7 +5617,7 @@ function MillistreamWidgetApi_getColumnInfo(widget, name) {
4935
5617
  case 'latestreport':
4936
5618
  case '3140':
4937
5619
  return [3140, 'date', 'right', widget.get_lang_text(name) || name, 0];
4938
-
5620
+ // basicdata join fields
4939
5621
  case 'fundcompanyname':
4940
5622
  case '3200':
4941
5623
  return [3200, 'string', 'left', widget.get_lang_text(name) || name, 0];
@@ -4954,17 +5636,17 @@ function MillistreamWidgetApi_getColumnInfo(widget, name) {
4954
5636
  case '3205':
4955
5637
  case 'underlyingsymbol':
4956
5638
  return [3204, 'string', 'left', widget.get_lang_text(name) || name, 0];
4957
- case '3206':
5639
+ case '3206': // tmcwatch
4958
5640
  case 'multiplier':
4959
5641
  return [3206, 'string', 'left', widget.get_lang_text(name) || name, 0];
4960
- case '3207':
5642
+ case '3207': // tmcwach
4961
5643
  case 'type':
4962
5644
  return [3207, 'string', 'left', widget.get_lang_text(name) || name, 0];
4963
- case '3208':
5645
+ case '3208': // tmcwach
4964
5646
  case 'direction':
4965
5647
  return [3208, 'string', 'left', widget.get_lang_text(name) || name, 0];
4966
5648
 
4967
-
5649
+ // optionwatch
4968
5650
  case '3300':
4969
5651
  case 'iv30d':
4970
5652
  case 'ivXXd':
@@ -5007,8 +5689,8 @@ function MillistreamWidgetApi_getColumnInfo(widget, name) {
5007
5689
  }
5008
5690
  }
5009
5691
 
5010
- function set_hashed_element(widget, insref, info, json, num_dec) {
5011
-
5692
+ function set_hashed_element(widget, insref, info, json, num_dec) { // called from push
5693
+ // external : list
5012
5694
  var key = insref + '_' + info[0];
5013
5695
  var arr = widget.cell_map.get(key);
5014
5696
  if (arr !== undefined) {
@@ -5018,9 +5700,9 @@ function set_hashed_element(widget, insref, info, json, num_dec) {
5018
5700
  }
5019
5701
  }
5020
5702
 
5021
-
5703
+ // Create Element functions
5022
5704
  function MillistreamWidgetApi_addElementToMap(insref, field, element, widget) {
5023
-
5705
+ // internal
5024
5706
  if (insref && field && widget && widget.cell_map) {
5025
5707
  var key = insref + '_' + field;
5026
5708
  var arr = widget.cell_map.get(key);
@@ -5036,7 +5718,7 @@ function MillistreamWidgetApi_addElementToMap(insref, field, element, widget) {
5036
5718
  }
5037
5719
 
5038
5720
  function MillistreamWidgetApi_addElement(widget, el, cl, parent, field, value, overridedecimals) {
5039
-
5721
+ // external
5040
5722
  var element = document.createElement(el);
5041
5723
  if (cl)
5042
5724
  element.setAttribute('class', cl);
@@ -5059,6 +5741,7 @@ function MillistreamWidgetApi_addTableCell2(widget, key, cl, parent, json, decim
5059
5741
  if (cl) td.setAttribute('class', cl);
5060
5742
  if (info[1] == 'numeric' && json && json[key]) {
5061
5743
  var v = 0;
5744
+ if(!isNaN(json[key])) json[key] = json[key].toString();
5062
5745
  var res = parseFloat(json[key].replace(widget.settings.decimalseparator, '.').split(widget.settings.thousandseparator).join(''));
5063
5746
  if (!isNaN(parseFloat(res)) && isFinite(res)) v = res;
5064
5747
  /*if (typeof widget.settings.positiveclass === 'string' && typeof widget.settings.negativeclass) {
@@ -5119,7 +5802,7 @@ function MillistreamWidgetApi_addTableCell(widget, key, cl, parent, json, decima
5119
5802
  widget.settings.link_field.forEach(function(element) {
5120
5803
  hrefparam[element] = json[element];
5121
5804
  });
5122
- if (info[0] == 1) {
5805
+ if (info[0] == 1) { // headline, borde inte behövas i list
5123
5806
  td.onclick = function(e) {
5124
5807
  hrefparam.event = e;
5125
5808
  hrefparam.source = widget;
@@ -5235,7 +5918,7 @@ function fabs(value) {
5235
5918
  }
5236
5919
 
5237
5920
  function zeroPad(number, width) {
5238
-
5921
+ //internal
5239
5922
  if (number <= 9.9999999 * Math.pow(10, width)) return ("0000000" + number).slice(-width);
5240
5923
  return number;
5241
5924
  }
@@ -5280,7 +5963,7 @@ function formatNiceNumber(y, thousandSeparator, decimalSeparator, precision, add
5280
5963
  }
5281
5964
 
5282
5965
  function formatDate(date, format, widget) {
5283
-
5966
+ // internal
5284
5967
  var timeStamp, mon, day;
5285
5968
  if (format == 'yyyy-mm-dd') {
5286
5969
  timeStamp = new Date(date);
@@ -5294,66 +5977,66 @@ function formatDate(date, format, widget) {
5294
5977
  day = timeStamp.getDate();
5295
5978
  return timeStamp.getFullYear() % 100 + '-' + (mon <= 9 ? '0' + mon : mon) + '-' + (day <= 9 ? '0' + day : day);
5296
5979
  }
5297
- if (format == 'b dd') {
5980
+ if (format == 'b dd') { // Jan 01
5298
5981
  timeStamp = new Date(date);
5299
5982
  mon = timeStamp.toDateString().split(' ');
5300
5983
  day = timeStamp.getDate();
5301
5984
  return mon[1] + ' ' + (day <= 9 ? '0' + day : day);
5302
5985
  }
5303
- if (format == 'b dd yyyy') {
5986
+ if (format == 'b dd yyyy') { // Jan 01 2017
5304
5987
  timeStamp = new Date(date);
5305
5988
  mon = timeStamp.toDateString().split(' ');
5306
5989
  day = timeStamp.getDate();
5307
5990
  return mon[1] + ' ' + (day <= 9 ? '0' + day : day) + ' ' + timeStamp.getFullYear();
5308
5991
  }
5309
- if (format == 'dd/mm') {
5992
+ if (format == 'dd/mm') { // Jan 01 2017
5310
5993
  timeStamp = new Date(date);
5311
5994
  mon = timeStamp.getMonth() + 1;
5312
5995
  day = timeStamp.getDate();
5313
5996
  return (day <= 9 ? '0' + day : day) + '/' + (mon <= 9 ? '0' + mon : mon);
5314
5997
  }
5315
- if (format == 'd/m') {
5998
+ if (format == 'd/m') { // Jan 01 2017
5316
5999
  timeStamp = new Date(date);
5317
6000
  return (timeStamp.getDate() + '/' + (timeStamp.getMonth() + 1));
5318
6001
  }
5319
6002
  if (format == 'd mmm yyyy') {
5320
6003
  timeStamp = new Date(date);
5321
- mon = timeStamp.toLocaleString(widget.settings.locale, { month: 'short' }).substring(0, 3);
6004
+ mon = timeStamp.toLocaleString(widget.settings.locale, { month: 'short' }).substring(0, 3); // lang....
5322
6005
  day = timeStamp.getDate();
5323
6006
  return day + ' ' + mon + ' ' + timeStamp.getFullYear();
5324
6007
  }
5325
6008
  if (format == 'dd mmm yyyy') {
5326
6009
  timeStamp = new Date(date);
5327
- mon = timeStamp.toLocaleString(widget.settings.locale, { month: 'short' }).substring(0, 3);
6010
+ mon = timeStamp.toLocaleString(widget.settings.locale, { month: 'short' }).substring(0, 3); // lang....
5328
6011
  day = timeStamp.getDate();
5329
6012
  return (day <= 9 ? '0' + day : day) + ' ' + mon + ' ' + timeStamp.getFullYear();
5330
6013
  }
5331
6014
  if (format == 'dd mmm') {
5332
6015
  timeStamp = new Date(date);
5333
- mon = timeStamp.toLocaleString(widget.settings.locale, { month: 'short' }).substring(0, 3);
6016
+ mon = timeStamp.toLocaleString(widget.settings.locale, { month: 'short' }).substring(0, 3); // lang....
5334
6017
  day = timeStamp.getDate();
5335
6018
  return (day <= 9 ? '0' + day : day) + ' ' + mon;
5336
6019
  }
5337
6020
  if (format == 'd mmm') {
5338
6021
  timeStamp = new Date(date);
5339
- mon = timeStamp.toLocaleString(widget.settings.locale, { month: 'short' }).substring(0, 3);
6022
+ mon = timeStamp.toLocaleString(widget.settings.locale, { month: 'short' }).substring(0, 3); // lang....
5340
6023
  day = timeStamp.getDate();
5341
6024
  return day + ' ' + mon;
5342
6025
  }
5343
6026
  if (format == 'mmm yyyy') {
5344
6027
  timeStamp = new Date(date);
5345
- mon = timeStamp.toLocaleString(widget.settings.locale, { month: 'short' }).substring(0, 3);
6028
+ mon = timeStamp.toLocaleString(widget.settings.locale, { month: 'short' }).substring(0, 3); // lang....
5346
6029
  timeStamp = mon + ' ' + timeStamp.getFullYear();
5347
6030
  return timeStamp;
5348
6031
  }
5349
6032
  if (format == 'mmm yy') {
5350
6033
  timeStamp = new Date(date);
5351
- mon = timeStamp.toLocaleString(widget.settings.locale, { month: 'short' }).substring(0, 3);
6034
+ mon = timeStamp.toLocaleString(widget.settings.locale, { month: 'short' }).substring(0, 3); // lang
5352
6035
  timeStamp = mon + ' ' + (timeStamp.getFullYear() % 100 < 9 ? '0' + timeStamp.getFullYear() % 100 : timeStamp.getFullYear() % 100);
5353
6036
  return timeStamp;
5354
6037
  }
5355
6038
 
5356
-
6039
+ // default yyyy-mm-dd
5357
6040
  timeStamp = new Date(date);
5358
6041
  mon = timeStamp.getMonth() + 1;
5359
6042
  day = timeStamp.getDate();
@@ -5361,7 +6044,7 @@ function formatDate(date, format, widget) {
5361
6044
  }
5362
6045
 
5363
6046
  function formatTime(value, format) {
5364
-
6047
+ // internal
5365
6048
  if (typeof value !== 'string') return "";
5366
6049
  var datetime = new Date();
5367
6050
  var tz_offset = datetime.getTimezoneOffset();
@@ -5438,7 +6121,10 @@ Number.prototype.countDecimals = function() {
5438
6121
  //if (isNaN(this.valueOf()) || Math.floor(this.valueOf()) === this.valueOf()) return 0;
5439
6122
  if (isNaN(this.valueOf())) return 0;
5440
6123
  if (Math.floor(this.valueOf()) === this.valueOf()) return 0;
5441
- return this.toString().split(".")[1].length || 0;
6124
+ var parts = this.toString().split(".");
6125
+ if (parts.length > 1) return parts[1].length;
6126
+ return 0;
6127
+ //return this.toString().split(".")[1].length || 0;
5442
6128
  };
5443
6129
 
5444
6130
 
@@ -5590,7 +6276,7 @@ function MillistreamWidgetApi_scrollIntoView(scrollarea, elem, xalign, yalign) {
5590
6276
  scrollarea.scrollLeft = elem.offsetLeft - scrollarea.getBoundingClientRect().width / 2;
5591
6277
  }
5592
6278
 
5593
-
6279
+ // scrollIntoView : replace this, breaks apps
5594
6280
  }
5595
6281
 
5596
6282
  var MillistreamWidgetSettings = {
@@ -5610,9 +6296,9 @@ function MillistreamWidgetStreamingApi(settings) {
5610
6296
  server: 'wss://stage.millistream.com:8900',
5611
6297
  alarmClient: null
5612
6298
  };
5613
- var m_requestid = 1;
6299
+ var m_requestid = 1; // 0 is invalid
5614
6300
  var m_socket = null;
5615
- var m_requests = [];
6301
+ var m_requests = []; // queued requests not sent
5616
6302
  var m_requestcallbacks = new Map();
5617
6303
 
5618
6304
 
@@ -5645,7 +6331,7 @@ function MillistreamWidgetStreamingApi(settings) {
5645
6331
  req = new Object({
5646
6332
  "widget": widget,
5647
6333
  });
5648
- m_requestcallbacks.set(requestid.toString(), req);
6334
+ m_requestcallbacks.set(requestid.toString(), req); // this requestid will be forarded to this widget
5649
6335
  }
5650
6336
  var request = '';
5651
6337
  if (MillistreamWidgetApi_isObjectEmpty(widget.unsubscriptions) == false) {
@@ -5707,7 +6393,7 @@ function MillistreamWidgetStreamingApi(settings) {
5707
6393
 
5708
6394
 
5709
6395
  widget.unsubscriptions.type = 'insrefs';
5710
- widget.unsubscriptions.insrefs = insrefs.slice(0);
6396
+ widget.unsubscriptions.insrefs = insrefs.slice(0); // copy array
5711
6397
  widget.unsubscriptions.messagetypes = widget.settings.messagetypes;
5712
6398
  widget.unsubscriptions.requestid = requestid;
5713
6399
 
@@ -5720,7 +6406,7 @@ function MillistreamWidgetStreamingApi(settings) {
5720
6406
 
5721
6407
  function reconnect() {
5722
6408
  if (!m_socket.CLOSED) {
5723
-
6409
+ //console.log('not closed');
5724
6410
  return;
5725
6411
  }
5726
6412
  m_requests.forEach(function(request) {
@@ -5739,21 +6425,21 @@ function MillistreamWidgetStreamingApi(settings) {
5739
6425
  try {
5740
6426
  m_socket = new WebSocket(_this.settings.server);
5741
6427
  m_socket.onopen = function() {
5742
- () => {};
6428
+ console.log('Connected to millistream push'); /*RemoveLogging:skip*/
5743
6429
  if (m_requests.length > 0) {
5744
6430
  m_requests.forEach(function(request) {
5745
6431
  if (request.send == 0) {
5746
-
6432
+ //console.log('rerequest:', request.request);
5747
6433
  m_socket.send('{ "token":"' + _this.settings.token + '",' + request.request);
5748
6434
  }
5749
6435
  });
5750
6436
  }
5751
6437
  };
5752
6438
  m_socket.onerror = function() {
5753
- () => {};
6439
+ console.log('Error, disconnected'); /*RemoveLogging:skip*/
5754
6440
  };
5755
6441
  m_socket.onclose = function() {
5756
- () => {};
6442
+ console.log('Disconnected'); /*RemoveLogging:skip*/
5757
6443
  reconnect();
5758
6444
  };
5759
6445
 
@@ -5762,9 +6448,9 @@ function MillistreamWidgetStreamingApi(settings) {
5762
6448
  try {
5763
6449
  jsondata = JSON.parse(msg.data);
5764
6450
  } catch (e) {
5765
- () => {};
6451
+ console.log('invalid data', msg.data); /*RemoveLogging:skip*/
5766
6452
  }
5767
-
6453
+ //console.log(JSON.stringify(jsondata));
5768
6454
  if (typeof jsondata.instruments !== 'undefined') {
5769
6455
  for (var s = 0; s < jsondata.instruments.length; s++) {
5770
6456
  var insref = jsondata.instruments[s].insref;
@@ -5790,22 +6476,23 @@ function MillistreamWidgetStreamingApi(settings) {
5790
6476
  if (_this.settings.statusCallback !== null) _this.settings.statusCallback(jsondata);
5791
6477
  } else
5792
6478
  if (typeof jsondata.alarm !== 'undefined') {
5793
- () => {};
6479
+ console.log('Alarm: ' + JSON.stringify(jsondata));
5794
6480
  if (null != _this.settings.alarmClient) {
5795
6481
  _this.settings.alarmClient(jsondata);
5796
6482
  }
5797
6483
 
5798
6484
  } else
5799
- () => {};
6485
+ console.log(JSON.stringify(jsondata)); /*RemoveLogging:skip*/
5800
6486
  };
5801
6487
  } catch (exception) {
5802
- () => {};
6488
+ console.log('Exception error: ' + exception); /*RemoveLogging:skip*/
5803
6489
  reconnect();
5804
6490
  }
5805
6491
  }
5806
6492
  milli_stream_connect();
5807
6493
  }
5808
6494
  exports.Milli_Chart = Milli_Chart;
6495
+ exports.Milli_OptionsList = Milli_OptionsList;
5809
6496
  exports.MillistreamWidgetSettings = MillistreamWidgetSettings;
5810
6497
  exports.formatDate = formatDate;
5811
6498
  exports.MillistreamWidgetStreamingApi = MillistreamWidgetStreamingApi;