mirror of https://github.com/ColorlibHQ/AdminLTE
Merge branch 'master' of https://github.com/ColorlibHQ/AdminLTE
commit
73a20bcc57
|
@ -434,7 +434,7 @@ body.sidebar-collapse:not(.sidebar-mini-xs):not(.sidebar-mini-md):not(.sidebar-m
|
|||
}
|
||||
}
|
||||
|
||||
body:not(.sidebar-mini-md):not(.sidebar-mini-xs) {
|
||||
body:not(.sidebar-mini-md):not(.sidebar-mini-xs):not(.layout-top-nav) {
|
||||
.content-wrapper,
|
||||
.main-footer,
|
||||
.main-header {
|
||||
|
|
|
@ -11348,9 +11348,9 @@
|
|||
}
|
||||
},
|
||||
"uplot": {
|
||||
"version": "1.4.4",
|
||||
"resolved": "https://registry.npmjs.org/uplot/-/uplot-1.4.4.tgz",
|
||||
"integrity": "sha512-vgV84+by3fGTU4bdpffSvA9FX8ide6MsmlBzOASPDdZCquXmCA+T2qodeNdnBen+7YOeqD9H91epVnF0dQgVKw=="
|
||||
"version": "1.4.6",
|
||||
"resolved": "https://registry.npmjs.org/uplot/-/uplot-1.4.6.tgz",
|
||||
"integrity": "sha512-nw3LdjLFhAqKQF/Rv7QjZICVnjJemOQVj2L3b7889gHBrnC1LwltkzTcawDcbMe6pxo++0KVev9xSC0YCw+m5w=="
|
||||
},
|
||||
"upper-case": {
|
||||
"version": "1.1.3",
|
||||
|
|
|
@ -126,7 +126,7 @@
|
|||
"sweetalert2": "^10.10.2",
|
||||
"tempusdominus-bootstrap-4": "^5.39.0",
|
||||
"toastr": "^2.1.4",
|
||||
"uplot": "^1.4.4"
|
||||
"uplot": "^1.4.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.11.6",
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*
|
||||
* uPlot.js (μPlot)
|
||||
* 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';
|
||||
|
@ -551,8 +551,6 @@ var onlyWhole = function (v) { return v % 1 == 0; };
|
|||
|
||||
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
|
||||
var decIncrs = genIncrs(10, -16, 0, allMults);
|
||||
|
||||
|
@ -564,61 +562,196 @@ var wholeIncrs = oneIncrs.filter(onlyWhole);
|
|||
|
||||
var numIncrs = decIncrs.concat(oneIncrs);
|
||||
|
||||
var s = 1,
|
||||
m = 60,
|
||||
h = m * m,
|
||||
d = h * 24,
|
||||
mo = d * 30,
|
||||
y = d * 365;
|
||||
var NL = "\n";
|
||||
|
||||
// min of 1e-3 prevents setting a temporal x ticks too small since Date objects cannot advance ticks smaller than 1ms
|
||||
var timeIncrs = genIncrs(10, -3, 0, wholeMults).concat([
|
||||
// minute divisors (# of secs)
|
||||
1,
|
||||
5,
|
||||
10,
|
||||
15,
|
||||
30,
|
||||
// hour divisors (# of mins)
|
||||
m,
|
||||
m * 5,
|
||||
m * 10,
|
||||
m * 15,
|
||||
m * 30,
|
||||
// day divisors (# of hrs)
|
||||
h,
|
||||
h * 2,
|
||||
h * 3,
|
||||
h * 4,
|
||||
h * 6,
|
||||
h * 8,
|
||||
h * 12,
|
||||
// month divisors TODO: need more?
|
||||
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 ]);
|
||||
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;
|
||||
|
||||
function genTimeStuffs(ms) {
|
||||
var s = ms * 1e3,
|
||||
m = s * 60,
|
||||
h = m * 60,
|
||||
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 subSecIncrs = ms == 1 ? genIncrs(10, 0, 3, allMults).filter(onlyWhole) : genIncrs(10, -3, 0, allMults);
|
||||
|
||||
var timeIncrs = subSecIncrs.concat([
|
||||
// minute divisors (# of secs)
|
||||
s,
|
||||
s * 5,
|
||||
s * 10,
|
||||
s * 15,
|
||||
s * 30,
|
||||
// hour divisors (# of mins)
|
||||
m,
|
||||
m * 5,
|
||||
m * 10,
|
||||
m * 15,
|
||||
m * 30,
|
||||
// day divisors (# of hrs)
|
||||
h,
|
||||
h * 2,
|
||||
h * 3,
|
||||
h * 4,
|
||||
h * 6,
|
||||
h * 8,
|
||||
h * 12,
|
||||
// month divisors TODO: need more?
|
||||
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
|
||||
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.
|
||||
// currently we ignore this for months since they're *nearly* uniform and the added complexity is not worth it
|
||||
function timeAxisVals(tzDate, stamps) {
|
||||
|
@ -725,93 +828,6 @@ function mkDate(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) {
|
||||
return fmtDate(stampCfg);
|
||||
}
|
||||
|
@ -1235,7 +1251,7 @@ function uPlot(opts, data, then) {
|
|||
{ opts = p.opts(self, opts) || opts; }
|
||||
});
|
||||
|
||||
|
||||
var ms = opts.ms || 1e-3;
|
||||
|
||||
var series = self.series = setDefaults(opts.series || [], xSeriesOpts, ySeriesOpts, false);
|
||||
var axes = self.axes = setDefaults(opts.axes || [], xAxisOpts, yAxisOpts, true);
|
||||
|
@ -1311,11 +1327,11 @@ function uPlot(opts, data, then) {
|
|||
gutters._y = gutters.y(self);
|
||||
|
||||
// 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 _timeAxisSplits = timeAxisSplits(_tzDate);
|
||||
var _timeAxisVals = timeAxisVals(_tzDate, timeAxisStamps(_timeAxisStamps, _fmtDate));
|
||||
var _timeAxisSplits = (ms == 1 ? timeAxisSplitsMs(_tzDate) : timeAxisSplitsS(_tzDate));
|
||||
var _timeAxisVals = timeAxisVals(_tzDate, timeAxisStamps((ms == 1 ? _timeAxisStampsMs : _timeAxisStampsS), _fmtDate));
|
||||
var _timeSeriesVal = timeSeriesVal(_tzDate, timeSeriesStamp(_timeSeriesStamp, _fmtDate));
|
||||
|
||||
var legend = assign({show: true, live: true}, opts.legend);
|
||||
|
@ -1471,9 +1487,13 @@ function uPlot(opts, data, then) {
|
|||
function convergeSize() {
|
||||
var converged = false;
|
||||
|
||||
var cycleNum = 0;
|
||||
|
||||
while (!converged) {
|
||||
var axesConverged = axesCalc();
|
||||
var guttersConverged = guttersCalc();
|
||||
cycleNum++;
|
||||
|
||||
var axesConverged = axesCalc(cycleNum);
|
||||
var guttersConverged = guttersCalc(cycleNum);
|
||||
|
||||
converged = axesConverged && guttersConverged;
|
||||
|
||||
|
@ -1685,7 +1705,7 @@ function uPlot(opts, data, then) {
|
|||
axis.size = fnOrSelf(axis.size);
|
||||
axis.space = fnOrSelf(axis.space);
|
||||
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));
|
||||
|
||||
var av = axis.values;
|
||||
|
@ -1704,7 +1724,7 @@ function uPlot(opts, data, then) {
|
|||
axis.font = pxRatioFont(axis.font);
|
||||
axis.labelFont = pxRatioFont(axis.labelFont);
|
||||
|
||||
axis._size = axis.size(self, null, i);
|
||||
axis._size = axis.size(self, null, i, 0);
|
||||
|
||||
axis._space =
|
||||
axis._rotate =
|
||||
|
@ -1789,7 +1809,7 @@ function uPlot(opts, data, then) {
|
|||
if (xScaleDistr == 3)
|
||||
{ (assign = rangeLog(_min, _min, scales[xScaleKey].log, false), _min = assign[0], _max = assign[1]); }
|
||||
else if (scales[xScaleKey].time)
|
||||
{ _max = _min + 86400; }
|
||||
{ _max = _min + 86400 / ms; }
|
||||
else
|
||||
{ (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);
|
||||
}
|
||||
|
||||
function axesCalc() {
|
||||
function axesCalc(cycleNum) {
|
||||
// log("axesCalc()", arguments);
|
||||
|
||||
var converged = true;
|
||||
|
@ -2387,7 +2407,7 @@ function uPlot(opts, data, then) {
|
|||
|
||||
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 && ?
|
||||
{ converged = false; }
|
||||
|
@ -2396,14 +2416,14 @@ function uPlot(opts, data, then) {
|
|||
return converged;
|
||||
}
|
||||
|
||||
function guttersCalc() {
|
||||
function guttersCalc(cycleNum) {
|
||||
var converged = true;
|
||||
|
||||
var _x = gutters._x;
|
||||
var _y = gutters._y;
|
||||
|
||||
gutters._x = gutters.x(self);
|
||||
gutters._y = gutters.y(self);
|
||||
gutters._x = ceil(gutters.x(self, cycleNum));
|
||||
gutters._y = ceil(gutters.y(self, cycleNum));
|
||||
|
||||
if (gutters._x != _x || gutters._y != _y)
|
||||
{ converged = false; }
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*
|
||||
* uPlot.js (μPlot)
|
||||
* 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) {
|
||||
|
@ -551,8 +551,6 @@ const onlyWhole = v => v % 1 == 0;
|
|||
|
||||
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
|
||||
const decIncrs = genIncrs(10, -16, 0, allMults);
|
||||
|
||||
|
@ -564,62 +562,193 @@ const wholeIncrs = oneIncrs.filter(onlyWhole);
|
|||
|
||||
const numIncrs = decIncrs.concat(oneIncrs);
|
||||
|
||||
let s = 1,
|
||||
m = 60,
|
||||
h = m * m,
|
||||
d = h * 24,
|
||||
mo = d * 30,
|
||||
y = d * 365;
|
||||
const NL = "\n";
|
||||
|
||||
// min of 1e-3 prevents setting a temporal x ticks too small since Date objects cannot advance ticks smaller than 1ms
|
||||
const timeIncrs = genIncrs(10, -3, 0, wholeMults).concat([
|
||||
// minute divisors (# of secs)
|
||||
1,
|
||||
5,
|
||||
10,
|
||||
15,
|
||||
30,
|
||||
// hour divisors (# of mins)
|
||||
m,
|
||||
m * 5,
|
||||
m * 10,
|
||||
m * 15,
|
||||
m * 30,
|
||||
// day divisors (# of hrs)
|
||||
h,
|
||||
h * 2,
|
||||
h * 3,
|
||||
h * 4,
|
||||
h * 6,
|
||||
h * 8,
|
||||
h * 12,
|
||||
// month divisors TODO: need more?
|
||||
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,
|
||||
]);
|
||||
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;
|
||||
|
||||
function genTimeStuffs(ms) {
|
||||
let s = ms * 1e3,
|
||||
m = s * 60,
|
||||
h = m * 60,
|
||||
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
|
||||
let subSecIncrs = ms == 1 ? genIncrs(10, 0, 3, allMults).filter(onlyWhole) : genIncrs(10, -3, 0, allMults);
|
||||
|
||||
let timeIncrs = subSecIncrs.concat([
|
||||
// minute divisors (# of secs)
|
||||
s,
|
||||
s * 5,
|
||||
s * 10,
|
||||
s * 15,
|
||||
s * 30,
|
||||
// hour divisors (# of mins)
|
||||
m,
|
||||
m * 5,
|
||||
m * 10,
|
||||
m * 15,
|
||||
m * 30,
|
||||
// day divisors (# of hrs)
|
||||
h,
|
||||
h * 2,
|
||||
h * 3,
|
||||
h * 4,
|
||||
h * 6,
|
||||
h * 8,
|
||||
h * 12,
|
||||
// month divisors TODO: need more?
|
||||
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
|
||||
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.
|
||||
// currently we ignore this for months since they're *nearly* uniform and the added complexity is not worth it
|
||||
function timeAxisVals(tzDate, stamps) {
|
||||
|
@ -728,93 +826,6 @@ function mkDate(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) {
|
||||
return fmtDate(stampCfg);
|
||||
}
|
||||
|
@ -1238,7 +1249,7 @@ function uPlot(opts, data, then) {
|
|||
opts = p.opts(self, opts) || opts;
|
||||
});
|
||||
|
||||
|
||||
const ms = opts.ms || 1e-3;
|
||||
|
||||
const series = self.series = setDefaults(opts.series || [], xSeriesOpts, ySeriesOpts, false);
|
||||
const axes = self.axes = setDefaults(opts.axes || [], xAxisOpts, yAxisOpts, true);
|
||||
|
@ -1314,11 +1325,11 @@ function uPlot(opts, data, then) {
|
|||
gutters._y = gutters.y(self);
|
||||
|
||||
// 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 _timeAxisSplits = timeAxisSplits(_tzDate);
|
||||
const _timeAxisVals = timeAxisVals(_tzDate, timeAxisStamps(_timeAxisStamps, _fmtDate));
|
||||
const _timeAxisSplits = (ms == 1 ? timeAxisSplitsMs(_tzDate) : timeAxisSplitsS(_tzDate));
|
||||
const _timeAxisVals = timeAxisVals(_tzDate, timeAxisStamps((ms == 1 ? _timeAxisStampsMs : _timeAxisStampsS), _fmtDate));
|
||||
const _timeSeriesVal = timeSeriesVal(_tzDate, timeSeriesStamp(_timeSeriesStamp, _fmtDate));
|
||||
|
||||
const legend = assign({show: true, live: true}, opts.legend);
|
||||
|
@ -1474,9 +1485,13 @@ function uPlot(opts, data, then) {
|
|||
function convergeSize() {
|
||||
let converged = false;
|
||||
|
||||
let cycleNum = 0;
|
||||
|
||||
while (!converged) {
|
||||
let axesConverged = axesCalc();
|
||||
let guttersConverged = guttersCalc();
|
||||
cycleNum++;
|
||||
|
||||
let axesConverged = axesCalc(cycleNum);
|
||||
let guttersConverged = guttersCalc(cycleNum);
|
||||
|
||||
converged = axesConverged && guttersConverged;
|
||||
|
||||
|
@ -1684,7 +1699,7 @@ function uPlot(opts, data, then) {
|
|||
axis.size = fnOrSelf(axis.size);
|
||||
axis.space = fnOrSelf(axis.space);
|
||||
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));
|
||||
|
||||
let av = axis.values;
|
||||
|
@ -1703,7 +1718,7 @@ function uPlot(opts, data, then) {
|
|||
axis.font = pxRatioFont(axis.font);
|
||||
axis.labelFont = pxRatioFont(axis.labelFont);
|
||||
|
||||
axis._size = axis.size(self, null, i);
|
||||
axis._size = axis.size(self, null, i, 0);
|
||||
|
||||
axis._space =
|
||||
axis._rotate =
|
||||
|
@ -1786,7 +1801,7 @@ function uPlot(opts, data, then) {
|
|||
if (xScaleDistr == 3)
|
||||
[_min, _max] = rangeLog(_min, _min, scales[xScaleKey].log, false);
|
||||
else if (scales[xScaleKey].time)
|
||||
_max = _min + 86400;
|
||||
_max = _min + 86400 / ms;
|
||||
else
|
||||
[_min, _max] = rangeNum(_min, _max, 0.1, true);
|
||||
}
|
||||
|
@ -2324,7 +2339,7 @@ function uPlot(opts, data, then) {
|
|||
ctx.translate(-offset, -offset);
|
||||
}
|
||||
|
||||
function axesCalc() {
|
||||
function axesCalc(cycleNum) {
|
||||
// log("axesCalc()", arguments);
|
||||
|
||||
let converged = true;
|
||||
|
@ -2378,7 +2393,7 @@ function uPlot(opts, data, then) {
|
|||
|
||||
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 && ?
|
||||
converged = false;
|
||||
|
@ -2387,13 +2402,13 @@ function uPlot(opts, data, then) {
|
|||
return converged;
|
||||
}
|
||||
|
||||
function guttersCalc() {
|
||||
function guttersCalc(cycleNum) {
|
||||
let converged = true;
|
||||
|
||||
let {_x, _y} = gutters;
|
||||
|
||||
gutters._x = gutters.x(self);
|
||||
gutters._y = gutters.y(self);
|
||||
gutters._x = ceil(gutters.x(self, cycleNum));
|
||||
gutters._y = ceil(gutters.y(self, cycleNum));
|
||||
|
||||
if (gutters._x != _x || gutters._y != _y)
|
||||
converged = false;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*
|
||||
* uPlot.js (μPlot)
|
||||
* 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 () {
|
||||
|
@ -552,8 +552,6 @@ var uPlot = (function () {
|
|||
|
||||
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
|
||||
var decIncrs = genIncrs(10, -16, 0, allMults);
|
||||
|
||||
|
@ -565,61 +563,196 @@ var uPlot = (function () {
|
|||
|
||||
var numIncrs = decIncrs.concat(oneIncrs);
|
||||
|
||||
var s = 1,
|
||||
m = 60,
|
||||
h = m * m,
|
||||
d = h * 24,
|
||||
mo = d * 30,
|
||||
y = d * 365;
|
||||
var NL = "\n";
|
||||
|
||||
// min of 1e-3 prevents setting a temporal x ticks too small since Date objects cannot advance ticks smaller than 1ms
|
||||
var timeIncrs = genIncrs(10, -3, 0, wholeMults).concat([
|
||||
// minute divisors (# of secs)
|
||||
1,
|
||||
5,
|
||||
10,
|
||||
15,
|
||||
30,
|
||||
// hour divisors (# of mins)
|
||||
m,
|
||||
m * 5,
|
||||
m * 10,
|
||||
m * 15,
|
||||
m * 30,
|
||||
// day divisors (# of hrs)
|
||||
h,
|
||||
h * 2,
|
||||
h * 3,
|
||||
h * 4,
|
||||
h * 6,
|
||||
h * 8,
|
||||
h * 12,
|
||||
// month divisors TODO: need more?
|
||||
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 ]);
|
||||
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;
|
||||
|
||||
function genTimeStuffs(ms) {
|
||||
var s = ms * 1e3,
|
||||
m = s * 60,
|
||||
h = m * 60,
|
||||
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 subSecIncrs = ms == 1 ? genIncrs(10, 0, 3, allMults).filter(onlyWhole) : genIncrs(10, -3, 0, allMults);
|
||||
|
||||
var timeIncrs = subSecIncrs.concat([
|
||||
// minute divisors (# of secs)
|
||||
s,
|
||||
s * 5,
|
||||
s * 10,
|
||||
s * 15,
|
||||
s * 30,
|
||||
// hour divisors (# of mins)
|
||||
m,
|
||||
m * 5,
|
||||
m * 10,
|
||||
m * 15,
|
||||
m * 30,
|
||||
// day divisors (# of hrs)
|
||||
h,
|
||||
h * 2,
|
||||
h * 3,
|
||||
h * 4,
|
||||
h * 6,
|
||||
h * 8,
|
||||
h * 12,
|
||||
// month divisors TODO: need more?
|
||||
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
|
||||
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.
|
||||
// currently we ignore this for months since they're *nearly* uniform and the added complexity is not worth it
|
||||
function timeAxisVals(tzDate, stamps) {
|
||||
|
@ -726,93 +829,6 @@ var uPlot = (function () {
|
|||
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) {
|
||||
return fmtDate(stampCfg);
|
||||
}
|
||||
|
@ -1236,7 +1252,7 @@ var uPlot = (function () {
|
|||
{ opts = p.opts(self, opts) || opts; }
|
||||
});
|
||||
|
||||
|
||||
var ms = opts.ms || 1e-3;
|
||||
|
||||
var series = self.series = setDefaults(opts.series || [], xSeriesOpts, ySeriesOpts, false);
|
||||
var axes = self.axes = setDefaults(opts.axes || [], xAxisOpts, yAxisOpts, true);
|
||||
|
@ -1312,11 +1328,11 @@ var uPlot = (function () {
|
|||
gutters._y = gutters.y(self);
|
||||
|
||||
// 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 _timeAxisSplits = timeAxisSplits(_tzDate);
|
||||
var _timeAxisVals = timeAxisVals(_tzDate, timeAxisStamps(_timeAxisStamps, _fmtDate));
|
||||
var _timeAxisSplits = (ms == 1 ? timeAxisSplitsMs(_tzDate) : timeAxisSplitsS(_tzDate));
|
||||
var _timeAxisVals = timeAxisVals(_tzDate, timeAxisStamps((ms == 1 ? _timeAxisStampsMs : _timeAxisStampsS), _fmtDate));
|
||||
var _timeSeriesVal = timeSeriesVal(_tzDate, timeSeriesStamp(_timeSeriesStamp, _fmtDate));
|
||||
|
||||
var legend = assign({show: true, live: true}, opts.legend);
|
||||
|
@ -1472,9 +1488,13 @@ var uPlot = (function () {
|
|||
function convergeSize() {
|
||||
var converged = false;
|
||||
|
||||
var cycleNum = 0;
|
||||
|
||||
while (!converged) {
|
||||
var axesConverged = axesCalc();
|
||||
var guttersConverged = guttersCalc();
|
||||
cycleNum++;
|
||||
|
||||
var axesConverged = axesCalc(cycleNum);
|
||||
var guttersConverged = guttersCalc(cycleNum);
|
||||
|
||||
converged = axesConverged && guttersConverged;
|
||||
|
||||
|
@ -1686,7 +1706,7 @@ var uPlot = (function () {
|
|||
axis.size = fnOrSelf(axis.size);
|
||||
axis.space = fnOrSelf(axis.space);
|
||||
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));
|
||||
|
||||
var av = axis.values;
|
||||
|
@ -1705,7 +1725,7 @@ var uPlot = (function () {
|
|||
axis.font = pxRatioFont(axis.font);
|
||||
axis.labelFont = pxRatioFont(axis.labelFont);
|
||||
|
||||
axis._size = axis.size(self, null, i);
|
||||
axis._size = axis.size(self, null, i, 0);
|
||||
|
||||
axis._space =
|
||||
axis._rotate =
|
||||
|
@ -1790,7 +1810,7 @@ var uPlot = (function () {
|
|||
if (xScaleDistr == 3)
|
||||
{ (assign = rangeLog(_min, _min, scales[xScaleKey].log, false), _min = assign[0], _max = assign[1]); }
|
||||
else if (scales[xScaleKey].time)
|
||||
{ _max = _min + 86400; }
|
||||
{ _max = _min + 86400 / ms; }
|
||||
else
|
||||
{ (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);
|
||||
}
|
||||
|
||||
function axesCalc() {
|
||||
function axesCalc(cycleNum) {
|
||||
// log("axesCalc()", arguments);
|
||||
|
||||
var converged = true;
|
||||
|
@ -2388,7 +2408,7 @@ var uPlot = (function () {
|
|||
|
||||
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 && ?
|
||||
{ converged = false; }
|
||||
|
@ -2397,14 +2417,14 @@ var uPlot = (function () {
|
|||
return converged;
|
||||
}
|
||||
|
||||
function guttersCalc() {
|
||||
function guttersCalc(cycleNum) {
|
||||
var converged = true;
|
||||
|
||||
var _x = gutters._x;
|
||||
var _y = gutters._y;
|
||||
|
||||
gutters._x = gutters.x(self);
|
||||
gutters._y = gutters.y(self);
|
||||
gutters._x = ceil(gutters.x(self, cycleNum));
|
||||
gutters._y = ceil(gutters.y(self, cycleNum));
|
||||
|
||||
if (gutters._x != _x || gutters._y != _y)
|
||||
{ converged = false; }
|
||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue