UNPKG

@adaptabletools/adaptable

Version:

Powerful AG Grid extension which provides advanced, cutting-edge functionality to meet all DataGrid requirements

210 lines (209 loc) 8.87 kB
import tinycolor from 'tinycolor2'; import { convertAdaptableStyleToCSS } from '../StyleHelper'; import { getAutoContrastTextColor, getVariableColor } from '../StyleHelper'; import { clamp } from '../../Extensions/NumberExtensions'; export const DEFAULT_GRADIENT_MIN_ALPHA = 0.15; export const DEFAULT_GRADIENT_MAX_ALPHA = 1; export const hasGradientRangesConfigured = (gs) => !!(gs?.ZeroCentred || gs?.CellRanges?.length || gs?.ColumnComparison); const evenlySpacedValues = (min, max, count) => { if (count <= 1) { return [min]; } const step = (max - min) / (count - 1); return Array.from({ length: count }, (_, i) => min + step * i); }; export const STYLED_COLUMN_PREVIEW_SAMPLE_COUNT = 6; export const ZERO_CENTRED_PREVIEW_SCALE_MIN = -20; export const ZERO_CENTRED_PREVIEW_SCALE_MAX = 20; export const ZERO_CENTRED_GRADIENT_PREVIEW_VALUES = evenlySpacedValues(ZERO_CENTRED_PREVIEW_SCALE_MIN, ZERO_CENTRED_PREVIEW_SCALE_MAX, STYLED_COLUMN_PREVIEW_SAMPLE_COUNT); export const getZeroCentredGradientPreviewValues = () => evenlySpacedValues(ZERO_CENTRED_PREVIEW_SCALE_MIN, ZERO_CENTRED_PREVIEW_SCALE_MAX, STYLED_COLUMN_PREVIEW_SAMPLE_COUNT); export function isDivergingZeroCellRanges(ranges) { if (!ranges || ranges.length !== 2) { return false; } const [a, b] = ranges; return a.Max === 0 && b.Min === 0; } export function isZeroCentredGradientStyle(gs) { return !!(gs.ZeroCentred || isDivergingZeroCellRanges(gs.CellRanges)); } export const getGradientPreviewSampleValues = (styledColumn, api) => { const gs = styledColumn.GradientStyle; if (!gs || !hasGradientRangesConfigured(gs)) { return []; } if (isZeroCentredGradientStyle(gs)) { return getZeroCentredGradientPreviewValues(); } if (gs.ColumnComparison) { const min = Number(gs.ColumnComparison.MinValue); const max = Number(gs.ColumnComparison.MaxValue); if (!Number.isNaN(min) && !Number.isNaN(max)) { return evenlySpacedValues(min, max, STYLED_COLUMN_PREVIEW_SAMPLE_COUNT); } return evenlySpacedValues(0, 100, STYLED_COLUMN_PREVIEW_SAMPLE_COUNT); } const column = styledColumn.ColumnId ? api.columnApi.getColumnWithColumnId(styledColumn.ColumnId) : undefined; if (!column) { return evenlySpacedValues(0, 100, STYLED_COLUMN_PREVIEW_SAMPLE_COUNT); } const colMin = api.styledColumnApi.internalApi.getMinValueForNumericColumn(column); const colMax = api.styledColumnApi.internalApi.getMaxValueForNumericColumn(column); if (colMin === colMax) { return [colMin]; } return evenlySpacedValues(colMin, colMax, STYLED_COLUMN_PREVIEW_SAMPLE_COUNT); }; const getZeroCentredPreviewColors = (gradientStyle) => { if (gradientStyle.ZeroCentred) { return { negative: gradientStyle.ZeroCentred.NegativeColor, positive: gradientStyle.ZeroCentred.PositiveColor, }; } const ranges = gradientStyle.CellRanges; if (isDivergingZeroCellRanges(ranges)) { return { negative: ranges[0].Color, positive: ranges[1].Color, }; } return null; }; const getZeroCentredGradientPreviewCellStyle = (cellValue, gradientStyle) => { const colors = getZeroCentredPreviewColors(gradientStyle); if (!colors) { return {}; } const previewMin = ZERO_CENTRED_PREVIEW_SCALE_MIN; const previewMax = ZERO_CENTRED_PREVIEW_SCALE_MAX; const syntheticRanges = [ { Min: previewMin, Max: 0, Color: colors.negative }, { Min: 0, Max: previewMax, Color: colors.positive }, ]; let matchingRange = null; for (const range of syntheticRanges) { const min = range.Min; const max = range.Max; if (cellValue >= min && cellValue <= max) { matchingRange = range; break; } } if (!matchingRange) { return {}; } const min = matchingRange.Min; const max = matchingRange.Max; const reverseGradient = matchingRange.Min === previewMin && matchingRange.Max === 0; const minAlphaBound = gradientStyle.MinAlpha ?? DEFAULT_GRADIENT_MIN_ALPHA; const maxAlphaBound = gradientStyle.MaxAlpha ?? DEFAULT_GRADIENT_MAX_ALPHA; const lo = Math.min(clamp(minAlphaBound, 0, 1), clamp(maxAlphaBound, 0, 1)); const hi = Math.max(clamp(minAlphaBound, 0, 1), clamp(maxAlphaBound, 0, 1)); const span = Math.abs(max - min); let t = span === 0 ? 0.5 : (Number(cellValue) - min) / span; t = clamp(t, 0, 1); if (reverseGradient) { t = 1 - t; } const alpha = Number((lo + t * (hi - lo)).toPrecision(4)); let style = {}; const preparedColor = getVariableColor(matchingRange.Color); const bg = tinycolor(preparedColor).setAlpha(alpha); style.backgroundColor = bg.toRgbString(); if (gradientStyle.AutoContrastText) { style.color = getAutoContrastTextColor(preparedColor, alpha); } const autoContrastColor = gradientStyle.AutoContrastText && style.color ? style.color : undefined; if (gradientStyle.Font) { style = { ...style, ...convertAdaptableStyleToCSS(gradientStyle.Font) }; } if (autoContrastColor) { style.color = autoContrastColor; } if (gradientStyle.Font?.Alignment && gradientStyle.Font.Alignment !== 'Default') { style.textAlign = gradientStyle.Font.Alignment.toLowerCase(); } return style; }; export const getGradientPreviewCellStyle = (cellValue, styledColumn, api, rowNode) => { const gradientStyle = styledColumn.GradientStyle; if (!gradientStyle || !hasGradientRangesConfigured(gradientStyle)) { return {}; } if (isZeroCentredGradientStyle(gradientStyle)) { return getZeroCentredGradientPreviewCellStyle(cellValue, gradientStyle); } const column = styledColumn.ColumnId ? api.columnApi.getColumnWithColumnId(styledColumn.ColumnId) : undefined; if (!column) { return {}; } const node = rowNode ?? api.gridApi?.getRowNodeForIndex(0) ?? null; const internalApi = api.styledColumnApi.internalApi; let style = {}; const min = internalApi.getNumericStyleMinValue(styledColumn, column, node, cellValue); const max = internalApi.getNumericStyleMaxValue(styledColumn, column, node, cellValue); let cellBackColor; let reverseGradient = false; if (gradientStyle.ColumnComparison) { cellBackColor = gradientStyle.ColumnComparison.Color; } else { const matchingRange = internalApi.findRangeForColumn(expandGradientCellRanges(gradientStyle), column, gradientStyleRangeLookupValueType(gradientStyle), cellValue); if (matchingRange) { cellBackColor = matchingRange.Color; reverseGradient = (!!gradientStyle.ZeroCentred && isNegativeZeroCentredBand(matchingRange)) || !!matchingRange.ReverseGradient; } } const minAlphaBound = gradientStyle.MinAlpha ?? DEFAULT_GRADIENT_MIN_ALPHA; const maxAlphaBound = gradientStyle.MaxAlpha ?? DEFAULT_GRADIENT_MAX_ALPHA; const lo = Math.min(clamp(minAlphaBound, 0, 1), clamp(maxAlphaBound, 0, 1)); const hi = Math.max(clamp(minAlphaBound, 0, 1), clamp(maxAlphaBound, 0, 1)); const span = Math.abs(max - min); let t = span === 0 ? 0.5 : (Number(cellValue) - min) / span; t = clamp(t, 0, 1); if (reverseGradient) { t = 1 - t; } const alpha = Number((lo + t * (hi - lo)).toPrecision(4)); if (cellBackColor) { const preparedColor = getVariableColor(cellBackColor); const bg = tinycolor(preparedColor).setAlpha(alpha); style.backgroundColor = bg.toRgbString(); if (gradientStyle.AutoContrastText) { style.color = getAutoContrastTextColor(preparedColor, alpha); } } const autoContrastColor = gradientStyle.AutoContrastText && style.color ? style.color : undefined; if (gradientStyle.Font) { style = { ...style, ...convertAdaptableStyleToCSS(gradientStyle.Font) }; } if (autoContrastColor) { style.color = autoContrastColor; } if (gradientStyle.Font?.Alignment && gradientStyle.Font.Alignment !== 'Default') { style.textAlign = gradientStyle.Font.Alignment.toLowerCase(); } return style; }; export function expandGradientCellRanges(gs) { if (gs.ZeroCentred) { return [ { Min: 'Col-Min', Max: 0, Color: gs.ZeroCentred.NegativeColor }, { Min: 0, Max: 'Col-Max', Color: gs.ZeroCentred.PositiveColor }, ]; } return gs.CellRanges; } export function gradientStyleRangeLookupValueType(gs) { return gs.ZeroCentred ? 'Number' : gs.RangeValueType ?? 'Number'; } export function isNegativeZeroCentredBand(range) { return range.Min === 'Col-Min' && range.Max === 0; }