You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by jl...@apache.org on 2026/09/24 07:55:36 UTC
(superset) branch ultraset-nif-44532-2 created (now 99183d3d1c9)
This is an automated email from the ASF dual-hosted git repository.
sadpandajoe pushed a change to branch ultraset-nif-44532-2
in repository https://gitbox.apache.org/repos/asf/superset.git
at 99183d3d1c9 fix(calendar): position month/week cells by index within their own block
This branch includes the following new commits:
new 99183d3d1c9 fix(calendar): position month/week cells by index within their own block
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
(superset) 01/01: fix(calendar): position month/week cells by index within their own block
Posted by jl...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
sadpandajoe pushed a commit to branch ultraset-nif-44532-2
in repository https://gitbox.apache.org/repos/asf/superset.git
commit 99183d3d1c9627720f40eed0958a19bb867fb2a7
Author: Joe Li <47...@users.noreply.github.com>
AuthorDate: Thu Sep 24 07:55:21 2026 +0000
fix(calendar): position month/week cells by index within their own block
getMonthWeekNumber positioned a week cell relative to the cell date's
own calendar month instead of the month block it is rendered in. Since
a month block also renders the tail (or head) of an adjacent month's
week, this made most months draw two week cells at the same x position
(one hiding the other), and made a month whose 1st falls on a Monday
resolve its own first week to x = -1, outside its block.
Position each cell by its index within the block's own generated cell
list instead. defaultColumnNumber for month domains also under-counted
by one relative to the number of cells computeWeekSubDomainSize
actually generates for the block, which narrowed the block itself and
is fixed alongside the positioning for the same reason.
Fixes #44532
Co-Authored-By: Claude Sonnet 5 <no...@anthropic.com>
---
.../src/vendor/cal-heatmap.ts | 50 +++++++++-------------
.../plugin-chart-calendar/test/cal-heatmap.test.ts | 40 +++++++++++++++++
2 files changed, 61 insertions(+), 29 deletions(-)
diff --git a/superset-frontend/plugins/plugin-chart-calendar/src/vendor/cal-heatmap.ts b/superset-frontend/plugins/plugin-chart-calendar/src/vendor/cal-heatmap.ts
index 8b366be1838..fe9253e5d2f 100644
--- a/superset-frontend/plugins/plugin-chart-calendar/src/vendor/cal-heatmap.ts
+++ b/superset-frontend/plugins/plugin-chart-calendar/src/vendor/cal-heatmap.ts
@@ -584,10 +584,15 @@ var CalHeatMap = function () {
case 'year':
return self._domainType.week.maxItemNumber;
case 'month':
+ // +1: this must match the number of cells computeWeekSubDomainSize
+ // generates for the block (an inclusive week-number range), or the
+ // block is rendered one column narrower than its own content.
return self.options.domainDynamicDimension
? self.getWeekNumber(
new Date(d.getFullYear(), d.getMonth() + 1, 0),
- ) - self.getWeekNumber(d)
+ ) -
+ self.getWeekNumber(d) +
+ 1
: 5;
}
},
@@ -599,16 +604,19 @@ var CalHeatMap = function () {
return self.getSubDomainColumnNumber(d);
},
position: {
- x: function (d) {
+ x: function (d, i) {
switch (self.options.domain) {
case 'year':
return Math.floor(
self.getWeekNumber(d) / self._domainType.week.row(d),
);
case 'month':
- return Math.floor(
- self.getMonthWeekNumber(d) / self._domainType.week.row(d),
- );
+ // Position by index within the block's own cell list rather
+ // than by a week-number difference against the cell's own
+ // month: a month block also renders the tail (or head) of an
+ // adjacent month's week, and that borrowed cell's "own month"
+ // is not the block it is being drawn into.
+ return Math.floor(i / self._domainType.week.row(d));
}
},
y: function (d) {
@@ -765,10 +773,11 @@ var CalHeatMap = function () {
.map(function (d) {
self._domains.set(
d,
- self.getSubDomain(d).map(function (d) {
+ self.getSubDomain(d).map(function (d, i) {
return {
t: self._domainType[self.options.subDomain].extractUnit(d),
v: null,
+ i: i,
};
}),
);
@@ -1062,7 +1071,7 @@ var CalHeatMap = function () {
.attr('width', options.cellSize)
.attr('height', options.cellSize)
.attr('x', function (d) {
- return self.positionSubDomainX(d.t);
+ return self.positionSubDomainX(d);
})
.attr('y', function (d) {
return self.positionSubDomainY(d.t);
@@ -1230,7 +1239,7 @@ var CalHeatMap = function () {
return 'subdomain-text' + self.getHighlightClassName(d.t);
})
.attr('x', function (d) {
- return self.positionSubDomainX(d.t) + options.cellSize / 2;
+ return self.positionSubDomainX(d) + options.cellSize / 2;
})
.attr('y', function (d) {
return self.positionSubDomainY(d.t) + options.cellSize / 2;
@@ -2105,10 +2114,11 @@ CalHeatMap.prototype = {
var total = newDomains.length;
var domains = this.getDomainKeys();
- function buildSubDomain(d) {
+ function buildSubDomain(d, i) {
return {
t: parent._domainType[parent.options.subDomain].extractUnit(d),
v: null,
+ i: i,
};
}
@@ -2214,7 +2224,8 @@ CalHeatMap.prototype = {
'use strict';
var index = this._domainType[this.options.subDomain].position.x(
- new Date(d),
+ new Date(d.t),
+ d.i,
);
return index * this.options.cellSize + index * this.options.cellPadding;
},
@@ -2449,25 +2460,6 @@ CalHeatMap.prototype = {
return f(d);
},
- /**
- * Return the week number, relative to its month
- *
- * @param int|Date d Date or timestamp in milliseconds
- * @return int Week number, relative to the month [0-5]
- */
- getMonthWeekNumber: function (d) {
- 'use strict';
-
- if (typeof d === 'number') {
- d = new Date(d);
- }
-
- var monthFirstWeekNumber = this.getWeekNumber(
- new Date(d.getFullYear(), d.getMonth()),
- );
- return this.getWeekNumber(d) - monthFirstWeekNumber - 1;
- },
-
/**
* Return the number of weeks in the dates' year
*
diff --git a/superset-frontend/plugins/plugin-chart-calendar/test/cal-heatmap.test.ts b/superset-frontend/plugins/plugin-chart-calendar/test/cal-heatmap.test.ts
index 2247592a50e..37b95948e48 100644
--- a/superset-frontend/plugins/plugin-chart-calendar/test/cal-heatmap.test.ts
+++ b/superset-frontend/plugins/plugin-chart-calendar/test/cal-heatmap.test.ts
@@ -27,10 +27,15 @@ interface CalHeatMapInstance {
dateFormatter: DateFormatter | null;
timeFormatter: (t: number) => string;
valueFormatter: (v: number) => string;
+ domain: string;
+ subDomain: string;
+ weekStartOnMonday: boolean;
};
formatDate(date: Date, format: string | FunctionalDateFormat): string;
tip: { html(): (d: { t: number; v: number }) => string };
legendTip: { html(): (d: number) => string };
+ positionSubDomainX(d: { t: number; i: number }): number;
+ getSubDomain(date: Date): Date[];
}
const CalHeatMap = CalHeatMapImport as unknown as new () => CalHeatMapInstance;
@@ -89,3 +94,38 @@ test('legend tooltip HTML escapes creator-controlled formatter output', () => {
expect(html).not.toContain('<img');
expect(html).toContain('<img');
});
+
+function positionsForMonthBlock(
+ calendar: CalHeatMapInstance,
+ monthStart: Date,
+): number[] {
+ // Mirrors how _init()/loadNewDomains() build a block's subdomain
+ // list: each cell's render position is derived from its index within
+ // that specific block's own cell list, not from the cell's own date.
+ return calendar
+ .getSubDomain(monthStart)
+ .map((date, i) => calendar.positionSubDomainX({ t: date.getTime(), i }));
+}
+
+test('Month/Week domain gives every cell in a block a distinct, non-negative position', () => {
+ // Regression test: a month block also renders the tail (or head) of
+ // an adjacent month's week. Positioning must be relative to the
+ // block being drawn, not to the cell date's own calendar month, or a
+ // borrowed cell collides with one of the block's own cells and hides
+ // its value.
+ const calendar = new CalHeatMap();
+ calendar.options.domain = 'month';
+ calendar.options.subDomain = 'week';
+ calendar.options.weekStartOnMonday = true;
+
+ // May 2026 borrows 2026-04-27 as its first cell; May's own last week
+ // (2026-05-25) must not resolve to the same on-screen column.
+ const mayPositions = positionsForMonthBlock(calendar, new Date(2026, 4, 1));
+ expect(new Set(mayPositions).size).toBe(mayPositions.length);
+
+ // June 2026's 1st falls on a Monday (the week-start day), so the
+ // block has no borrowed cell. Its own first week must stay within
+ // the block instead of resolving to a negative position.
+ const junePositions = positionsForMonthBlock(calendar, new Date(2026, 5, 1));
+ expect(Math.min(...junePositions)).toBeGreaterThanOrEqual(0);
+});