Skip to content

Commit

Permalink
Fix row theme and column theme cutting off when entering into blank r…
Browse files Browse the repository at this point in the history
…egion of Grid (#880)

* Fix row theme and column theme cutting off when entering into blank region of Grid

* Fix review issues
  • Loading branch information
jassmith committed Jan 24, 2024
1 parent 904cb33 commit a67f54e
Show file tree
Hide file tree
Showing 4 changed files with 176 additions and 28 deletions.
7 changes: 6 additions & 1 deletion packages/core/src/common/styles.ts
@@ -1,4 +1,5 @@
import React from "react";
import { blend } from "../internal/data-grid/color-parser.js";

// theme variable precidence

Expand Down Expand Up @@ -159,7 +160,11 @@ export function mergeAndRealizeTheme(theme: Theme, ...overlays: Partial<Theme |
for (const key in overlay) {
// eslint-disable-next-line no-prototype-builtins
if (overlay.hasOwnProperty(key)) {
merged[key] = (overlay as any)[key];
if (key === "bgCell") {
merged[key] = blend(overlay[key] as string, merged[key]);
} else {
merged[key] = (overlay as any)[key];
}
}
}
}
Expand Down
30 changes: 21 additions & 9 deletions packages/core/src/docs/examples/theme-per-row.stories.tsx
Expand Up @@ -35,27 +35,39 @@ export default {
export const ThemePerRow: React.VFC = () => {
const { cols, getCellContent, onColumnResize, setCellValue } = useMockDataGenerator(5);

const realCols = React.useMemo(() => {
const c = [...cols];
c[3] = {
...c[3],
themeOverride: {
bgCell: "#d6fafd",
},
};
return c;
}, [cols]);

return (
<DataEditor
{...defaultProps}
getCellContent={getCellContent}
columns={cols}
trailingRowOptions={{
sticky: true,
tint: true,
}}
onRowAppended={() => undefined}
columns={realCols}
height="100%"
// trailingRowOptions={{
// sticky: true,
// tint: true,
// }}
// onRowAppended={() => undefined}
getRowThemeOverride={i =>
i % 2 === 0
? undefined
: {
bgCell: "#f0f8ff",
borderColor: "#3f90e0",
bgCell: "#e0f0ff88",
// borderColor: "#3f90e0",
}
}
onCellEdited={setCellValue}
onColumnResize={onColumnResize}
rows={1_000_000}
rows={10}
/>
);
};
147 changes: 130 additions & 17 deletions packages/core/src/internal/data-grid/render/data-grid-render.lines.ts
Expand Up @@ -146,6 +146,135 @@ export function overdrawStickyBoundaries(
}
}

const getMinMaxXY = (drawRegions: Rectangle[] | undefined, width: number, height: number) => {
let minX = 0;
let maxX = width;
let minY = 0;
let maxY = height;

if (drawRegions !== undefined && drawRegions.length > 0) {
minX = Number.MAX_SAFE_INTEGER;
minY = Number.MAX_SAFE_INTEGER;
maxX = Number.MIN_SAFE_INTEGER;
maxY = Number.MIN_SAFE_INTEGER;
for (const r of drawRegions) {
minX = Math.min(minX, r.x - 1);
maxX = Math.max(maxX, r.x + r.width + 1);
minY = Math.min(minY, r.y - 1);
maxY = Math.max(maxY, r.y + r.height + 1);
}
}

return { minX, maxX, minY, maxY };
};

export function drawExtraRowThemes(
ctx: CanvasRenderingContext2D,
effectiveCols: readonly MappedGridColumn[],
cellYOffset: number,
translateX: number,
translateY: number,
width: number,
height: number,
drawRegions: Rectangle[] | undefined,
totalHeaderHeight: number,
getRowHeight: (row: number) => number,
getRowThemeOverride: GetRowThemeCallback | undefined,
verticalBorder: (col: number) => boolean,
freezeTrailingRows: number,
rows: number,
theme: FullTheme
) {
const bgCell = theme.bgCell;

const { minX, maxX, minY, maxY } = getMinMaxXY(drawRegions, width, height);

const toDraw: { x: number; y: number; w: number; h: number; color: string }[] = [];

const freezeY = height - getFreezeTrailingHeight(rows, freezeTrailingRows, getRowHeight);

// row overflow
let y = totalHeaderHeight;
let row = cellYOffset;
let extraRowsStartY = 0;
while (y + translateY < freezeY) {
const ty = y + translateY;
const rh = getRowHeight(row);
if (ty >= minY && ty <= maxY - 1) {
const rowTheme = getRowThemeOverride?.(row);
const rowThemeBgCell = rowTheme?.bgCell;
const needDraw =
rowThemeBgCell !== undefined && rowThemeBgCell !== bgCell && row >= rows - freezeTrailingRows;
if (needDraw) {
toDraw.push({
x: minX,
y: ty,
w: maxX - minX,
h: rh,
color: rowThemeBgCell,
});
}
}

y += rh;
if (row < rows - freezeTrailingRows) extraRowsStartY = y;
row++;
}

// column overflow
let x = 0;
const h = Math.min(freezeY, maxY) - extraRowsStartY;
if (h > 0) {
for (let index = 0; index < effectiveCols.length; index++) {
const c = effectiveCols[index];
if (c.width === 0) continue;
const tx = c.sticky ? x : x + translateX;
const colThemeBgCell = c.themeOverride?.bgCell;
if (
colThemeBgCell !== undefined &&
colThemeBgCell !== bgCell &&
tx >= minX &&
tx <= maxX &&
verticalBorder(index + 1)
) {
toDraw.push({
x: tx,
y: extraRowsStartY,
w: c.width,
h,
color: colThemeBgCell,
});
}

x += c.width;
}
}

if (toDraw.length === 0) return;

let color: string | undefined;
ctx.beginPath();
// render in reverse order because we computed and added the columns last, but they should actually be lower
// priority than the rows.
for (let i = toDraw.length - 1; i >= 0; i--) {
const r = toDraw[i];
if (color === undefined) {
color = r.color;
} else if (r.color !== color) {
ctx.fillStyle = color;
ctx.fill();
ctx.beginPath();
color = r.color;
}
ctx.rect(r.x, r.y, r.w, r.h);
}
if (color !== undefined) {
ctx.fillStyle = color;
ctx.fill();
}
ctx.beginPath();
}

// lines are effectively drawn on the top left edge of a cell.
export function drawGridLines(
ctx: CanvasRenderingContext2D,
Expand Down Expand Up @@ -179,23 +308,7 @@ export function drawGridLines(
const hColor = theme.horizontalBorderColor ?? theme.borderColor;
const vColor = theme.borderColor;

let minX = 0;
let maxX = width;
let minY = 0;
let maxY = height;

if (drawRegions !== undefined && drawRegions.length > 0) {
minX = Number.MAX_SAFE_INTEGER;
minY = Number.MAX_SAFE_INTEGER;
maxX = Number.MIN_SAFE_INTEGER;
maxY = Number.MIN_SAFE_INTEGER;
for (const r of drawRegions) {
minX = Math.min(minX, r.x - 1);
maxX = Math.max(maxX, r.x + r.width + 1);
minY = Math.min(minY, r.y - 1);
maxY = Math.max(maxY, r.y + r.height + 1);
}
}
const { minX, maxX, minY, maxY } = getMinMaxXY(drawRegions, width, height);

const toDraw: { x1: number; y1: number; x2: number; y2: number; color: string }[] = [];

Expand Down
20 changes: 19 additions & 1 deletion packages/core/src/internal/data-grid/render/data-grid-render.ts
Expand Up @@ -9,7 +9,7 @@ import type { DrawGridArg } from "./draw-grid-arg.js";
import { walkColumns, walkGroups, walkRowsInCol } from "./data-grid-render.walk.js";
import { drawCells } from "./data-grid-render.cells.js";
import { drawGridHeaders } from "./data-grid-render.header.js";
import { drawGridLines, overdrawStickyBoundaries, drawBlanks } from "./data-grid-render.lines.js";
import { drawGridLines, overdrawStickyBoundaries, drawBlanks, drawExtraRowThemes } from "./data-grid-render.lines.js";
import { blitLastFrame, blitResizedCol, computeCanBlit } from "./data-grid-render.blit.js";
import { drawHighlightRings, drawFocusRing, drawColumnResizeOutline } from "./data-grid.render.rings.js";

Expand Down Expand Up @@ -680,6 +680,24 @@ export function drawGrid(arg: DrawGridArg, lastArg: DrawGridArg | undefined) {
theme
);

drawExtraRowThemes(
targetCtx,
effectiveCols,
cellYOffset,
translateX,
translateY,
width,
height,
drawRegions,
totalHeaderHeight,
getRowHeight,
getRowThemeOverride,
verticalBorder,
freezeTrailingRows,
rows,
theme
);

drawGridLines(
targetCtx,
effectiveCols,
Expand Down

0 comments on commit a67f54e

Please sign in to comment.