mirror of https://github.com/ColorlibHQ/AdminLTE
update uplot
parent
2c98813cc1
commit
5fc36f6176
|
@ -11348,9 +11348,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"uplot": {
|
"uplot": {
|
||||||
"version": "1.4.4",
|
"version": "1.4.6",
|
||||||
"resolved": "https://registry.npmjs.org/uplot/-/uplot-1.4.4.tgz",
|
"resolved": "https://registry.npmjs.org/uplot/-/uplot-1.4.6.tgz",
|
||||||
"integrity": "sha512-vgV84+by3fGTU4bdpffSvA9FX8ide6MsmlBzOASPDdZCquXmCA+T2qodeNdnBen+7YOeqD9H91epVnF0dQgVKw=="
|
"integrity": "sha512-nw3LdjLFhAqKQF/Rv7QjZICVnjJemOQVj2L3b7889gHBrnC1LwltkzTcawDcbMe6pxo++0KVev9xSC0YCw+m5w=="
|
||||||
},
|
},
|
||||||
"upper-case": {
|
"upper-case": {
|
||||||
"version": "1.1.3",
|
"version": "1.1.3",
|
||||||
|
|
|
@ -126,7 +126,7 @@
|
||||||
"sweetalert2": "^10.10.2",
|
"sweetalert2": "^10.10.2",
|
||||||
"tempusdominus-bootstrap-4": "^5.39.0",
|
"tempusdominus-bootstrap-4": "^5.39.0",
|
||||||
"toastr": "^2.1.4",
|
"toastr": "^2.1.4",
|
||||||
"uplot": "^1.4.4"
|
"uplot": "^1.4.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.11.6",
|
"@babel/core": "^7.11.6",
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
*
|
*
|
||||||
* uPlot.js (μPlot)
|
* uPlot.js (μPlot)
|
||||||
* A small, fast chart for time series, lines, areas, ohlc & bars
|
* A small, fast chart for time series, lines, areas, ohlc & bars
|
||||||
* https://github.com/leeoniya/uPlot (v1.4.4)
|
* https://github.com/leeoniya/uPlot (v1.4.6)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
@ -551,8 +551,6 @@ var onlyWhole = function (v) { return v % 1 == 0; };
|
||||||
|
|
||||||
var allMults = [1,2,2.5,5];
|
var allMults = [1,2,2.5,5];
|
||||||
|
|
||||||
var wholeMults = allMults.filter(onlyWhole);
|
|
||||||
|
|
||||||
// ...0.01, 0.02, 0.025, 0.05, 0.1, 0.2, 0.25, 0.5
|
// ...0.01, 0.02, 0.025, 0.05, 0.1, 0.2, 0.25, 0.5
|
||||||
var decIncrs = genIncrs(10, -16, 0, allMults);
|
var decIncrs = genIncrs(10, -16, 0, allMults);
|
||||||
|
|
||||||
|
@ -564,61 +562,196 @@ var wholeIncrs = oneIncrs.filter(onlyWhole);
|
||||||
|
|
||||||
var numIncrs = decIncrs.concat(oneIncrs);
|
var numIncrs = decIncrs.concat(oneIncrs);
|
||||||
|
|
||||||
var s = 1,
|
var NL = "\n";
|
||||||
m = 60,
|
|
||||||
h = m * m,
|
|
||||||
d = h * 24,
|
|
||||||
mo = d * 30,
|
|
||||||
y = d * 365;
|
|
||||||
|
|
||||||
// min of 1e-3 prevents setting a temporal x ticks too small since Date objects cannot advance ticks smaller than 1ms
|
var yyyy = "{YYYY}";
|
||||||
var timeIncrs = genIncrs(10, -3, 0, wholeMults).concat([
|
var NLyyyy = NL + yyyy;
|
||||||
// minute divisors (# of secs)
|
var md = "{M}/{D}";
|
||||||
1,
|
var NLmd = NL + md;
|
||||||
5,
|
var NLmdyy = NLmd + "/{YY}";
|
||||||
10,
|
|
||||||
15,
|
var aa = "{aa}";
|
||||||
30,
|
var hmm = "{h}:{mm}";
|
||||||
// hour divisors (# of mins)
|
var hmmaa = hmm + aa;
|
||||||
m,
|
var NLhmmaa = NL + hmmaa;
|
||||||
m * 5,
|
var ss = ":{ss}";
|
||||||
m * 10,
|
|
||||||
m * 15,
|
var _ = null;
|
||||||
m * 30,
|
|
||||||
// day divisors (# of hrs)
|
function genTimeStuffs(ms) {
|
||||||
h,
|
var s = ms * 1e3,
|
||||||
h * 2,
|
m = s * 60,
|
||||||
h * 3,
|
h = m * 60,
|
||||||
h * 4,
|
d = h * 24,
|
||||||
h * 6,
|
mo = d * 30,
|
||||||
h * 8,
|
y = d * 365;
|
||||||
h * 12,
|
|
||||||
// month divisors TODO: need more?
|
// min of 1e-3 prevents setting a temporal x ticks too small since Date objects cannot advance ticks smaller than 1ms
|
||||||
d,
|
var subSecIncrs = ms == 1 ? genIncrs(10, 0, 3, allMults).filter(onlyWhole) : genIncrs(10, -3, 0, allMults);
|
||||||
d * 2,
|
|
||||||
d * 3,
|
var timeIncrs = subSecIncrs.concat([
|
||||||
d * 4,
|
// minute divisors (# of secs)
|
||||||
d * 5,
|
s,
|
||||||
d * 6,
|
s * 5,
|
||||||
d * 7,
|
s * 10,
|
||||||
d * 8,
|
s * 15,
|
||||||
d * 9,
|
s * 30,
|
||||||
d * 10,
|
// hour divisors (# of mins)
|
||||||
d * 15,
|
m,
|
||||||
// year divisors (# months, approx)
|
m * 5,
|
||||||
mo,
|
m * 10,
|
||||||
mo * 2,
|
m * 15,
|
||||||
mo * 3,
|
m * 30,
|
||||||
mo * 4,
|
// day divisors (# of hrs)
|
||||||
mo * 6,
|
h,
|
||||||
// century divisors
|
h * 2,
|
||||||
y,
|
h * 3,
|
||||||
y * 2,
|
h * 4,
|
||||||
y * 5,
|
h * 6,
|
||||||
y * 10,
|
h * 8,
|
||||||
y * 25,
|
h * 12,
|
||||||
y * 50,
|
// month divisors TODO: need more?
|
||||||
y * 100 ]);
|
d,
|
||||||
|
d * 2,
|
||||||
|
d * 3,
|
||||||
|
d * 4,
|
||||||
|
d * 5,
|
||||||
|
d * 6,
|
||||||
|
d * 7,
|
||||||
|
d * 8,
|
||||||
|
d * 9,
|
||||||
|
d * 10,
|
||||||
|
d * 15,
|
||||||
|
// year divisors (# months, approx)
|
||||||
|
mo,
|
||||||
|
mo * 2,
|
||||||
|
mo * 3,
|
||||||
|
mo * 4,
|
||||||
|
mo * 6,
|
||||||
|
// century divisors
|
||||||
|
y,
|
||||||
|
y * 2,
|
||||||
|
y * 5,
|
||||||
|
y * 10,
|
||||||
|
y * 25,
|
||||||
|
y * 50,
|
||||||
|
y * 100 ]);
|
||||||
|
|
||||||
|
// [0]: minimum num secs in the tick incr
|
||||||
|
// [1]: default tick format
|
||||||
|
// [2-7]: rollover tick formats
|
||||||
|
// [8]: mode: 0: replace [1] -> [2-7], 1: concat [1] + [2-7]
|
||||||
|
var _timeAxisStamps = [
|
||||||
|
// tick incr default year month day hour min sec mode
|
||||||
|
[y, yyyy, _, _, _, _, _, _, 1],
|
||||||
|
[d * 28, "{MMM}", NLyyyy, _, _, _, _, _, 1],
|
||||||
|
[d, md, NLyyyy, _, _, _, _, _, 1],
|
||||||
|
[h, "{h}" + aa, NLmdyy, _, NLmd, _, _, _, 1],
|
||||||
|
[m, hmmaa, NLmdyy, _, NLmd, _, _, _, 1],
|
||||||
|
[s, ss, NLmdyy + " " + hmmaa, _, NLmd + " " + hmmaa, _, NLhmmaa, _, 1],
|
||||||
|
[ms, ss + ".{fff}", NLmdyy + " " + hmmaa, _, NLmd + " " + hmmaa, _, NLhmmaa, _, 1] ];
|
||||||
|
|
||||||
|
// the ensures that axis ticks, values & grid are aligned to logical temporal breakpoints and not an arbitrary timestamp
|
||||||
|
// https://www.timeanddate.com/time/dst/
|
||||||
|
// https://www.timeanddate.com/time/dst/2019.html
|
||||||
|
// https://www.epochconverter.com/timezones
|
||||||
|
function timeAxisSplits(tzDate) {
|
||||||
|
return function (self, axisIdx, scaleMin, scaleMax, foundIncr, foundSpace) {
|
||||||
|
var splits = [];
|
||||||
|
var isYr = foundIncr >= y;
|
||||||
|
var isMo = foundIncr >= mo && foundIncr < y;
|
||||||
|
|
||||||
|
// get the timezone-adjusted date
|
||||||
|
var minDate = tzDate(scaleMin);
|
||||||
|
var minDateTs = minDate * ms;
|
||||||
|
|
||||||
|
// get ts of 12am (this lands us at or before the original scaleMin)
|
||||||
|
var minMin = mkDate(minDate[getFullYear](), isYr ? 0 : minDate[getMonth](), isMo || isYr ? 1 : minDate[getDate]());
|
||||||
|
var minMinTs = minMin * ms;
|
||||||
|
|
||||||
|
if (isMo || isYr) {
|
||||||
|
var moIncr = isMo ? foundIncr / mo : 0;
|
||||||
|
var yrIncr = isYr ? foundIncr / y : 0;
|
||||||
|
// let tzOffset = scaleMin - minDateTs; // needed?
|
||||||
|
var split = minDateTs == minMinTs ? minDateTs : mkDate(minMin[getFullYear]() + yrIncr, minMin[getMonth]() + moIncr, 1) * ms;
|
||||||
|
var splitDate = new Date(split / ms);
|
||||||
|
var baseYear = splitDate[getFullYear]();
|
||||||
|
var baseMonth = splitDate[getMonth]();
|
||||||
|
|
||||||
|
for (var i = 0; split <= scaleMax; i++) {
|
||||||
|
var next = mkDate(baseYear + yrIncr * i, baseMonth + moIncr * i, 1);
|
||||||
|
var offs = next - tzDate(next * ms);
|
||||||
|
|
||||||
|
split = (+next + offs) * ms;
|
||||||
|
|
||||||
|
if (split <= scaleMax)
|
||||||
|
{ splits.push(split); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var incr0 = foundIncr >= d ? d : foundIncr;
|
||||||
|
var tzOffset = floor(scaleMin) - floor(minDateTs);
|
||||||
|
var split$1 = minMinTs + tzOffset + incrRoundUp(minDateTs - minMinTs, incr0);
|
||||||
|
splits.push(split$1);
|
||||||
|
|
||||||
|
var date0 = tzDate(split$1);
|
||||||
|
|
||||||
|
var prevHour = date0[getHours]() + (date0[getMinutes]() / m) + (date0[getSeconds]() / h);
|
||||||
|
var incrHours = foundIncr / h;
|
||||||
|
|
||||||
|
var minSpace = self.axes[axisIdx]._space;
|
||||||
|
var pctSpace = foundSpace / minSpace;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
split$1 = roundDec(split$1 + foundIncr, ms == 1 ? 0 : 3);
|
||||||
|
|
||||||
|
if (split$1 > scaleMax)
|
||||||
|
{ break; }
|
||||||
|
|
||||||
|
if (incrHours > 1) {
|
||||||
|
var expectedHour = floor(roundDec(prevHour + incrHours, 6)) % 24;
|
||||||
|
var splitDate$1 = tzDate(split$1);
|
||||||
|
var actualHour = splitDate$1.getHours();
|
||||||
|
|
||||||
|
var dstShift = actualHour - expectedHour;
|
||||||
|
|
||||||
|
if (dstShift > 1)
|
||||||
|
{ dstShift = -1; }
|
||||||
|
|
||||||
|
split$1 -= dstShift * h;
|
||||||
|
|
||||||
|
prevHour = (prevHour + incrHours) % 24;
|
||||||
|
|
||||||
|
// add a tick only if it's further than 70% of the min allowed label spacing
|
||||||
|
var prevSplit = splits[splits.length - 1];
|
||||||
|
var pctIncr = roundDec((split$1 - prevSplit) / foundIncr, 3);
|
||||||
|
|
||||||
|
if (pctIncr * pctSpace >= .7)
|
||||||
|
{ splits.push(split$1); }
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ splits.push(split$1); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return splits;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
timeIncrs,
|
||||||
|
_timeAxisStamps,
|
||||||
|
timeAxisSplits ];
|
||||||
|
}
|
||||||
|
|
||||||
|
var ref = genTimeStuffs(1);
|
||||||
|
var timeIncrsMs = ref[0];
|
||||||
|
var _timeAxisStampsMs = ref[1];
|
||||||
|
var timeAxisSplitsMs = ref[2];
|
||||||
|
var ref$1 = genTimeStuffs(1e-3);
|
||||||
|
var timeIncrsS = ref$1[0];
|
||||||
|
var _timeAxisStampsS = ref$1[1];
|
||||||
|
var timeAxisSplitsS = ref$1[2];
|
||||||
|
|
||||||
// base 2
|
// base 2
|
||||||
var binIncrs = genIncrs(2, -53, 53, [1]);
|
var binIncrs = genIncrs(2, -53, 53, [1]);
|
||||||
|
@ -639,36 +772,6 @@ function timeAxisStamps(stampCfg, fmtDate) {
|
||||||
); });
|
); });
|
||||||
}
|
}
|
||||||
|
|
||||||
var NL = "\n";
|
|
||||||
|
|
||||||
var yyyy = "{YYYY}";
|
|
||||||
var NLyyyy = NL + yyyy;
|
|
||||||
var md = "{M}/{D}";
|
|
||||||
var NLmd = NL + md;
|
|
||||||
var NLmdyy = NLmd + "/{YY}";
|
|
||||||
|
|
||||||
var aa = "{aa}";
|
|
||||||
var hmm = "{h}:{mm}";
|
|
||||||
var hmmaa = hmm + aa;
|
|
||||||
var NLhmmaa = NL + hmmaa;
|
|
||||||
var ss = ":{ss}";
|
|
||||||
|
|
||||||
var _ = null;
|
|
||||||
|
|
||||||
// [0]: minimum num secs in the tick incr
|
|
||||||
// [1]: default tick format
|
|
||||||
// [2-7]: rollover tick formats
|
|
||||||
// [8]: mode: 0: replace [1] -> [2-7], 1: concat [1] + [2-7]
|
|
||||||
var _timeAxisStamps = [
|
|
||||||
// tick incr default year month day hour min sec mode
|
|
||||||
[y, yyyy, _, _, _, _, _, _, 1],
|
|
||||||
[d * 28, "{MMM}", NLyyyy, _, _, _, _, _, 1],
|
|
||||||
[d, md, NLyyyy, _, _, _, _, _, 1],
|
|
||||||
[h, "{h}" + aa, NLmdyy, _, NLmd, _, _, _, 1],
|
|
||||||
[m, hmmaa, NLmdyy, _, NLmd, _, _, _, 1],
|
|
||||||
[s, ss, NLmdyy + " " + hmmaa, _, NLmd + " " + hmmaa, _, NLhmmaa, _, 1],
|
|
||||||
[1e-3, ss + ".{fff}", NLmdyy + " " + hmmaa, _, NLmd + " " + hmmaa, _, NLhmmaa, _, 1] ];
|
|
||||||
|
|
||||||
// TODO: will need to accept spaces[] and pull incr into the loop when grid will be non-uniform, eg for log scales.
|
// TODO: will need to accept spaces[] and pull incr into the loop when grid will be non-uniform, eg for log scales.
|
||||||
// currently we ignore this for months since they're *nearly* uniform and the added complexity is not worth it
|
// currently we ignore this for months since they're *nearly* uniform and the added complexity is not worth it
|
||||||
function timeAxisVals(tzDate, stamps) {
|
function timeAxisVals(tzDate, stamps) {
|
||||||
|
@ -725,93 +828,6 @@ function mkDate(y, m, d) {
|
||||||
return new Date(y, m, d);
|
return new Date(y, m, d);
|
||||||
}
|
}
|
||||||
|
|
||||||
// the ensures that axis ticks, values & grid are aligned to logical temporal breakpoints and not an arbitrary timestamp
|
|
||||||
// https://www.timeanddate.com/time/dst/
|
|
||||||
// https://www.timeanddate.com/time/dst/2019.html
|
|
||||||
// https://www.epochconverter.com/timezones
|
|
||||||
function timeAxisSplits(tzDate) {
|
|
||||||
return function (self, axisIdx, scaleMin, scaleMax, foundIncr, foundSpace) {
|
|
||||||
var splits = [];
|
|
||||||
var isYr = foundIncr >= y;
|
|
||||||
var isMo = foundIncr >= mo && foundIncr < y;
|
|
||||||
|
|
||||||
// get the timezone-adjusted date
|
|
||||||
var minDate = tzDate(scaleMin);
|
|
||||||
var minDateTs = minDate / 1e3;
|
|
||||||
|
|
||||||
// get ts of 12am (this lands us at or before the original scaleMin)
|
|
||||||
var minMin = mkDate(minDate[getFullYear](), isYr ? 0 : minDate[getMonth](), isMo || isYr ? 1 : minDate[getDate]());
|
|
||||||
var minMinTs = minMin / 1e3;
|
|
||||||
|
|
||||||
if (isMo || isYr) {
|
|
||||||
var moIncr = isMo ? foundIncr / mo : 0;
|
|
||||||
var yrIncr = isYr ? foundIncr / y : 0;
|
|
||||||
// let tzOffset = scaleMin - minDateTs; // needed?
|
|
||||||
var split = minDateTs == minMinTs ? minDateTs : mkDate(minMin[getFullYear]() + yrIncr, minMin[getMonth]() + moIncr, 1) / 1e3;
|
|
||||||
var splitDate = new Date(split * 1e3);
|
|
||||||
var baseYear = splitDate[getFullYear]();
|
|
||||||
var baseMonth = splitDate[getMonth]();
|
|
||||||
|
|
||||||
for (var i = 0; split <= scaleMax; i++) {
|
|
||||||
var next = mkDate(baseYear + yrIncr * i, baseMonth + moIncr * i, 1);
|
|
||||||
var offs = next - tzDate(next / 1e3);
|
|
||||||
|
|
||||||
split = (+next + offs) / 1e3;
|
|
||||||
|
|
||||||
if (split <= scaleMax)
|
|
||||||
{ splits.push(split); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var incr0 = foundIncr >= d ? d : foundIncr;
|
|
||||||
var tzOffset = floor(scaleMin) - floor(minDateTs);
|
|
||||||
var split$1 = minMinTs + tzOffset + incrRoundUp(minDateTs - minMinTs, incr0);
|
|
||||||
splits.push(split$1);
|
|
||||||
|
|
||||||
var date0 = tzDate(split$1);
|
|
||||||
|
|
||||||
var prevHour = date0[getHours]() + (date0[getMinutes]() / m) + (date0[getSeconds]() / h);
|
|
||||||
var incrHours = foundIncr / h;
|
|
||||||
|
|
||||||
var minSpace = self.axes[axisIdx]._space;
|
|
||||||
var pctSpace = foundSpace / minSpace;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
split$1 = roundDec(split$1 + foundIncr, 3);
|
|
||||||
|
|
||||||
if (split$1 > scaleMax)
|
|
||||||
{ break; }
|
|
||||||
|
|
||||||
if (incrHours > 1) {
|
|
||||||
var expectedHour = floor(roundDec(prevHour + incrHours, 6)) % 24;
|
|
||||||
var splitDate$1 = tzDate(split$1);
|
|
||||||
var actualHour = splitDate$1.getHours();
|
|
||||||
|
|
||||||
var dstShift = actualHour - expectedHour;
|
|
||||||
|
|
||||||
if (dstShift > 1)
|
|
||||||
{ dstShift = -1; }
|
|
||||||
|
|
||||||
split$1 -= dstShift * h;
|
|
||||||
|
|
||||||
prevHour = (prevHour + incrHours) % 24;
|
|
||||||
|
|
||||||
// add a tick only if it's further than 70% of the min allowed label spacing
|
|
||||||
var prevSplit = splits[splits.length - 1];
|
|
||||||
var pctIncr = roundDec((split$1 - prevSplit) / foundIncr, 3);
|
|
||||||
|
|
||||||
if (pctIncr * pctSpace >= .7)
|
|
||||||
{ splits.push(split$1); }
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{ splits.push(split$1); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return splits;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function timeSeriesStamp(stampCfg, fmtDate) {
|
function timeSeriesStamp(stampCfg, fmtDate) {
|
||||||
return fmtDate(stampCfg);
|
return fmtDate(stampCfg);
|
||||||
}
|
}
|
||||||
|
@ -1235,7 +1251,7 @@ function uPlot(opts, data, then) {
|
||||||
{ opts = p.opts(self, opts) || opts; }
|
{ opts = p.opts(self, opts) || opts; }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var ms = opts.ms || 1e-3;
|
||||||
|
|
||||||
var series = self.series = setDefaults(opts.series || [], xSeriesOpts, ySeriesOpts, false);
|
var series = self.series = setDefaults(opts.series || [], xSeriesOpts, ySeriesOpts, false);
|
||||||
var axes = self.axes = setDefaults(opts.axes || [], xAxisOpts, yAxisOpts, true);
|
var axes = self.axes = setDefaults(opts.axes || [], xAxisOpts, yAxisOpts, true);
|
||||||
|
@ -1311,11 +1327,11 @@ function uPlot(opts, data, then) {
|
||||||
gutters._y = gutters.y(self);
|
gutters._y = gutters.y(self);
|
||||||
|
|
||||||
// self.tz = opts.tz || Intl.DateTimeFormat().resolvedOptions().timeZone;
|
// self.tz = opts.tz || Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||||
var _tzDate = (opts.tzDate || (function (ts) { return new Date(ts * 1e3); }));
|
var _tzDate = (opts.tzDate || (function (ts) { return new Date(ts / ms); }));
|
||||||
var _fmtDate = (opts.fmtDate || fmtDate);
|
var _fmtDate = (opts.fmtDate || fmtDate);
|
||||||
|
|
||||||
var _timeAxisSplits = timeAxisSplits(_tzDate);
|
var _timeAxisSplits = (ms == 1 ? timeAxisSplitsMs(_tzDate) : timeAxisSplitsS(_tzDate));
|
||||||
var _timeAxisVals = timeAxisVals(_tzDate, timeAxisStamps(_timeAxisStamps, _fmtDate));
|
var _timeAxisVals = timeAxisVals(_tzDate, timeAxisStamps((ms == 1 ? _timeAxisStampsMs : _timeAxisStampsS), _fmtDate));
|
||||||
var _timeSeriesVal = timeSeriesVal(_tzDate, timeSeriesStamp(_timeSeriesStamp, _fmtDate));
|
var _timeSeriesVal = timeSeriesVal(_tzDate, timeSeriesStamp(_timeSeriesStamp, _fmtDate));
|
||||||
|
|
||||||
var legend = assign({show: true, live: true}, opts.legend);
|
var legend = assign({show: true, live: true}, opts.legend);
|
||||||
|
@ -1471,9 +1487,13 @@ function uPlot(opts, data, then) {
|
||||||
function convergeSize() {
|
function convergeSize() {
|
||||||
var converged = false;
|
var converged = false;
|
||||||
|
|
||||||
|
var cycleNum = 0;
|
||||||
|
|
||||||
while (!converged) {
|
while (!converged) {
|
||||||
var axesConverged = axesCalc();
|
cycleNum++;
|
||||||
var guttersConverged = guttersCalc();
|
|
||||||
|
var axesConverged = axesCalc(cycleNum);
|
||||||
|
var guttersConverged = guttersCalc(cycleNum);
|
||||||
|
|
||||||
converged = axesConverged && guttersConverged;
|
converged = axesConverged && guttersConverged;
|
||||||
|
|
||||||
|
@ -1685,7 +1705,7 @@ function uPlot(opts, data, then) {
|
||||||
axis.size = fnOrSelf(axis.size);
|
axis.size = fnOrSelf(axis.size);
|
||||||
axis.space = fnOrSelf(axis.space);
|
axis.space = fnOrSelf(axis.space);
|
||||||
axis.rotate = fnOrSelf(axis.rotate);
|
axis.rotate = fnOrSelf(axis.rotate);
|
||||||
axis.incrs = fnOrSelf(axis.incrs || ( sc.distr == 2 ? wholeIncrs : (isTime ? timeIncrs : numIncrs)));
|
axis.incrs = fnOrSelf(axis.incrs || ( sc.distr == 2 ? wholeIncrs : (isTime ? (ms == 1 ? timeIncrsMs : timeIncrsS) : numIncrs)));
|
||||||
axis.splits = fnOrSelf(axis.splits || (isTime && sc.distr == 1 ? _timeAxisSplits : sc.distr == 3 ? logAxisSplits : numAxisSplits));
|
axis.splits = fnOrSelf(axis.splits || (isTime && sc.distr == 1 ? _timeAxisSplits : sc.distr == 3 ? logAxisSplits : numAxisSplits));
|
||||||
|
|
||||||
var av = axis.values;
|
var av = axis.values;
|
||||||
|
@ -1704,7 +1724,7 @@ function uPlot(opts, data, then) {
|
||||||
axis.font = pxRatioFont(axis.font);
|
axis.font = pxRatioFont(axis.font);
|
||||||
axis.labelFont = pxRatioFont(axis.labelFont);
|
axis.labelFont = pxRatioFont(axis.labelFont);
|
||||||
|
|
||||||
axis._size = axis.size(self, null, i);
|
axis._size = axis.size(self, null, i, 0);
|
||||||
|
|
||||||
axis._space =
|
axis._space =
|
||||||
axis._rotate =
|
axis._rotate =
|
||||||
|
@ -1789,7 +1809,7 @@ function uPlot(opts, data, then) {
|
||||||
if (xScaleDistr == 3)
|
if (xScaleDistr == 3)
|
||||||
{ (assign = rangeLog(_min, _min, scales[xScaleKey].log, false), _min = assign[0], _max = assign[1]); }
|
{ (assign = rangeLog(_min, _min, scales[xScaleKey].log, false), _min = assign[0], _max = assign[1]); }
|
||||||
else if (scales[xScaleKey].time)
|
else if (scales[xScaleKey].time)
|
||||||
{ _max = _min + 86400; }
|
{ _max = _min + 86400 / ms; }
|
||||||
else
|
else
|
||||||
{ (assign$1 = rangeNum(_min, _max, 0.1, true), _min = assign$1[0], _max = assign$1[1]); }
|
{ (assign$1 = rangeNum(_min, _max, 0.1, true), _min = assign$1[0], _max = assign$1[1]); }
|
||||||
}
|
}
|
||||||
|
@ -2330,7 +2350,7 @@ function uPlot(opts, data, then) {
|
||||||
ctx.translate(-offset, -offset);
|
ctx.translate(-offset, -offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
function axesCalc() {
|
function axesCalc(cycleNum) {
|
||||||
// log("axesCalc()", arguments);
|
// log("axesCalc()", arguments);
|
||||||
|
|
||||||
var converged = true;
|
var converged = true;
|
||||||
|
@ -2387,7 +2407,7 @@ function uPlot(opts, data, then) {
|
||||||
|
|
||||||
var oldSize = axis._size;
|
var oldSize = axis._size;
|
||||||
|
|
||||||
axis._size = axis.size(self, values, i);
|
axis._size = ceil(axis.size(self, values, i, cycleNum));
|
||||||
|
|
||||||
if (oldSize != null && axis._size != oldSize) // ready && ?
|
if (oldSize != null && axis._size != oldSize) // ready && ?
|
||||||
{ converged = false; }
|
{ converged = false; }
|
||||||
|
@ -2396,14 +2416,14 @@ function uPlot(opts, data, then) {
|
||||||
return converged;
|
return converged;
|
||||||
}
|
}
|
||||||
|
|
||||||
function guttersCalc() {
|
function guttersCalc(cycleNum) {
|
||||||
var converged = true;
|
var converged = true;
|
||||||
|
|
||||||
var _x = gutters._x;
|
var _x = gutters._x;
|
||||||
var _y = gutters._y;
|
var _y = gutters._y;
|
||||||
|
|
||||||
gutters._x = gutters.x(self);
|
gutters._x = ceil(gutters.x(self, cycleNum));
|
||||||
gutters._y = gutters.y(self);
|
gutters._y = ceil(gutters.y(self, cycleNum));
|
||||||
|
|
||||||
if (gutters._x != _x || gutters._y != _y)
|
if (gutters._x != _x || gutters._y != _y)
|
||||||
{ converged = false; }
|
{ converged = false; }
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
*
|
*
|
||||||
* uPlot.js (μPlot)
|
* uPlot.js (μPlot)
|
||||||
* A small, fast chart for time series, lines, areas, ohlc & bars
|
* A small, fast chart for time series, lines, areas, ohlc & bars
|
||||||
* https://github.com/leeoniya/uPlot (v1.4.4)
|
* https://github.com/leeoniya/uPlot (v1.4.6)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function debounce(fn, time) {
|
function debounce(fn, time) {
|
||||||
|
@ -551,8 +551,6 @@ const onlyWhole = v => v % 1 == 0;
|
||||||
|
|
||||||
const allMults = [1,2,2.5,5];
|
const allMults = [1,2,2.5,5];
|
||||||
|
|
||||||
const wholeMults = allMults.filter(onlyWhole);
|
|
||||||
|
|
||||||
// ...0.01, 0.02, 0.025, 0.05, 0.1, 0.2, 0.25, 0.5
|
// ...0.01, 0.02, 0.025, 0.05, 0.1, 0.2, 0.25, 0.5
|
||||||
const decIncrs = genIncrs(10, -16, 0, allMults);
|
const decIncrs = genIncrs(10, -16, 0, allMults);
|
||||||
|
|
||||||
|
@ -564,62 +562,193 @@ const wholeIncrs = oneIncrs.filter(onlyWhole);
|
||||||
|
|
||||||
const numIncrs = decIncrs.concat(oneIncrs);
|
const numIncrs = decIncrs.concat(oneIncrs);
|
||||||
|
|
||||||
let s = 1,
|
const NL = "\n";
|
||||||
m = 60,
|
|
||||||
h = m * m,
|
|
||||||
d = h * 24,
|
|
||||||
mo = d * 30,
|
|
||||||
y = d * 365;
|
|
||||||
|
|
||||||
// min of 1e-3 prevents setting a temporal x ticks too small since Date objects cannot advance ticks smaller than 1ms
|
const yyyy = "{YYYY}";
|
||||||
const timeIncrs = genIncrs(10, -3, 0, wholeMults).concat([
|
const NLyyyy = NL + yyyy;
|
||||||
// minute divisors (# of secs)
|
const md = "{M}/{D}";
|
||||||
1,
|
const NLmd = NL + md;
|
||||||
5,
|
const NLmdyy = NLmd + "/{YY}";
|
||||||
10,
|
|
||||||
15,
|
const aa = "{aa}";
|
||||||
30,
|
const hmm = "{h}:{mm}";
|
||||||
// hour divisors (# of mins)
|
const hmmaa = hmm + aa;
|
||||||
m,
|
const NLhmmaa = NL + hmmaa;
|
||||||
m * 5,
|
const ss = ":{ss}";
|
||||||
m * 10,
|
|
||||||
m * 15,
|
const _ = null;
|
||||||
m * 30,
|
|
||||||
// day divisors (# of hrs)
|
function genTimeStuffs(ms) {
|
||||||
h,
|
let s = ms * 1e3,
|
||||||
h * 2,
|
m = s * 60,
|
||||||
h * 3,
|
h = m * 60,
|
||||||
h * 4,
|
d = h * 24,
|
||||||
h * 6,
|
mo = d * 30,
|
||||||
h * 8,
|
y = d * 365;
|
||||||
h * 12,
|
|
||||||
// month divisors TODO: need more?
|
// min of 1e-3 prevents setting a temporal x ticks too small since Date objects cannot advance ticks smaller than 1ms
|
||||||
d,
|
let subSecIncrs = ms == 1 ? genIncrs(10, 0, 3, allMults).filter(onlyWhole) : genIncrs(10, -3, 0, allMults);
|
||||||
d * 2,
|
|
||||||
d * 3,
|
let timeIncrs = subSecIncrs.concat([
|
||||||
d * 4,
|
// minute divisors (# of secs)
|
||||||
d * 5,
|
s,
|
||||||
d * 6,
|
s * 5,
|
||||||
d * 7,
|
s * 10,
|
||||||
d * 8,
|
s * 15,
|
||||||
d * 9,
|
s * 30,
|
||||||
d * 10,
|
// hour divisors (# of mins)
|
||||||
d * 15,
|
m,
|
||||||
// year divisors (# months, approx)
|
m * 5,
|
||||||
mo,
|
m * 10,
|
||||||
mo * 2,
|
m * 15,
|
||||||
mo * 3,
|
m * 30,
|
||||||
mo * 4,
|
// day divisors (# of hrs)
|
||||||
mo * 6,
|
h,
|
||||||
// century divisors
|
h * 2,
|
||||||
y,
|
h * 3,
|
||||||
y * 2,
|
h * 4,
|
||||||
y * 5,
|
h * 6,
|
||||||
y * 10,
|
h * 8,
|
||||||
y * 25,
|
h * 12,
|
||||||
y * 50,
|
// month divisors TODO: need more?
|
||||||
y * 100,
|
d,
|
||||||
]);
|
d * 2,
|
||||||
|
d * 3,
|
||||||
|
d * 4,
|
||||||
|
d * 5,
|
||||||
|
d * 6,
|
||||||
|
d * 7,
|
||||||
|
d * 8,
|
||||||
|
d * 9,
|
||||||
|
d * 10,
|
||||||
|
d * 15,
|
||||||
|
// year divisors (# months, approx)
|
||||||
|
mo,
|
||||||
|
mo * 2,
|
||||||
|
mo * 3,
|
||||||
|
mo * 4,
|
||||||
|
mo * 6,
|
||||||
|
// century divisors
|
||||||
|
y,
|
||||||
|
y * 2,
|
||||||
|
y * 5,
|
||||||
|
y * 10,
|
||||||
|
y * 25,
|
||||||
|
y * 50,
|
||||||
|
y * 100,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// [0]: minimum num secs in the tick incr
|
||||||
|
// [1]: default tick format
|
||||||
|
// [2-7]: rollover tick formats
|
||||||
|
// [8]: mode: 0: replace [1] -> [2-7], 1: concat [1] + [2-7]
|
||||||
|
const _timeAxisStamps = [
|
||||||
|
// tick incr default year month day hour min sec mode
|
||||||
|
[y, yyyy, _, _, _, _, _, _, 1],
|
||||||
|
[d * 28, "{MMM}", NLyyyy, _, _, _, _, _, 1],
|
||||||
|
[d, md, NLyyyy, _, _, _, _, _, 1],
|
||||||
|
[h, "{h}" + aa, NLmdyy, _, NLmd, _, _, _, 1],
|
||||||
|
[m, hmmaa, NLmdyy, _, NLmd, _, _, _, 1],
|
||||||
|
[s, ss, NLmdyy + " " + hmmaa, _, NLmd + " " + hmmaa, _, NLhmmaa, _, 1],
|
||||||
|
[ms, ss + ".{fff}", NLmdyy + " " + hmmaa, _, NLmd + " " + hmmaa, _, NLhmmaa, _, 1],
|
||||||
|
];
|
||||||
|
|
||||||
|
// the ensures that axis ticks, values & grid are aligned to logical temporal breakpoints and not an arbitrary timestamp
|
||||||
|
// https://www.timeanddate.com/time/dst/
|
||||||
|
// https://www.timeanddate.com/time/dst/2019.html
|
||||||
|
// https://www.epochconverter.com/timezones
|
||||||
|
function timeAxisSplits(tzDate) {
|
||||||
|
return (self, axisIdx, scaleMin, scaleMax, foundIncr, foundSpace) => {
|
||||||
|
let splits = [];
|
||||||
|
let isYr = foundIncr >= y;
|
||||||
|
let isMo = foundIncr >= mo && foundIncr < y;
|
||||||
|
|
||||||
|
// get the timezone-adjusted date
|
||||||
|
let minDate = tzDate(scaleMin);
|
||||||
|
let minDateTs = minDate * ms;
|
||||||
|
|
||||||
|
// get ts of 12am (this lands us at or before the original scaleMin)
|
||||||
|
let minMin = mkDate(minDate[getFullYear](), isYr ? 0 : minDate[getMonth](), isMo || isYr ? 1 : minDate[getDate]());
|
||||||
|
let minMinTs = minMin * ms;
|
||||||
|
|
||||||
|
if (isMo || isYr) {
|
||||||
|
let moIncr = isMo ? foundIncr / mo : 0;
|
||||||
|
let yrIncr = isYr ? foundIncr / y : 0;
|
||||||
|
// let tzOffset = scaleMin - minDateTs; // needed?
|
||||||
|
let split = minDateTs == minMinTs ? minDateTs : mkDate(minMin[getFullYear]() + yrIncr, minMin[getMonth]() + moIncr, 1) * ms;
|
||||||
|
let splitDate = new Date(split / ms);
|
||||||
|
let baseYear = splitDate[getFullYear]();
|
||||||
|
let baseMonth = splitDate[getMonth]();
|
||||||
|
|
||||||
|
for (let i = 0; split <= scaleMax; i++) {
|
||||||
|
let next = mkDate(baseYear + yrIncr * i, baseMonth + moIncr * i, 1);
|
||||||
|
let offs = next - tzDate(next * ms);
|
||||||
|
|
||||||
|
split = (+next + offs) * ms;
|
||||||
|
|
||||||
|
if (split <= scaleMax)
|
||||||
|
splits.push(split);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let incr0 = foundIncr >= d ? d : foundIncr;
|
||||||
|
let tzOffset = floor(scaleMin) - floor(minDateTs);
|
||||||
|
let split = minMinTs + tzOffset + incrRoundUp(minDateTs - minMinTs, incr0);
|
||||||
|
splits.push(split);
|
||||||
|
|
||||||
|
let date0 = tzDate(split);
|
||||||
|
|
||||||
|
let prevHour = date0[getHours]() + (date0[getMinutes]() / m) + (date0[getSeconds]() / h);
|
||||||
|
let incrHours = foundIncr / h;
|
||||||
|
|
||||||
|
let minSpace = self.axes[axisIdx]._space;
|
||||||
|
let pctSpace = foundSpace / minSpace;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
split = roundDec(split + foundIncr, ms == 1 ? 0 : 3);
|
||||||
|
|
||||||
|
if (split > scaleMax)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (incrHours > 1) {
|
||||||
|
let expectedHour = floor(roundDec(prevHour + incrHours, 6)) % 24;
|
||||||
|
let splitDate = tzDate(split);
|
||||||
|
let actualHour = splitDate.getHours();
|
||||||
|
|
||||||
|
let dstShift = actualHour - expectedHour;
|
||||||
|
|
||||||
|
if (dstShift > 1)
|
||||||
|
dstShift = -1;
|
||||||
|
|
||||||
|
split -= dstShift * h;
|
||||||
|
|
||||||
|
prevHour = (prevHour + incrHours) % 24;
|
||||||
|
|
||||||
|
// add a tick only if it's further than 70% of the min allowed label spacing
|
||||||
|
let prevSplit = splits[splits.length - 1];
|
||||||
|
let pctIncr = roundDec((split - prevSplit) / foundIncr, 3);
|
||||||
|
|
||||||
|
if (pctIncr * pctSpace >= .7)
|
||||||
|
splits.push(split);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
splits.push(split);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return splits;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
timeIncrs,
|
||||||
|
_timeAxisStamps,
|
||||||
|
timeAxisSplits,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
const [ timeIncrsMs, _timeAxisStampsMs, timeAxisSplitsMs ] = genTimeStuffs(1);
|
||||||
|
const [ timeIncrsS, _timeAxisStampsS, timeAxisSplitsS ] = genTimeStuffs(1e-3);
|
||||||
|
|
||||||
// base 2
|
// base 2
|
||||||
const binIncrs = genIncrs(2, -53, 53, [1]);
|
const binIncrs = genIncrs(2, -53, 53, [1]);
|
||||||
|
@ -641,37 +770,6 @@ function timeAxisStamps(stampCfg, fmtDate) {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
const NL = "\n";
|
|
||||||
|
|
||||||
const yyyy = "{YYYY}";
|
|
||||||
const NLyyyy = NL + yyyy;
|
|
||||||
const md = "{M}/{D}";
|
|
||||||
const NLmd = NL + md;
|
|
||||||
const NLmdyy = NLmd + "/{YY}";
|
|
||||||
|
|
||||||
const aa = "{aa}";
|
|
||||||
const hmm = "{h}:{mm}";
|
|
||||||
const hmmaa = hmm + aa;
|
|
||||||
const NLhmmaa = NL + hmmaa;
|
|
||||||
const ss = ":{ss}";
|
|
||||||
|
|
||||||
const _ = null;
|
|
||||||
|
|
||||||
// [0]: minimum num secs in the tick incr
|
|
||||||
// [1]: default tick format
|
|
||||||
// [2-7]: rollover tick formats
|
|
||||||
// [8]: mode: 0: replace [1] -> [2-7], 1: concat [1] + [2-7]
|
|
||||||
const _timeAxisStamps = [
|
|
||||||
// tick incr default year month day hour min sec mode
|
|
||||||
[y, yyyy, _, _, _, _, _, _, 1],
|
|
||||||
[d * 28, "{MMM}", NLyyyy, _, _, _, _, _, 1],
|
|
||||||
[d, md, NLyyyy, _, _, _, _, _, 1],
|
|
||||||
[h, "{h}" + aa, NLmdyy, _, NLmd, _, _, _, 1],
|
|
||||||
[m, hmmaa, NLmdyy, _, NLmd, _, _, _, 1],
|
|
||||||
[s, ss, NLmdyy + " " + hmmaa, _, NLmd + " " + hmmaa, _, NLhmmaa, _, 1],
|
|
||||||
[1e-3, ss + ".{fff}", NLmdyy + " " + hmmaa, _, NLmd + " " + hmmaa, _, NLhmmaa, _, 1],
|
|
||||||
];
|
|
||||||
|
|
||||||
// TODO: will need to accept spaces[] and pull incr into the loop when grid will be non-uniform, eg for log scales.
|
// TODO: will need to accept spaces[] and pull incr into the loop when grid will be non-uniform, eg for log scales.
|
||||||
// currently we ignore this for months since they're *nearly* uniform and the added complexity is not worth it
|
// currently we ignore this for months since they're *nearly* uniform and the added complexity is not worth it
|
||||||
function timeAxisVals(tzDate, stamps) {
|
function timeAxisVals(tzDate, stamps) {
|
||||||
|
@ -728,93 +826,6 @@ function mkDate(y, m, d) {
|
||||||
return new Date(y, m, d);
|
return new Date(y, m, d);
|
||||||
}
|
}
|
||||||
|
|
||||||
// the ensures that axis ticks, values & grid are aligned to logical temporal breakpoints and not an arbitrary timestamp
|
|
||||||
// https://www.timeanddate.com/time/dst/
|
|
||||||
// https://www.timeanddate.com/time/dst/2019.html
|
|
||||||
// https://www.epochconverter.com/timezones
|
|
||||||
function timeAxisSplits(tzDate) {
|
|
||||||
return (self, axisIdx, scaleMin, scaleMax, foundIncr, foundSpace) => {
|
|
||||||
let splits = [];
|
|
||||||
let isYr = foundIncr >= y;
|
|
||||||
let isMo = foundIncr >= mo && foundIncr < y;
|
|
||||||
|
|
||||||
// get the timezone-adjusted date
|
|
||||||
let minDate = tzDate(scaleMin);
|
|
||||||
let minDateTs = minDate / 1e3;
|
|
||||||
|
|
||||||
// get ts of 12am (this lands us at or before the original scaleMin)
|
|
||||||
let minMin = mkDate(minDate[getFullYear](), isYr ? 0 : minDate[getMonth](), isMo || isYr ? 1 : minDate[getDate]());
|
|
||||||
let minMinTs = minMin / 1e3;
|
|
||||||
|
|
||||||
if (isMo || isYr) {
|
|
||||||
let moIncr = isMo ? foundIncr / mo : 0;
|
|
||||||
let yrIncr = isYr ? foundIncr / y : 0;
|
|
||||||
// let tzOffset = scaleMin - minDateTs; // needed?
|
|
||||||
let split = minDateTs == minMinTs ? minDateTs : mkDate(minMin[getFullYear]() + yrIncr, minMin[getMonth]() + moIncr, 1) / 1e3;
|
|
||||||
let splitDate = new Date(split * 1e3);
|
|
||||||
let baseYear = splitDate[getFullYear]();
|
|
||||||
let baseMonth = splitDate[getMonth]();
|
|
||||||
|
|
||||||
for (let i = 0; split <= scaleMax; i++) {
|
|
||||||
let next = mkDate(baseYear + yrIncr * i, baseMonth + moIncr * i, 1);
|
|
||||||
let offs = next - tzDate(next / 1e3);
|
|
||||||
|
|
||||||
split = (+next + offs) / 1e3;
|
|
||||||
|
|
||||||
if (split <= scaleMax)
|
|
||||||
splits.push(split);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
let incr0 = foundIncr >= d ? d : foundIncr;
|
|
||||||
let tzOffset = floor(scaleMin) - floor(minDateTs);
|
|
||||||
let split = minMinTs + tzOffset + incrRoundUp(minDateTs - minMinTs, incr0);
|
|
||||||
splits.push(split);
|
|
||||||
|
|
||||||
let date0 = tzDate(split);
|
|
||||||
|
|
||||||
let prevHour = date0[getHours]() + (date0[getMinutes]() / m) + (date0[getSeconds]() / h);
|
|
||||||
let incrHours = foundIncr / h;
|
|
||||||
|
|
||||||
let minSpace = self.axes[axisIdx]._space;
|
|
||||||
let pctSpace = foundSpace / minSpace;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
split = roundDec(split + foundIncr, 3);
|
|
||||||
|
|
||||||
if (split > scaleMax)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (incrHours > 1) {
|
|
||||||
let expectedHour = floor(roundDec(prevHour + incrHours, 6)) % 24;
|
|
||||||
let splitDate = tzDate(split);
|
|
||||||
let actualHour = splitDate.getHours();
|
|
||||||
|
|
||||||
let dstShift = actualHour - expectedHour;
|
|
||||||
|
|
||||||
if (dstShift > 1)
|
|
||||||
dstShift = -1;
|
|
||||||
|
|
||||||
split -= dstShift * h;
|
|
||||||
|
|
||||||
prevHour = (prevHour + incrHours) % 24;
|
|
||||||
|
|
||||||
// add a tick only if it's further than 70% of the min allowed label spacing
|
|
||||||
let prevSplit = splits[splits.length - 1];
|
|
||||||
let pctIncr = roundDec((split - prevSplit) / foundIncr, 3);
|
|
||||||
|
|
||||||
if (pctIncr * pctSpace >= .7)
|
|
||||||
splits.push(split);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
splits.push(split);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return splits;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function timeSeriesStamp(stampCfg, fmtDate) {
|
function timeSeriesStamp(stampCfg, fmtDate) {
|
||||||
return fmtDate(stampCfg);
|
return fmtDate(stampCfg);
|
||||||
}
|
}
|
||||||
|
@ -1238,7 +1249,7 @@ function uPlot(opts, data, then) {
|
||||||
opts = p.opts(self, opts) || opts;
|
opts = p.opts(self, opts) || opts;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const ms = opts.ms || 1e-3;
|
||||||
|
|
||||||
const series = self.series = setDefaults(opts.series || [], xSeriesOpts, ySeriesOpts, false);
|
const series = self.series = setDefaults(opts.series || [], xSeriesOpts, ySeriesOpts, false);
|
||||||
const axes = self.axes = setDefaults(opts.axes || [], xAxisOpts, yAxisOpts, true);
|
const axes = self.axes = setDefaults(opts.axes || [], xAxisOpts, yAxisOpts, true);
|
||||||
|
@ -1314,11 +1325,11 @@ function uPlot(opts, data, then) {
|
||||||
gutters._y = gutters.y(self);
|
gutters._y = gutters.y(self);
|
||||||
|
|
||||||
// self.tz = opts.tz || Intl.DateTimeFormat().resolvedOptions().timeZone;
|
// self.tz = opts.tz || Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||||
const _tzDate = (opts.tzDate || (ts => new Date(ts * 1e3)));
|
const _tzDate = (opts.tzDate || (ts => new Date(ts / ms)));
|
||||||
const _fmtDate = (opts.fmtDate || fmtDate);
|
const _fmtDate = (opts.fmtDate || fmtDate);
|
||||||
|
|
||||||
const _timeAxisSplits = timeAxisSplits(_tzDate);
|
const _timeAxisSplits = (ms == 1 ? timeAxisSplitsMs(_tzDate) : timeAxisSplitsS(_tzDate));
|
||||||
const _timeAxisVals = timeAxisVals(_tzDate, timeAxisStamps(_timeAxisStamps, _fmtDate));
|
const _timeAxisVals = timeAxisVals(_tzDate, timeAxisStamps((ms == 1 ? _timeAxisStampsMs : _timeAxisStampsS), _fmtDate));
|
||||||
const _timeSeriesVal = timeSeriesVal(_tzDate, timeSeriesStamp(_timeSeriesStamp, _fmtDate));
|
const _timeSeriesVal = timeSeriesVal(_tzDate, timeSeriesStamp(_timeSeriesStamp, _fmtDate));
|
||||||
|
|
||||||
const legend = assign({show: true, live: true}, opts.legend);
|
const legend = assign({show: true, live: true}, opts.legend);
|
||||||
|
@ -1474,9 +1485,13 @@ function uPlot(opts, data, then) {
|
||||||
function convergeSize() {
|
function convergeSize() {
|
||||||
let converged = false;
|
let converged = false;
|
||||||
|
|
||||||
|
let cycleNum = 0;
|
||||||
|
|
||||||
while (!converged) {
|
while (!converged) {
|
||||||
let axesConverged = axesCalc();
|
cycleNum++;
|
||||||
let guttersConverged = guttersCalc();
|
|
||||||
|
let axesConverged = axesCalc(cycleNum);
|
||||||
|
let guttersConverged = guttersCalc(cycleNum);
|
||||||
|
|
||||||
converged = axesConverged && guttersConverged;
|
converged = axesConverged && guttersConverged;
|
||||||
|
|
||||||
|
@ -1684,7 +1699,7 @@ function uPlot(opts, data, then) {
|
||||||
axis.size = fnOrSelf(axis.size);
|
axis.size = fnOrSelf(axis.size);
|
||||||
axis.space = fnOrSelf(axis.space);
|
axis.space = fnOrSelf(axis.space);
|
||||||
axis.rotate = fnOrSelf(axis.rotate);
|
axis.rotate = fnOrSelf(axis.rotate);
|
||||||
axis.incrs = fnOrSelf(axis.incrs || ( sc.distr == 2 ? wholeIncrs : (isTime ? timeIncrs : numIncrs)));
|
axis.incrs = fnOrSelf(axis.incrs || ( sc.distr == 2 ? wholeIncrs : (isTime ? (ms == 1 ? timeIncrsMs : timeIncrsS) : numIncrs)));
|
||||||
axis.splits = fnOrSelf(axis.splits || (isTime && sc.distr == 1 ? _timeAxisSplits : sc.distr == 3 ? logAxisSplits : numAxisSplits));
|
axis.splits = fnOrSelf(axis.splits || (isTime && sc.distr == 1 ? _timeAxisSplits : sc.distr == 3 ? logAxisSplits : numAxisSplits));
|
||||||
|
|
||||||
let av = axis.values;
|
let av = axis.values;
|
||||||
|
@ -1703,7 +1718,7 @@ function uPlot(opts, data, then) {
|
||||||
axis.font = pxRatioFont(axis.font);
|
axis.font = pxRatioFont(axis.font);
|
||||||
axis.labelFont = pxRatioFont(axis.labelFont);
|
axis.labelFont = pxRatioFont(axis.labelFont);
|
||||||
|
|
||||||
axis._size = axis.size(self, null, i);
|
axis._size = axis.size(self, null, i, 0);
|
||||||
|
|
||||||
axis._space =
|
axis._space =
|
||||||
axis._rotate =
|
axis._rotate =
|
||||||
|
@ -1786,7 +1801,7 @@ function uPlot(opts, data, then) {
|
||||||
if (xScaleDistr == 3)
|
if (xScaleDistr == 3)
|
||||||
[_min, _max] = rangeLog(_min, _min, scales[xScaleKey].log, false);
|
[_min, _max] = rangeLog(_min, _min, scales[xScaleKey].log, false);
|
||||||
else if (scales[xScaleKey].time)
|
else if (scales[xScaleKey].time)
|
||||||
_max = _min + 86400;
|
_max = _min + 86400 / ms;
|
||||||
else
|
else
|
||||||
[_min, _max] = rangeNum(_min, _max, 0.1, true);
|
[_min, _max] = rangeNum(_min, _max, 0.1, true);
|
||||||
}
|
}
|
||||||
|
@ -2324,7 +2339,7 @@ function uPlot(opts, data, then) {
|
||||||
ctx.translate(-offset, -offset);
|
ctx.translate(-offset, -offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
function axesCalc() {
|
function axesCalc(cycleNum) {
|
||||||
// log("axesCalc()", arguments);
|
// log("axesCalc()", arguments);
|
||||||
|
|
||||||
let converged = true;
|
let converged = true;
|
||||||
|
@ -2378,7 +2393,7 @@ function uPlot(opts, data, then) {
|
||||||
|
|
||||||
let oldSize = axis._size;
|
let oldSize = axis._size;
|
||||||
|
|
||||||
axis._size = axis.size(self, values, i);
|
axis._size = ceil(axis.size(self, values, i, cycleNum));
|
||||||
|
|
||||||
if (oldSize != null && axis._size != oldSize) // ready && ?
|
if (oldSize != null && axis._size != oldSize) // ready && ?
|
||||||
converged = false;
|
converged = false;
|
||||||
|
@ -2387,13 +2402,13 @@ function uPlot(opts, data, then) {
|
||||||
return converged;
|
return converged;
|
||||||
}
|
}
|
||||||
|
|
||||||
function guttersCalc() {
|
function guttersCalc(cycleNum) {
|
||||||
let converged = true;
|
let converged = true;
|
||||||
|
|
||||||
let {_x, _y} = gutters;
|
let {_x, _y} = gutters;
|
||||||
|
|
||||||
gutters._x = gutters.x(self);
|
gutters._x = ceil(gutters.x(self, cycleNum));
|
||||||
gutters._y = gutters.y(self);
|
gutters._y = ceil(gutters.y(self, cycleNum));
|
||||||
|
|
||||||
if (gutters._x != _x || gutters._y != _y)
|
if (gutters._x != _x || gutters._y != _y)
|
||||||
converged = false;
|
converged = false;
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
*
|
*
|
||||||
* uPlot.js (μPlot)
|
* uPlot.js (μPlot)
|
||||||
* A small, fast chart for time series, lines, areas, ohlc & bars
|
* A small, fast chart for time series, lines, areas, ohlc & bars
|
||||||
* https://github.com/leeoniya/uPlot (v1.4.4)
|
* https://github.com/leeoniya/uPlot (v1.4.6)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var uPlot = (function () {
|
var uPlot = (function () {
|
||||||
|
@ -552,8 +552,6 @@ var uPlot = (function () {
|
||||||
|
|
||||||
var allMults = [1,2,2.5,5];
|
var allMults = [1,2,2.5,5];
|
||||||
|
|
||||||
var wholeMults = allMults.filter(onlyWhole);
|
|
||||||
|
|
||||||
// ...0.01, 0.02, 0.025, 0.05, 0.1, 0.2, 0.25, 0.5
|
// ...0.01, 0.02, 0.025, 0.05, 0.1, 0.2, 0.25, 0.5
|
||||||
var decIncrs = genIncrs(10, -16, 0, allMults);
|
var decIncrs = genIncrs(10, -16, 0, allMults);
|
||||||
|
|
||||||
|
@ -565,61 +563,196 @@ var uPlot = (function () {
|
||||||
|
|
||||||
var numIncrs = decIncrs.concat(oneIncrs);
|
var numIncrs = decIncrs.concat(oneIncrs);
|
||||||
|
|
||||||
var s = 1,
|
var NL = "\n";
|
||||||
m = 60,
|
|
||||||
h = m * m,
|
|
||||||
d = h * 24,
|
|
||||||
mo = d * 30,
|
|
||||||
y = d * 365;
|
|
||||||
|
|
||||||
// min of 1e-3 prevents setting a temporal x ticks too small since Date objects cannot advance ticks smaller than 1ms
|
var yyyy = "{YYYY}";
|
||||||
var timeIncrs = genIncrs(10, -3, 0, wholeMults).concat([
|
var NLyyyy = NL + yyyy;
|
||||||
// minute divisors (# of secs)
|
var md = "{M}/{D}";
|
||||||
1,
|
var NLmd = NL + md;
|
||||||
5,
|
var NLmdyy = NLmd + "/{YY}";
|
||||||
10,
|
|
||||||
15,
|
var aa = "{aa}";
|
||||||
30,
|
var hmm = "{h}:{mm}";
|
||||||
// hour divisors (# of mins)
|
var hmmaa = hmm + aa;
|
||||||
m,
|
var NLhmmaa = NL + hmmaa;
|
||||||
m * 5,
|
var ss = ":{ss}";
|
||||||
m * 10,
|
|
||||||
m * 15,
|
var _ = null;
|
||||||
m * 30,
|
|
||||||
// day divisors (# of hrs)
|
function genTimeStuffs(ms) {
|
||||||
h,
|
var s = ms * 1e3,
|
||||||
h * 2,
|
m = s * 60,
|
||||||
h * 3,
|
h = m * 60,
|
||||||
h * 4,
|
d = h * 24,
|
||||||
h * 6,
|
mo = d * 30,
|
||||||
h * 8,
|
y = d * 365;
|
||||||
h * 12,
|
|
||||||
// month divisors TODO: need more?
|
// min of 1e-3 prevents setting a temporal x ticks too small since Date objects cannot advance ticks smaller than 1ms
|
||||||
d,
|
var subSecIncrs = ms == 1 ? genIncrs(10, 0, 3, allMults).filter(onlyWhole) : genIncrs(10, -3, 0, allMults);
|
||||||
d * 2,
|
|
||||||
d * 3,
|
var timeIncrs = subSecIncrs.concat([
|
||||||
d * 4,
|
// minute divisors (# of secs)
|
||||||
d * 5,
|
s,
|
||||||
d * 6,
|
s * 5,
|
||||||
d * 7,
|
s * 10,
|
||||||
d * 8,
|
s * 15,
|
||||||
d * 9,
|
s * 30,
|
||||||
d * 10,
|
// hour divisors (# of mins)
|
||||||
d * 15,
|
m,
|
||||||
// year divisors (# months, approx)
|
m * 5,
|
||||||
mo,
|
m * 10,
|
||||||
mo * 2,
|
m * 15,
|
||||||
mo * 3,
|
m * 30,
|
||||||
mo * 4,
|
// day divisors (# of hrs)
|
||||||
mo * 6,
|
h,
|
||||||
// century divisors
|
h * 2,
|
||||||
y,
|
h * 3,
|
||||||
y * 2,
|
h * 4,
|
||||||
y * 5,
|
h * 6,
|
||||||
y * 10,
|
h * 8,
|
||||||
y * 25,
|
h * 12,
|
||||||
y * 50,
|
// month divisors TODO: need more?
|
||||||
y * 100 ]);
|
d,
|
||||||
|
d * 2,
|
||||||
|
d * 3,
|
||||||
|
d * 4,
|
||||||
|
d * 5,
|
||||||
|
d * 6,
|
||||||
|
d * 7,
|
||||||
|
d * 8,
|
||||||
|
d * 9,
|
||||||
|
d * 10,
|
||||||
|
d * 15,
|
||||||
|
// year divisors (# months, approx)
|
||||||
|
mo,
|
||||||
|
mo * 2,
|
||||||
|
mo * 3,
|
||||||
|
mo * 4,
|
||||||
|
mo * 6,
|
||||||
|
// century divisors
|
||||||
|
y,
|
||||||
|
y * 2,
|
||||||
|
y * 5,
|
||||||
|
y * 10,
|
||||||
|
y * 25,
|
||||||
|
y * 50,
|
||||||
|
y * 100 ]);
|
||||||
|
|
||||||
|
// [0]: minimum num secs in the tick incr
|
||||||
|
// [1]: default tick format
|
||||||
|
// [2-7]: rollover tick formats
|
||||||
|
// [8]: mode: 0: replace [1] -> [2-7], 1: concat [1] + [2-7]
|
||||||
|
var _timeAxisStamps = [
|
||||||
|
// tick incr default year month day hour min sec mode
|
||||||
|
[y, yyyy, _, _, _, _, _, _, 1],
|
||||||
|
[d * 28, "{MMM}", NLyyyy, _, _, _, _, _, 1],
|
||||||
|
[d, md, NLyyyy, _, _, _, _, _, 1],
|
||||||
|
[h, "{h}" + aa, NLmdyy, _, NLmd, _, _, _, 1],
|
||||||
|
[m, hmmaa, NLmdyy, _, NLmd, _, _, _, 1],
|
||||||
|
[s, ss, NLmdyy + " " + hmmaa, _, NLmd + " " + hmmaa, _, NLhmmaa, _, 1],
|
||||||
|
[ms, ss + ".{fff}", NLmdyy + " " + hmmaa, _, NLmd + " " + hmmaa, _, NLhmmaa, _, 1] ];
|
||||||
|
|
||||||
|
// the ensures that axis ticks, values & grid are aligned to logical temporal breakpoints and not an arbitrary timestamp
|
||||||
|
// https://www.timeanddate.com/time/dst/
|
||||||
|
// https://www.timeanddate.com/time/dst/2019.html
|
||||||
|
// https://www.epochconverter.com/timezones
|
||||||
|
function timeAxisSplits(tzDate) {
|
||||||
|
return function (self, axisIdx, scaleMin, scaleMax, foundIncr, foundSpace) {
|
||||||
|
var splits = [];
|
||||||
|
var isYr = foundIncr >= y;
|
||||||
|
var isMo = foundIncr >= mo && foundIncr < y;
|
||||||
|
|
||||||
|
// get the timezone-adjusted date
|
||||||
|
var minDate = tzDate(scaleMin);
|
||||||
|
var minDateTs = minDate * ms;
|
||||||
|
|
||||||
|
// get ts of 12am (this lands us at or before the original scaleMin)
|
||||||
|
var minMin = mkDate(minDate[getFullYear](), isYr ? 0 : minDate[getMonth](), isMo || isYr ? 1 : minDate[getDate]());
|
||||||
|
var minMinTs = minMin * ms;
|
||||||
|
|
||||||
|
if (isMo || isYr) {
|
||||||
|
var moIncr = isMo ? foundIncr / mo : 0;
|
||||||
|
var yrIncr = isYr ? foundIncr / y : 0;
|
||||||
|
// let tzOffset = scaleMin - minDateTs; // needed?
|
||||||
|
var split = minDateTs == minMinTs ? minDateTs : mkDate(minMin[getFullYear]() + yrIncr, minMin[getMonth]() + moIncr, 1) * ms;
|
||||||
|
var splitDate = new Date(split / ms);
|
||||||
|
var baseYear = splitDate[getFullYear]();
|
||||||
|
var baseMonth = splitDate[getMonth]();
|
||||||
|
|
||||||
|
for (var i = 0; split <= scaleMax; i++) {
|
||||||
|
var next = mkDate(baseYear + yrIncr * i, baseMonth + moIncr * i, 1);
|
||||||
|
var offs = next - tzDate(next * ms);
|
||||||
|
|
||||||
|
split = (+next + offs) * ms;
|
||||||
|
|
||||||
|
if (split <= scaleMax)
|
||||||
|
{ splits.push(split); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var incr0 = foundIncr >= d ? d : foundIncr;
|
||||||
|
var tzOffset = floor(scaleMin) - floor(minDateTs);
|
||||||
|
var split$1 = minMinTs + tzOffset + incrRoundUp(minDateTs - minMinTs, incr0);
|
||||||
|
splits.push(split$1);
|
||||||
|
|
||||||
|
var date0 = tzDate(split$1);
|
||||||
|
|
||||||
|
var prevHour = date0[getHours]() + (date0[getMinutes]() / m) + (date0[getSeconds]() / h);
|
||||||
|
var incrHours = foundIncr / h;
|
||||||
|
|
||||||
|
var minSpace = self.axes[axisIdx]._space;
|
||||||
|
var pctSpace = foundSpace / minSpace;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
split$1 = roundDec(split$1 + foundIncr, ms == 1 ? 0 : 3);
|
||||||
|
|
||||||
|
if (split$1 > scaleMax)
|
||||||
|
{ break; }
|
||||||
|
|
||||||
|
if (incrHours > 1) {
|
||||||
|
var expectedHour = floor(roundDec(prevHour + incrHours, 6)) % 24;
|
||||||
|
var splitDate$1 = tzDate(split$1);
|
||||||
|
var actualHour = splitDate$1.getHours();
|
||||||
|
|
||||||
|
var dstShift = actualHour - expectedHour;
|
||||||
|
|
||||||
|
if (dstShift > 1)
|
||||||
|
{ dstShift = -1; }
|
||||||
|
|
||||||
|
split$1 -= dstShift * h;
|
||||||
|
|
||||||
|
prevHour = (prevHour + incrHours) % 24;
|
||||||
|
|
||||||
|
// add a tick only if it's further than 70% of the min allowed label spacing
|
||||||
|
var prevSplit = splits[splits.length - 1];
|
||||||
|
var pctIncr = roundDec((split$1 - prevSplit) / foundIncr, 3);
|
||||||
|
|
||||||
|
if (pctIncr * pctSpace >= .7)
|
||||||
|
{ splits.push(split$1); }
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ splits.push(split$1); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return splits;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
timeIncrs,
|
||||||
|
_timeAxisStamps,
|
||||||
|
timeAxisSplits ];
|
||||||
|
}
|
||||||
|
|
||||||
|
var ref = genTimeStuffs(1);
|
||||||
|
var timeIncrsMs = ref[0];
|
||||||
|
var _timeAxisStampsMs = ref[1];
|
||||||
|
var timeAxisSplitsMs = ref[2];
|
||||||
|
var ref$1 = genTimeStuffs(1e-3);
|
||||||
|
var timeIncrsS = ref$1[0];
|
||||||
|
var _timeAxisStampsS = ref$1[1];
|
||||||
|
var timeAxisSplitsS = ref$1[2];
|
||||||
|
|
||||||
// base 2
|
// base 2
|
||||||
var binIncrs = genIncrs(2, -53, 53, [1]);
|
var binIncrs = genIncrs(2, -53, 53, [1]);
|
||||||
|
@ -640,36 +773,6 @@ var uPlot = (function () {
|
||||||
); });
|
); });
|
||||||
}
|
}
|
||||||
|
|
||||||
var NL = "\n";
|
|
||||||
|
|
||||||
var yyyy = "{YYYY}";
|
|
||||||
var NLyyyy = NL + yyyy;
|
|
||||||
var md = "{M}/{D}";
|
|
||||||
var NLmd = NL + md;
|
|
||||||
var NLmdyy = NLmd + "/{YY}";
|
|
||||||
|
|
||||||
var aa = "{aa}";
|
|
||||||
var hmm = "{h}:{mm}";
|
|
||||||
var hmmaa = hmm + aa;
|
|
||||||
var NLhmmaa = NL + hmmaa;
|
|
||||||
var ss = ":{ss}";
|
|
||||||
|
|
||||||
var _ = null;
|
|
||||||
|
|
||||||
// [0]: minimum num secs in the tick incr
|
|
||||||
// [1]: default tick format
|
|
||||||
// [2-7]: rollover tick formats
|
|
||||||
// [8]: mode: 0: replace [1] -> [2-7], 1: concat [1] + [2-7]
|
|
||||||
var _timeAxisStamps = [
|
|
||||||
// tick incr default year month day hour min sec mode
|
|
||||||
[y, yyyy, _, _, _, _, _, _, 1],
|
|
||||||
[d * 28, "{MMM}", NLyyyy, _, _, _, _, _, 1],
|
|
||||||
[d, md, NLyyyy, _, _, _, _, _, 1],
|
|
||||||
[h, "{h}" + aa, NLmdyy, _, NLmd, _, _, _, 1],
|
|
||||||
[m, hmmaa, NLmdyy, _, NLmd, _, _, _, 1],
|
|
||||||
[s, ss, NLmdyy + " " + hmmaa, _, NLmd + " " + hmmaa, _, NLhmmaa, _, 1],
|
|
||||||
[1e-3, ss + ".{fff}", NLmdyy + " " + hmmaa, _, NLmd + " " + hmmaa, _, NLhmmaa, _, 1] ];
|
|
||||||
|
|
||||||
// TODO: will need to accept spaces[] and pull incr into the loop when grid will be non-uniform, eg for log scales.
|
// TODO: will need to accept spaces[] and pull incr into the loop when grid will be non-uniform, eg for log scales.
|
||||||
// currently we ignore this for months since they're *nearly* uniform and the added complexity is not worth it
|
// currently we ignore this for months since they're *nearly* uniform and the added complexity is not worth it
|
||||||
function timeAxisVals(tzDate, stamps) {
|
function timeAxisVals(tzDate, stamps) {
|
||||||
|
@ -726,93 +829,6 @@ var uPlot = (function () {
|
||||||
return new Date(y, m, d);
|
return new Date(y, m, d);
|
||||||
}
|
}
|
||||||
|
|
||||||
// the ensures that axis ticks, values & grid are aligned to logical temporal breakpoints and not an arbitrary timestamp
|
|
||||||
// https://www.timeanddate.com/time/dst/
|
|
||||||
// https://www.timeanddate.com/time/dst/2019.html
|
|
||||||
// https://www.epochconverter.com/timezones
|
|
||||||
function timeAxisSplits(tzDate) {
|
|
||||||
return function (self, axisIdx, scaleMin, scaleMax, foundIncr, foundSpace) {
|
|
||||||
var splits = [];
|
|
||||||
var isYr = foundIncr >= y;
|
|
||||||
var isMo = foundIncr >= mo && foundIncr < y;
|
|
||||||
|
|
||||||
// get the timezone-adjusted date
|
|
||||||
var minDate = tzDate(scaleMin);
|
|
||||||
var minDateTs = minDate / 1e3;
|
|
||||||
|
|
||||||
// get ts of 12am (this lands us at or before the original scaleMin)
|
|
||||||
var minMin = mkDate(minDate[getFullYear](), isYr ? 0 : minDate[getMonth](), isMo || isYr ? 1 : minDate[getDate]());
|
|
||||||
var minMinTs = minMin / 1e3;
|
|
||||||
|
|
||||||
if (isMo || isYr) {
|
|
||||||
var moIncr = isMo ? foundIncr / mo : 0;
|
|
||||||
var yrIncr = isYr ? foundIncr / y : 0;
|
|
||||||
// let tzOffset = scaleMin - minDateTs; // needed?
|
|
||||||
var split = minDateTs == minMinTs ? minDateTs : mkDate(minMin[getFullYear]() + yrIncr, minMin[getMonth]() + moIncr, 1) / 1e3;
|
|
||||||
var splitDate = new Date(split * 1e3);
|
|
||||||
var baseYear = splitDate[getFullYear]();
|
|
||||||
var baseMonth = splitDate[getMonth]();
|
|
||||||
|
|
||||||
for (var i = 0; split <= scaleMax; i++) {
|
|
||||||
var next = mkDate(baseYear + yrIncr * i, baseMonth + moIncr * i, 1);
|
|
||||||
var offs = next - tzDate(next / 1e3);
|
|
||||||
|
|
||||||
split = (+next + offs) / 1e3;
|
|
||||||
|
|
||||||
if (split <= scaleMax)
|
|
||||||
{ splits.push(split); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var incr0 = foundIncr >= d ? d : foundIncr;
|
|
||||||
var tzOffset = floor(scaleMin) - floor(minDateTs);
|
|
||||||
var split$1 = minMinTs + tzOffset + incrRoundUp(minDateTs - minMinTs, incr0);
|
|
||||||
splits.push(split$1);
|
|
||||||
|
|
||||||
var date0 = tzDate(split$1);
|
|
||||||
|
|
||||||
var prevHour = date0[getHours]() + (date0[getMinutes]() / m) + (date0[getSeconds]() / h);
|
|
||||||
var incrHours = foundIncr / h;
|
|
||||||
|
|
||||||
var minSpace = self.axes[axisIdx]._space;
|
|
||||||
var pctSpace = foundSpace / minSpace;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
split$1 = roundDec(split$1 + foundIncr, 3);
|
|
||||||
|
|
||||||
if (split$1 > scaleMax)
|
|
||||||
{ break; }
|
|
||||||
|
|
||||||
if (incrHours > 1) {
|
|
||||||
var expectedHour = floor(roundDec(prevHour + incrHours, 6)) % 24;
|
|
||||||
var splitDate$1 = tzDate(split$1);
|
|
||||||
var actualHour = splitDate$1.getHours();
|
|
||||||
|
|
||||||
var dstShift = actualHour - expectedHour;
|
|
||||||
|
|
||||||
if (dstShift > 1)
|
|
||||||
{ dstShift = -1; }
|
|
||||||
|
|
||||||
split$1 -= dstShift * h;
|
|
||||||
|
|
||||||
prevHour = (prevHour + incrHours) % 24;
|
|
||||||
|
|
||||||
// add a tick only if it's further than 70% of the min allowed label spacing
|
|
||||||
var prevSplit = splits[splits.length - 1];
|
|
||||||
var pctIncr = roundDec((split$1 - prevSplit) / foundIncr, 3);
|
|
||||||
|
|
||||||
if (pctIncr * pctSpace >= .7)
|
|
||||||
{ splits.push(split$1); }
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{ splits.push(split$1); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return splits;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function timeSeriesStamp(stampCfg, fmtDate) {
|
function timeSeriesStamp(stampCfg, fmtDate) {
|
||||||
return fmtDate(stampCfg);
|
return fmtDate(stampCfg);
|
||||||
}
|
}
|
||||||
|
@ -1236,7 +1252,7 @@ var uPlot = (function () {
|
||||||
{ opts = p.opts(self, opts) || opts; }
|
{ opts = p.opts(self, opts) || opts; }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var ms = opts.ms || 1e-3;
|
||||||
|
|
||||||
var series = self.series = setDefaults(opts.series || [], xSeriesOpts, ySeriesOpts, false);
|
var series = self.series = setDefaults(opts.series || [], xSeriesOpts, ySeriesOpts, false);
|
||||||
var axes = self.axes = setDefaults(opts.axes || [], xAxisOpts, yAxisOpts, true);
|
var axes = self.axes = setDefaults(opts.axes || [], xAxisOpts, yAxisOpts, true);
|
||||||
|
@ -1312,11 +1328,11 @@ var uPlot = (function () {
|
||||||
gutters._y = gutters.y(self);
|
gutters._y = gutters.y(self);
|
||||||
|
|
||||||
// self.tz = opts.tz || Intl.DateTimeFormat().resolvedOptions().timeZone;
|
// self.tz = opts.tz || Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||||
var _tzDate = (opts.tzDate || (function (ts) { return new Date(ts * 1e3); }));
|
var _tzDate = (opts.tzDate || (function (ts) { return new Date(ts / ms); }));
|
||||||
var _fmtDate = (opts.fmtDate || fmtDate);
|
var _fmtDate = (opts.fmtDate || fmtDate);
|
||||||
|
|
||||||
var _timeAxisSplits = timeAxisSplits(_tzDate);
|
var _timeAxisSplits = (ms == 1 ? timeAxisSplitsMs(_tzDate) : timeAxisSplitsS(_tzDate));
|
||||||
var _timeAxisVals = timeAxisVals(_tzDate, timeAxisStamps(_timeAxisStamps, _fmtDate));
|
var _timeAxisVals = timeAxisVals(_tzDate, timeAxisStamps((ms == 1 ? _timeAxisStampsMs : _timeAxisStampsS), _fmtDate));
|
||||||
var _timeSeriesVal = timeSeriesVal(_tzDate, timeSeriesStamp(_timeSeriesStamp, _fmtDate));
|
var _timeSeriesVal = timeSeriesVal(_tzDate, timeSeriesStamp(_timeSeriesStamp, _fmtDate));
|
||||||
|
|
||||||
var legend = assign({show: true, live: true}, opts.legend);
|
var legend = assign({show: true, live: true}, opts.legend);
|
||||||
|
@ -1472,9 +1488,13 @@ var uPlot = (function () {
|
||||||
function convergeSize() {
|
function convergeSize() {
|
||||||
var converged = false;
|
var converged = false;
|
||||||
|
|
||||||
|
var cycleNum = 0;
|
||||||
|
|
||||||
while (!converged) {
|
while (!converged) {
|
||||||
var axesConverged = axesCalc();
|
cycleNum++;
|
||||||
var guttersConverged = guttersCalc();
|
|
||||||
|
var axesConverged = axesCalc(cycleNum);
|
||||||
|
var guttersConverged = guttersCalc(cycleNum);
|
||||||
|
|
||||||
converged = axesConverged && guttersConverged;
|
converged = axesConverged && guttersConverged;
|
||||||
|
|
||||||
|
@ -1686,7 +1706,7 @@ var uPlot = (function () {
|
||||||
axis.size = fnOrSelf(axis.size);
|
axis.size = fnOrSelf(axis.size);
|
||||||
axis.space = fnOrSelf(axis.space);
|
axis.space = fnOrSelf(axis.space);
|
||||||
axis.rotate = fnOrSelf(axis.rotate);
|
axis.rotate = fnOrSelf(axis.rotate);
|
||||||
axis.incrs = fnOrSelf(axis.incrs || ( sc.distr == 2 ? wholeIncrs : (isTime ? timeIncrs : numIncrs)));
|
axis.incrs = fnOrSelf(axis.incrs || ( sc.distr == 2 ? wholeIncrs : (isTime ? (ms == 1 ? timeIncrsMs : timeIncrsS) : numIncrs)));
|
||||||
axis.splits = fnOrSelf(axis.splits || (isTime && sc.distr == 1 ? _timeAxisSplits : sc.distr == 3 ? logAxisSplits : numAxisSplits));
|
axis.splits = fnOrSelf(axis.splits || (isTime && sc.distr == 1 ? _timeAxisSplits : sc.distr == 3 ? logAxisSplits : numAxisSplits));
|
||||||
|
|
||||||
var av = axis.values;
|
var av = axis.values;
|
||||||
|
@ -1705,7 +1725,7 @@ var uPlot = (function () {
|
||||||
axis.font = pxRatioFont(axis.font);
|
axis.font = pxRatioFont(axis.font);
|
||||||
axis.labelFont = pxRatioFont(axis.labelFont);
|
axis.labelFont = pxRatioFont(axis.labelFont);
|
||||||
|
|
||||||
axis._size = axis.size(self, null, i);
|
axis._size = axis.size(self, null, i, 0);
|
||||||
|
|
||||||
axis._space =
|
axis._space =
|
||||||
axis._rotate =
|
axis._rotate =
|
||||||
|
@ -1790,7 +1810,7 @@ var uPlot = (function () {
|
||||||
if (xScaleDistr == 3)
|
if (xScaleDistr == 3)
|
||||||
{ (assign = rangeLog(_min, _min, scales[xScaleKey].log, false), _min = assign[0], _max = assign[1]); }
|
{ (assign = rangeLog(_min, _min, scales[xScaleKey].log, false), _min = assign[0], _max = assign[1]); }
|
||||||
else if (scales[xScaleKey].time)
|
else if (scales[xScaleKey].time)
|
||||||
{ _max = _min + 86400; }
|
{ _max = _min + 86400 / ms; }
|
||||||
else
|
else
|
||||||
{ (assign$1 = rangeNum(_min, _max, 0.1, true), _min = assign$1[0], _max = assign$1[1]); }
|
{ (assign$1 = rangeNum(_min, _max, 0.1, true), _min = assign$1[0], _max = assign$1[1]); }
|
||||||
}
|
}
|
||||||
|
@ -2331,7 +2351,7 @@ var uPlot = (function () {
|
||||||
ctx.translate(-offset, -offset);
|
ctx.translate(-offset, -offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
function axesCalc() {
|
function axesCalc(cycleNum) {
|
||||||
// log("axesCalc()", arguments);
|
// log("axesCalc()", arguments);
|
||||||
|
|
||||||
var converged = true;
|
var converged = true;
|
||||||
|
@ -2388,7 +2408,7 @@ var uPlot = (function () {
|
||||||
|
|
||||||
var oldSize = axis._size;
|
var oldSize = axis._size;
|
||||||
|
|
||||||
axis._size = axis.size(self, values, i);
|
axis._size = ceil(axis.size(self, values, i, cycleNum));
|
||||||
|
|
||||||
if (oldSize != null && axis._size != oldSize) // ready && ?
|
if (oldSize != null && axis._size != oldSize) // ready && ?
|
||||||
{ converged = false; }
|
{ converged = false; }
|
||||||
|
@ -2397,14 +2417,14 @@ var uPlot = (function () {
|
||||||
return converged;
|
return converged;
|
||||||
}
|
}
|
||||||
|
|
||||||
function guttersCalc() {
|
function guttersCalc(cycleNum) {
|
||||||
var converged = true;
|
var converged = true;
|
||||||
|
|
||||||
var _x = gutters._x;
|
var _x = gutters._x;
|
||||||
var _y = gutters._y;
|
var _y = gutters._y;
|
||||||
|
|
||||||
gutters._x = gutters.x(self);
|
gutters._x = ceil(gutters.x(self, cycleNum));
|
||||||
gutters._y = gutters.y(self);
|
gutters._y = ceil(gutters.y(self, cycleNum));
|
||||||
|
|
||||||
if (gutters._x != _x || gutters._y != _y)
|
if (gutters._x != _x || gutters._y != _y)
|
||||||
{ converged = false; }
|
{ converged = false; }
|
||||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue