Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 01ad533

Browse files
authored
Merge pull request plotly#5089 from plotly/improve-weekly-period-positioning
Fixup weekly and quarterly period label positioning and with rangebreaks
2 parents b57760f + 5775048 commit 01ad533

File tree

5 files changed

+652
-86
lines changed

5 files changed

+652
-86
lines changed

src/constants/numerical.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,17 @@ module.exports = {
3131
* to remind us that not all years and months
3232
* have the same length
3333
*/
34+
ONEMAXYEAR: 31622400000, // 366 * ONEDAY
3435
ONEAVGYEAR: 31557600000, // 365.25 days
36+
ONEMINYEAR: 31536000000, // 365 * ONEDAY
37+
ONEMAXQUARTER: 7948800000, // 92 * ONEDAY
3538
ONEAVGQUARTER: 7889400000, // 1/4 of ONEAVGYEAR
39+
ONEMINQUARTER: 7689600000, // 89 * ONEDAY
3640
ONEMAXMONTH: 2678400000, // 31 * ONEDAY
3741
ONEAVGMONTH: 2629800000, // 1/12 of ONEAVGYEAR
3842
ONEMINMONTH: 2419200000, // 28 * ONEDAY
3943
ONEWEEK: 604800000, // 7 * ONEDAY
40-
ONEDAY: 86400000,
44+
ONEDAY: 86400000, // 24 * ONEHOUR
4145
ONEHOUR: 3600000,
4246
ONEMIN: 60000,
4347
ONESEC: 1000,

src/plots/cartesian/axes.js

Lines changed: 102 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,18 @@ var axAttrs = require('./layout_attributes');
2323
var cleanTicks = require('./clean_ticks');
2424

2525
var constants = require('../../constants/numerical');
26+
var ONEMAXYEAR = constants.ONEMAXYEAR;
2627
var ONEAVGYEAR = constants.ONEAVGYEAR;
28+
var ONEMINYEAR = constants.ONEMINYEAR;
29+
var ONEMAXQUARTER = constants.ONEMAXQUARTER;
2730
var ONEAVGQUARTER = constants.ONEAVGQUARTER;
31+
var ONEMINQUARTER = constants.ONEMINQUARTER;
2832
var ONEMAXMONTH = constants.ONEMAXMONTH;
2933
var ONEAVGMONTH = constants.ONEAVGMONTH;
3034
var ONEMINMONTH = constants.ONEMINMONTH;
3135
var ONEWEEK = constants.ONEWEEK;
3236
var ONEDAY = constants.ONEDAY;
37+
var HALFDAY = ONEDAY / 2;
3338
var ONEHOUR = constants.ONEHOUR;
3439
var ONEMIN = constants.ONEMIN;
3540
var ONESEC = constants.ONESEC;
@@ -499,7 +504,7 @@ function autoShiftMonthBins(binStart, data, dtick, dataMin, calendar) {
499504
// will always give a somewhat odd-looking label, until we do something
500505
// smarter like showing the bin boundaries (or the bounds of the actual
501506
// data in each bin)
502-
binStart -= ONEDAY / 2;
507+
binStart -= HALFDAY;
503508
}
504509
var nextBinStart = axes.tickIncrement(binStart, dtick);
505510

@@ -698,22 +703,28 @@ axes.calcTicks = function calcTicks(ax, opts) {
698703
var maxRange = Math.max(rng[0], rng[1]);
699704

700705
var definedDelta;
701-
if(isPeriod && ax.tickformat) {
706+
var tickformat = axes.getTickFormat(ax);
707+
if(isPeriod && tickformat) {
702708
if(
703-
!(/%[fLQsSMHIpX]/.test(ax.tickformat))
709+
!(/%[fLQsSMX]/.test(tickformat))
704710
// %f: microseconds as a decimal number [000000, 999999]
705711
// %L: milliseconds as a decimal number [000, 999]
706712
// %Q: milliseconds since UNIX epoch
707713
// %s: seconds since UNIX epoch
708714
// %S: second as a decimal number [00,61]
709715
// %M: minute as a decimal number [00,59]
710-
// %H: hour (24-hour clock) as a decimal number [00,23]
711-
// %I: hour (12-hour clock) as a decimal number [01,12]
712-
// %p: either AM or PM
713716
// %X: the locale’s time, such as %-I:%M:%S %p
714717
) {
715718
if(
716-
/%[Aadejuwx]/.test(ax.tickformat)
719+
/%[HI]/.test(tickformat)
720+
// %H: hour (24-hour clock) as a decimal number [00,23]
721+
// %I: hour (12-hour clock) as a decimal number [01,12]
722+
) definedDelta = ONEHOUR;
723+
else if(
724+
/%p/.test(tickformat) // %p: either AM or PM
725+
) definedDelta = HALFDAY;
726+
else if(
727+
/%[Aadejuwx]/.test(tickformat)
717728
// %A: full weekday name
718729
// %a: abbreviated weekday name
719730
// %d: zero-padded day of the month as a decimal number [01,31]
@@ -724,75 +735,124 @@ axes.calcTicks = function calcTicks(ax, opts) {
724735
// %x: the locale’s date, such as %-m/%-d/%Y
725736
) definedDelta = ONEDAY;
726737
else if(
727-
/%[UVW]/.test(ax.tickformat)
738+
/%[UVW]/.test(tickformat)
728739
// %U: Sunday-based week of the year as a decimal number [00,53]
729740
// %V: ISO 8601 week of the year as a decimal number [01, 53]
730741
// %W: Monday-based week of the year as a decimal number [00,53]
731742
) definedDelta = ONEWEEK;
732743
else if(
733-
/%[Bbm]/.test(ax.tickformat)
744+
/%[Bbm]/.test(tickformat)
734745
// %B: full month name
735746
// %b: abbreviated month name
736747
// %m: month as a decimal number [01,12]
737748
) definedDelta = ONEAVGMONTH;
738749
else if(
739-
/%[q]/.test(ax.tickformat)
750+
/%[q]/.test(tickformat)
740751
// %q: quarter of the year as a decimal number [1,4]
741752
) definedDelta = ONEAVGQUARTER;
742753
else if(
743-
/%[Yy]/.test(ax.tickformat)
754+
/%[Yy]/.test(tickformat)
744755
// %Y: year with century as a decimal number, such as 1999
745756
// %y: year without century as a decimal number [00,99]
746757
) definedDelta = ONEAVGYEAR;
747758
}
748759
}
749760

750-
var removedPreTick0Label = false;
751-
var ticksOut = new Array(tickVals.length);
761+
var ticksOut = [];
752762
var i;
763+
var prevText;
753764
for(i = 0; i < tickVals.length; i++) {
754765
var _minor = tickVals[i].minor;
755766
var _value = tickVals[i].value;
756767

757-
ticksOut[i] = axes.tickText(
768+
var t = axes.tickText(
758769
ax,
759770
_value,
760771
false, // hover
761772
_minor // noSuffixPrefix
762773
);
763774

764-
if(isPeriod) {
765-
var v = tickVals[i].value;
775+
if(isPeriod && prevText === t.text) continue;
776+
prevText = t.text;
777+
778+
ticksOut.push(t);
779+
}
780+
781+
if(isPeriod) {
782+
var removedPreTick0Label = false;
783+
784+
for(i = 0; i < ticksOut.length; i++) {
785+
var v = ticksOut[i].x;
766786

767787
var a = i;
768788
var b = i + 1;
769-
if(i < tickVals.length - 1) {
789+
if(i < ticksOut.length - 1) {
770790
a = i;
771791
b = i + 1;
772-
} else {
792+
} else if(i > 0) {
773793
a = i - 1;
774794
b = i;
795+
} else {
796+
a = i;
797+
b = i;
775798
}
776799

777-
var A = tickVals[a].value;
778-
var B = tickVals[b].value;
800+
var A = ticksOut[a].x;
801+
var B = ticksOut[b].x;
802+
var actualDelta = Math.abs(B - A);
803+
var delta = definedDelta || actualDelta;
804+
var periodLength = 0;
779805

780-
var delta = definedDelta || Math.abs(B - A);
781-
if(delta >= ONEDAY * 365) { // Years could have days less than ONEAVGYEAR period
782-
v += ONEAVGYEAR / 2;
783-
} else if(delta >= ONEAVGQUARTER) {
784-
v += ONEAVGQUARTER / 2;
785-
} else if(delta >= ONEMINMONTH) { // Months could have days less than ONEAVGMONTH period
786-
var actualDelta = Math.abs(B - A);
806+
if(delta >= ONEMINYEAR) {
807+
if(actualDelta >= ONEMINYEAR && actualDelta <= ONEMAXYEAR) {
808+
periodLength = actualDelta;
809+
} else {
810+
periodLength = ONEAVGYEAR;
811+
}
812+
} else if(definedDelta === ONEAVGQUARTER && delta >= ONEMINQUARTER) {
813+
if(actualDelta >= ONEMINQUARTER && actualDelta <= ONEMAXQUARTER) {
814+
periodLength = actualDelta;
815+
} else {
816+
periodLength = ONEAVGQUARTER;
817+
}
818+
} else if(delta >= ONEMINMONTH) {
787819
if(actualDelta >= ONEMINMONTH && actualDelta <= ONEMAXMONTH) {
788-
v += actualDelta / 2;
820+
periodLength = actualDelta;
789821
} else {
790-
v += ONEAVGMONTH / 2;
822+
periodLength = ONEAVGMONTH;
791823
}
792-
} else if(delta >= ONEWEEK) {
793-
v += ONEWEEK / 2;
824+
} else if(definedDelta === ONEWEEK && delta >= ONEWEEK) {
825+
periodLength = ONEWEEK;
794826
} else if(delta >= ONEDAY) {
795-
v += ONEDAY / 2;
827+
periodLength = ONEDAY;
828+
} else if(definedDelta === HALFDAY && delta >= HALFDAY) {
829+
periodLength = HALFDAY;
830+
} else if(definedDelta === ONEHOUR && delta >= ONEHOUR) {
831+
periodLength = ONEHOUR;
832+
}
833+
834+
if(periodLength && ax.rangebreaks) {
835+
var nFirstHalf = 0;
836+
var nSecondHalf = 0;
837+
var nAll = 2 * 3 * 7; // number of samples
838+
for(var c = 0; c < nAll; c++) {
839+
var r = c / nAll;
840+
if(ax.maskBreaks(A * (1 - r) + B * r) !== BADNUM) {
841+
if(r < 0.5) {
842+
nFirstHalf++;
843+
} else {
844+
nSecondHalf++;
845+
}
846+
}
847+
}
848+
849+
if(nSecondHalf) {
850+
periodLength *= (nFirstHalf + nSecondHalf) / nAll;
851+
}
852+
}
853+
854+
if(periodLength <= actualDelta) { // i.e. to ensure new label positions remain between ticks
855+
v += periodLength / 2;
796856
}
797857

798858
ticksOut[i].periodX = v;
@@ -802,15 +862,15 @@ axes.calcTicks = function calcTicks(ax, opts) {
802862
removedPreTick0Label = true;
803863
}
804864
}
805-
}
806865

807-
if(removedPreTick0Label) {
808-
for(i = 0; i < ticksOut.length; i++) {
809-
if(ticksOut[i].periodX <= maxRange && ticksOut[i].periodX >= minRange) {
810-
// redo first visible tick
811-
ax._prevDateHead = '';
812-
ticksOut[i].text = axes.tickText(ax, tickVals[i].value).text;
813-
break;
866+
if(removedPreTick0Label) {
867+
for(i = 0; i < ticksOut.length; i++) {
868+
if(ticksOut[i].periodX <= maxRange && ticksOut[i].periodX >= minRange) {
869+
// redo first visible tick
870+
ax._prevDateHead = '';
871+
ticksOut[i].text = axes.tickText(ax, ticksOut[i].x).text;
872+
break;
873+
}
814874
}
815875
}
816876
}
@@ -924,7 +984,8 @@ axes.autoTicks = function(ax, roughDTick) {
924984
// 2 or 3 days... but that's a weird enough case that we'll ignore it.
925985
ax.tick0 = Lib.dateTick0(ax.calendar, true);
926986

927-
if(/%[uVW]/.test(ax.tickformat)) {
987+
var tickformat = axes.getTickFormat(ax);
988+
if(/%[uVW]/.test(tickformat)) {
928989
// replace Sunday with Monday for ISO and Monday-based formats
929990
var len = ax.tick0.length;
930991
var lastD = +ax.tick0[len - 1];
134 Bytes
Loading
-5 Bytes
Loading

0 commit comments

Comments
 (0)