From 46fba1348bdc73a3cee1a1b25c2450bf9895dfbd Mon Sep 17 00:00:00 2001 From: xiaoluoHe Date: Wed, 15 Jan 2025 14:30:17 +0800 Subject: [PATCH 01/10] feat: support transparent foreground and background color for label `smartInvert` --- packages/vrender-components/src/label/base.ts | 10 +++ .../src/util/label-smartInvert.ts | 68 ++++++++++++------- 2 files changed, 55 insertions(+), 23 deletions(-) diff --git a/packages/vrender-components/src/label/base.ts b/packages/vrender-components/src/label/base.ts index 8e1c79c94..8183ac9fb 100644 --- a/packages/vrender-components/src/label/base.ts +++ b/packages/vrender-components/src/label/base.ts @@ -1022,6 +1022,12 @@ export class LabelBase extends AbstractComponent { * */ let backgroundColor = baseMark.attribute.fill as IColor; let foregroundColor = label.attribute.fill as IColor; + const { fillOpacity: backgroundFillOpacity = 1, opacity: backgroundOpacity = 1 } = baseMark.attribute; + const { + fillOpacity: foregroundFillOpacity = 1, + opacity: foregroundOpacity = 1, + strokeOpacity: foregroundStrokeOpacity = 1 + } = label.attribute; if (isObject(backgroundColor) && backgroundColor.gradient) { const firstStopColor = (backgroundColor as ILinearGradient).stops?.[0]?.color; @@ -1035,6 +1041,8 @@ export class LabelBase extends AbstractComponent { const invertColor = labelSmartInvert( foregroundColor, backgroundColor, + foregroundFillOpacity * foregroundOpacity, + backgroundFillOpacity * backgroundOpacity, textType, contrastRatiosThreshold, alternativeColors, @@ -1069,6 +1077,8 @@ export class LabelBase extends AbstractComponent { fill: labelSmartInvert( label.attribute.fill as IColor, label.attribute.stroke as IColor, + foregroundFillOpacity * foregroundOpacity, + foregroundStrokeOpacity * foregroundOpacity, textType, contrastRatiosThreshold, alternativeColors, diff --git a/packages/vrender-components/src/util/label-smartInvert.ts b/packages/vrender-components/src/util/label-smartInvert.ts index bc046a894..e311aa318 100644 --- a/packages/vrender-components/src/util/label-smartInvert.ts +++ b/packages/vrender-components/src/util/label-smartInvert.ts @@ -1,38 +1,66 @@ import type { IColor } from '@visactor/vrender-core'; -import { Color, hexToRgb } from '@visactor/vutils'; +import { Color, RGB, hexToRgb, isValidNumber } from '@visactor/vutils'; const defaultAlternativeColors: string[] = ['#ffffff', '#000000']; /** * 标签智能反色 * @param foregroundColorOrigin - * @param backgroundColorOrogin + * @param backgroundColorOrigin * @returns */ export function labelSmartInvert( foregroundColorOrigin: IColor | undefined, - backgroundColorOrogin: IColor | undefined, + backgroundColorOrigin: IColor | undefined, + foregroundOpacity: number, + backgroundOpacity: number, textType?: string | undefined, contrastRatiosThreshold?: number, alternativeColors?: string | string[], mode?: string ): IColor | undefined { - if (typeof foregroundColorOrigin !== 'string' || typeof backgroundColorOrogin !== 'string') { + if (typeof foregroundColorOrigin !== 'string' || typeof backgroundColorOrigin !== 'string') { return foregroundColorOrigin; } - const foregroundColor = new Color(foregroundColorOrigin as string).toHex(); - const backgroundColor = new Color(backgroundColorOrogin as string).toHex(); - if (!contrastAccessibilityChecker(foregroundColor, backgroundColor, textType, contrastRatiosThreshold, mode)) { + let foregroundColor = new Color(foregroundColorOrigin as string).setOpacity(foregroundOpacity); + let backgroundColor = new Color(backgroundColorOrigin as string).setOpacity(backgroundOpacity); + if (foregroundOpacity < 1) { + foregroundColor = blendColor(foregroundColor, backgroundColor); + } + if (backgroundOpacity < 1) { + backgroundColor = blendColor(backgroundColor); + } + const foregroundHex = foregroundColor.toHex(); + const backgroundHex = backgroundColor.toHex(); + if (!contrastAccessibilityChecker(foregroundHex, backgroundHex, textType, contrastRatiosThreshold, mode)) { return improveContrastReverse( - foregroundColor, - backgroundColor, + foregroundHex, + backgroundHex, textType, contrastRatiosThreshold, alternativeColors, mode ); } - return foregroundColor; + return foregroundHex; +} + +/** + * Target.R = ((1 - Source.A) * BGColor.R) + (Source.A * Source.R) + * Target.G = ((1 - Source.A) * BGColor.G) + (Source.A * Source.G) + * Target.B = ((1 - Source.A) * BGColor.B) + (Source.A * Source.B) + * @param source + * @param background + */ +function blendColor(source: Color, background?: Color) { + if (!background) { + background = new Color(new RGB(255, 255, 255).toString()); + } + const alpha = source.color.opacity; + const r = ~~((1 - alpha) * background.color.r + alpha * source.color.r); + const g = ~~((1 - alpha) * background.color.g + alpha * source.color.g); + const b = ~~((1 - alpha) * background.color.b + alpha * source.color.b); + return new Color(new RGB(r, g, b).toString()); } /** @@ -103,21 +131,15 @@ export function contrastAccessibilityChecker( return false; } //Contrast ratios can range from 1 to 21 - if (contrastRatiosThreshold) { - if (contrastRatios(foregroundColor, backgroundColor) > contrastRatiosThreshold) { - return true; - } - return false; - } else if (textType === 'largeText') { - if (contrastRatios(foregroundColor, backgroundColor) > 3) { - return true; + let threshold = contrastRatiosThreshold; + if (!isValidNumber(threshold)) { + if (textType === 'largeText') { + threshold = 3; + } else { + threshold = 4.5; } - return false; - } - if (contrastRatios(foregroundColor, backgroundColor) > 4.5) { - return true; } - return false; + return contrastRatios(foregroundColor, backgroundColor) > threshold; } /** From 95e4a1763e630292d749fc3941c47a591fd99f0e Mon Sep 17 00:00:00 2001 From: xiaoluoHe Date: Wed, 15 Jan 2025 14:31:41 +0800 Subject: [PATCH 02/10] docs: add changelog --- .../feat-smartInvert-optimize_2025-01-15-06-31.json | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 common/changes/@visactor/vrender-components/feat-smartInvert-optimize_2025-01-15-06-31.json diff --git a/common/changes/@visactor/vrender-components/feat-smartInvert-optimize_2025-01-15-06-31.json b/common/changes/@visactor/vrender-components/feat-smartInvert-optimize_2025-01-15-06-31.json new file mode 100644 index 000000000..69fcd536b --- /dev/null +++ b/common/changes/@visactor/vrender-components/feat-smartInvert-optimize_2025-01-15-06-31.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@visactor/vrender-components", + "comment": "feat: support transparent foreground and background color for label `smartInvert`", + "type": "none" + } + ], + "packageName": "@visactor/vrender-components" +} \ No newline at end of file From 163c3de1fb6e3c9bf64235c2eb7507cc5b80a033 Mon Sep 17 00:00:00 2001 From: xiaoluoHe Date: Wed, 15 Jan 2025 15:21:28 +0800 Subject: [PATCH 03/10] feat: add `underlyingColor` for blending of transparent background --- packages/vrender-components/src/label/base.ts | 32 +++++++++++++------ packages/vrender-components/src/label/type.ts | 7 ++++ .../src/util/label-smartInvert.ts | 15 ++++++--- 3 files changed, 39 insertions(+), 15 deletions(-) diff --git a/packages/vrender-components/src/label/base.ts b/packages/vrender-components/src/label/base.ts index 8183ac9fb..1272537f7 100644 --- a/packages/vrender-components/src/label/base.ts +++ b/packages/vrender-components/src/label/base.ts @@ -1000,6 +1000,13 @@ export class LabelBase extends AbstractComponent { const brightColor = option.brightColor ?? '#ffffff'; const darkColor = option.darkColor ?? '#000000'; const outsideEnable = option.outsideEnable ?? false; + const colorFromGradient = (color: ILinearGradient) => { + return color.stops?.[0]?.color; + }; + const underlyingColor = + option.underlyingColor ?? isObject(this.stage.background) + ? colorFromGradient(this.stage.background as ILinearGradient) + : this.stage.background; if (fillStrategy === 'null' && strokeStrategy === 'null') { return; @@ -1030,8 +1037,7 @@ export class LabelBase extends AbstractComponent { } = label.attribute; if (isObject(backgroundColor) && backgroundColor.gradient) { - const firstStopColor = (backgroundColor as ILinearGradient).stops?.[0]?.color; - + const firstStopColor = colorFromGradient(backgroundColor as ILinearGradient); if (firstStopColor) { backgroundColor = firstStopColor; foregroundColor = firstStopColor; // 渐变色的时候,标签的颜色可能会和背景色不一致,所以需要设置为相同的颜色 @@ -1043,10 +1049,13 @@ export class LabelBase extends AbstractComponent { backgroundColor, foregroundFillOpacity * foregroundOpacity, backgroundFillOpacity * backgroundOpacity, - textType, - contrastRatiosThreshold, - alternativeColors, - mode + { + textType, + contrastRatiosThreshold, + alternativeColors, + mode, + underlyingColor + } ); const similarColor = contrastAccessibilityChecker(invertColor, brightColor) ? brightColor : darkColor; const isInside = this._canPlaceInside(label.AABBBounds, baseMark.AABBBounds); @@ -1079,10 +1088,13 @@ export class LabelBase extends AbstractComponent { label.attribute.stroke as IColor, foregroundFillOpacity * foregroundOpacity, foregroundStrokeOpacity * foregroundOpacity, - textType, - contrastRatiosThreshold, - alternativeColors, - mode + { + textType, + contrastRatiosThreshold, + alternativeColors, + mode, + underlyingColor + } ) }); continue; diff --git a/packages/vrender-components/src/label/type.ts b/packages/vrender-components/src/label/type.ts index fcef620ce..8131389df 100644 --- a/packages/vrender-components/src/label/type.ts +++ b/packages/vrender-components/src/label/type.ts @@ -280,6 +280,13 @@ export interface SmartInvertAttrs { * * inside: 和标签完全在mark内部一样处理 */ interactInvertType?: 'none' | 'stroked' | 'inside'; + /** + * 底层颜色 + * 通常,反色的背景色取自图元填充色。当背景色为透明色时,需要与其底层颜色进行颜色混合计算。 + * @default stage.background + * @since 0.22.0 + */ + underlyingColor?: string; } export type ShiftYStrategy = { diff --git a/packages/vrender-components/src/util/label-smartInvert.ts b/packages/vrender-components/src/util/label-smartInvert.ts index e311aa318..3db5e1d0d 100644 --- a/packages/vrender-components/src/util/label-smartInvert.ts +++ b/packages/vrender-components/src/util/label-smartInvert.ts @@ -14,21 +14,26 @@ export function labelSmartInvert( backgroundColorOrigin: IColor | undefined, foregroundOpacity: number, backgroundOpacity: number, - textType?: string | undefined, - contrastRatiosThreshold?: number, - alternativeColors?: string | string[], - mode?: string + params: { + textType?: string | undefined; + contrastRatiosThreshold?: number; + alternativeColors?: string | string[]; + mode?: string; + // 背景色为透明时,用作颜色混合 + underlyingColor?: string; + } = {} ): IColor | undefined { if (typeof foregroundColorOrigin !== 'string' || typeof backgroundColorOrigin !== 'string') { return foregroundColorOrigin; } + const { textType, contrastRatiosThreshold, alternativeColors, mode, underlyingColor = 'white' } = params; let foregroundColor = new Color(foregroundColorOrigin as string).setOpacity(foregroundOpacity); let backgroundColor = new Color(backgroundColorOrigin as string).setOpacity(backgroundOpacity); if (foregroundOpacity < 1) { foregroundColor = blendColor(foregroundColor, backgroundColor); } if (backgroundOpacity < 1) { - backgroundColor = blendColor(backgroundColor); + backgroundColor = blendColor(backgroundColor, new Color(underlyingColor)); } const foregroundHex = foregroundColor.toHex(); const backgroundHex = backgroundColor.toHex(); From d1d8cad8bc739eb5ad82a1e04ec1cee120a584aa Mon Sep 17 00:00:00 2001 From: xiaoluoHe Date: Wed, 15 Jan 2025 15:22:19 +0800 Subject: [PATCH 04/10] docs: add changelog --- .../feat-smartInvert-optimize_2025-01-15-07-22.json | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 common/changes/@visactor/vrender-components/feat-smartInvert-optimize_2025-01-15-07-22.json diff --git a/common/changes/@visactor/vrender-components/feat-smartInvert-optimize_2025-01-15-07-22.json b/common/changes/@visactor/vrender-components/feat-smartInvert-optimize_2025-01-15-07-22.json new file mode 100644 index 000000000..4b579951e --- /dev/null +++ b/common/changes/@visactor/vrender-components/feat-smartInvert-optimize_2025-01-15-07-22.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@visactor/vrender-components", + "comment": "feat: add `underlyingColor` for blending of transparent background", + "type": "none" + } + ], + "packageName": "@visactor/vrender-components" +} \ No newline at end of file From 6b03b57f6604f36551793dc93a81356e804162a9 Mon Sep 17 00:00:00 2001 From: xiaoluoHe Date: Wed, 15 Jan 2025 15:44:09 +0800 Subject: [PATCH 05/10] feat: optimize the default logic when label intersects with graphic --- packages/vrender-components/src/label/base.ts | 2 +- packages/vrender-components/src/label/type.ts | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/vrender-components/src/label/base.ts b/packages/vrender-components/src/label/base.ts index 1272537f7..474baedbb 100644 --- a/packages/vrender-components/src/label/base.ts +++ b/packages/vrender-components/src/label/base.ts @@ -994,7 +994,7 @@ export class LabelBase extends AbstractComponent { protected _smartInvert(labels: (IText | IRichText)[]) { const option = (isObject(this.attribute.smartInvert) ? this.attribute.smartInvert : {}) as SmartInvertAttrs; - const { textType, contrastRatiosThreshold, alternativeColors, mode, interactInvertType } = option; + const { textType, contrastRatiosThreshold, alternativeColors, mode, interactInvertType = 'inside' } = option; const fillStrategy = option.fillStrategy ?? 'invertBase'; const strokeStrategy = option.strokeStrategy ?? 'base'; const brightColor = option.brightColor ?? '#ffffff'; diff --git a/packages/vrender-components/src/label/type.ts b/packages/vrender-components/src/label/type.ts index 8131389df..b48256f6f 100644 --- a/packages/vrender-components/src/label/type.ts +++ b/packages/vrender-components/src/label/type.ts @@ -278,6 +278,9 @@ export interface SmartInvertAttrs { * * none:不做任何处理 * * stroked:标签存在描边的时候,根据描边进行处理 * * inside: 和标签完全在mark内部一样处理 + * 在 0.22.0 版本之前,该配置项的默认值为 undefined。 + * 在 0.22.0 版本后,该配置项的默认值为 'inside'。 + * @default 'inside' */ interactInvertType?: 'none' | 'stroked' | 'inside'; /** From 5152de452632348cbb7d18f60336568782ac2fbd Mon Sep 17 00:00:00 2001 From: xiaoluoHe Date: Wed, 15 Jan 2025 15:49:49 +0800 Subject: [PATCH 06/10] refactor: deprecate `label.smartInvert.outsideEnable` --- packages/vrender-components/src/label/base.ts | 4 ++-- packages/vrender-components/src/label/type.ts | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/vrender-components/src/label/base.ts b/packages/vrender-components/src/label/base.ts index 474baedbb..d35203bf1 100644 --- a/packages/vrender-components/src/label/base.ts +++ b/packages/vrender-components/src/label/base.ts @@ -999,7 +999,7 @@ export class LabelBase extends AbstractComponent { const strokeStrategy = option.strokeStrategy ?? 'base'; const brightColor = option.brightColor ?? '#ffffff'; const darkColor = option.darkColor ?? '#000000'; - const outsideEnable = option.outsideEnable ?? false; + const colorFromGradient = (color: ILinearGradient) => { return color.stops?.[0]?.color; }; @@ -1062,7 +1062,7 @@ export class LabelBase extends AbstractComponent { const isIntersect = !isInside && label.AABBBounds && baseMark.AABBBounds && baseMark.AABBBounds.intersects(label.AABBBounds); - if (isInside || outsideEnable || (isIntersect && interactInvertType === 'inside')) { + if (isInside || (isIntersect && interactInvertType === 'inside')) { // 按照标签展示在柱子内部的情况,执行反色逻辑 const fill = smartInvertStrategy(fillStrategy, backgroundColor, invertColor, similarColor); fill && label.setAttributes({ fill }); diff --git a/packages/vrender-components/src/label/type.ts b/packages/vrender-components/src/label/type.ts index b48256f6f..64980cf15 100644 --- a/packages/vrender-components/src/label/type.ts +++ b/packages/vrender-components/src/label/type.ts @@ -270,6 +270,7 @@ export interface SmartInvertAttrs { darkColor?: string; /** * label超出mark范围,也以mark作为背景色进行反色 + * @deprecated since 0.22.0 */ outsideEnable?: boolean; /** From 3f1d3a450d1decadfac0fcf76dea38784b5a7989 Mon Sep 17 00:00:00 2001 From: xiaoluoHe Date: Wed, 15 Jan 2025 15:50:29 +0800 Subject: [PATCH 07/10] docs: add changelog --- .../feat-smartInvert-optimize_2025-01-15-07-50.json | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 common/changes/@visactor/vrender-components/feat-smartInvert-optimize_2025-01-15-07-50.json diff --git a/common/changes/@visactor/vrender-components/feat-smartInvert-optimize_2025-01-15-07-50.json b/common/changes/@visactor/vrender-components/feat-smartInvert-optimize_2025-01-15-07-50.json new file mode 100644 index 000000000..9d269e1a2 --- /dev/null +++ b/common/changes/@visactor/vrender-components/feat-smartInvert-optimize_2025-01-15-07-50.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@visactor/vrender-components", + "comment": " refactor: deprecate `label.smartInvert.outsideEnable`", + "type": "none" + } + ], + "packageName": "@visactor/vrender-components" +} \ No newline at end of file From baeced41857974a2723279e6148c04edee187ad8 Mon Sep 17 00:00:00 2001 From: xiaoluoHe Date: Wed, 15 Jan 2025 16:24:24 +0800 Subject: [PATCH 08/10] feat: support `lumCalculate` in label smartInvert --- ...smartInvert-optimize_2025-01-15-08-24.json | 10 ++ packages/vrender-components/src/label/type.ts | 7 ++ .../src/util/label-smartInvert.ts | 96 +++++-------------- 3 files changed, 39 insertions(+), 74 deletions(-) create mode 100644 common/changes/@visactor/vrender-components/feat-smartInvert-optimize_2025-01-15-08-24.json diff --git a/common/changes/@visactor/vrender-components/feat-smartInvert-optimize_2025-01-15-08-24.json b/common/changes/@visactor/vrender-components/feat-smartInvert-optimize_2025-01-15-08-24.json new file mode 100644 index 000000000..739e8da6d --- /dev/null +++ b/common/changes/@visactor/vrender-components/feat-smartInvert-optimize_2025-01-15-08-24.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@visactor/vrender-components", + "comment": "feat: support `lumCalculate` in label smartInvert", + "type": "none" + } + ], + "packageName": "@visactor/vrender-components" +} \ No newline at end of file diff --git a/packages/vrender-components/src/label/type.ts b/packages/vrender-components/src/label/type.ts index 64980cf15..a1a388839 100644 --- a/packages/vrender-components/src/label/type.ts +++ b/packages/vrender-components/src/label/type.ts @@ -225,6 +225,13 @@ export interface SmartInvertAttrs { * 默认使用'WCAG' */ mode?: string; + /** + * 颜色亮度的计算方法。 + * 当 mode 为 'WCAG' 时,默认采用 'wcag' 标准计算方法,参考:https://www.w3.org/TR/WCAG21/#use-of-color + * 当 mode 为 'lightness' 时,默认采用 'hsl' + * @since 0.22.0 + */ + lumCalculate?: 'wcag' | 'hsl' | 'hsv' | 'lum' | 'lum2' | 'lum3'; /** * 文本类型 * 包含普通文本和大文本,对应不同的对比度标准,label默认为普通文本 diff --git a/packages/vrender-components/src/util/label-smartInvert.ts b/packages/vrender-components/src/util/label-smartInvert.ts index 3db5e1d0d..3b9b64b18 100644 --- a/packages/vrender-components/src/util/label-smartInvert.ts +++ b/packages/vrender-components/src/util/label-smartInvert.ts @@ -1,8 +1,14 @@ import type { IColor } from '@visactor/vrender-core'; -import { Color, RGB, hexToRgb, isValidNumber } from '@visactor/vutils'; +import { Color, RGB, isValidNumber } from '@visactor/vutils'; +import type { SmartInvertAttrs } from '../label'; const defaultAlternativeColors: string[] = ['#ffffff', '#000000']; +type SmartInvertParams = Pick< + SmartInvertAttrs, + 'textType' | 'contrastRatiosThreshold' | 'alternativeColors' | 'mode' | 'lumCalculate' | 'underlyingColor' +>; + /** * 标签智能反色 * @param foregroundColorOrigin @@ -14,14 +20,7 @@ export function labelSmartInvert( backgroundColorOrigin: IColor | undefined, foregroundOpacity: number, backgroundOpacity: number, - params: { - textType?: string | undefined; - contrastRatiosThreshold?: number; - alternativeColors?: string | string[]; - mode?: string; - // 背景色为透明时,用作颜色混合 - underlyingColor?: string; - } = {} + params: SmartInvertParams = {} ): IColor | undefined { if (typeof foregroundColorOrigin !== 'string' || typeof backgroundColorOrigin !== 'string') { return foregroundColorOrigin; @@ -37,15 +36,8 @@ export function labelSmartInvert( } const foregroundHex = foregroundColor.toHex(); const backgroundHex = backgroundColor.toHex(); - if (!contrastAccessibilityChecker(foregroundHex, backgroundHex, textType, contrastRatiosThreshold, mode)) { - return improveContrastReverse( - foregroundHex, - backgroundHex, - textType, - contrastRatiosThreshold, - alternativeColors, - mode - ); + if (!contrastAccessibilityChecker(foregroundHex, backgroundHex, { textType, contrastRatiosThreshold, mode })) { + return improveContrastReverse(foregroundHex, backgroundHex, params); } return foregroundHex; } @@ -78,12 +70,10 @@ function blendColor(source: Color, background?: Color) { function improveContrastReverse( foregroundColor: IColor | undefined, backgroundColor: IColor | undefined, - textType?: IColor | undefined, - contrastRatiosThreshold?: number, - alternativeColors?: string | string[], - mode?: string + params: SmartInvertParams = {} ) { const alternativeColorPalletes: string[] = []; + const { alternativeColors } = params; if (alternativeColors) { if (alternativeColors instanceof Array) { alternativeColorPalletes.push(...alternativeColors); @@ -96,7 +86,7 @@ function improveContrastReverse( if (foregroundColor === alternativeColor) { continue; } - if (contrastAccessibilityChecker(alternativeColor, backgroundColor, textType, contrastRatiosThreshold, mode)) { + if (contrastAccessibilityChecker(alternativeColor, backgroundColor, params)) { return alternativeColor; } } @@ -115,13 +105,15 @@ function improveContrastReverse( export function contrastAccessibilityChecker( foregroundColor: IColor | undefined, backgroundColor: IColor | undefined, - textType?: IColor | undefined, - contrastRatiosThreshold?: number, - mode?: string + params: SmartInvertParams = {} ): boolean { + const { mode, textType, contrastRatiosThreshold } = params; + const isLightnessMode = mode === 'lightness'; + const lumCalculate = (params.lumCalculate as SmartInvertAttrs['lumCalculate']) ?? isLightnessMode ? 'hsl' : 'wcag'; + + const backgroundColorLightness = Color.getColorBrightness(new Color(backgroundColor as string), lumCalculate as any); + const foregroundColorLightness = Color.getColorBrightness(new Color(foregroundColor as string), lumCalculate as any); if (mode === 'lightness') { - const backgroundColorLightness = Color.getColorBrightness(new Color(backgroundColor as string)); - const foregroundColorLightness = Color.getColorBrightness(new Color(foregroundColor as string)); if (foregroundColorLightness < 0.5) { // 文字颜色为'#ffffff' if (backgroundColorLightness >= 0.5) { @@ -144,7 +136,7 @@ export function contrastAccessibilityChecker( threshold = 4.5; } } - return contrastRatios(foregroundColor, backgroundColor) > threshold; + return contrastRatios(foregroundColorLightness, backgroundColorLightness) > threshold; } /** @@ -157,57 +149,13 @@ export function contrastAccessibilityChecker( * @param backgroundColor * @returns */ -function contrastRatios(foregroundColor: IColor | undefined, backgroundColor: IColor | undefined): number { - const foregroundColorLuminance = getColorLuminance(foregroundColor as string); - const backgroundColorLuminance = getColorLuminance(backgroundColor as string); +function contrastRatios(foregroundColorLuminance: number, backgroundColorLuminance: number): number { const L1 = foregroundColorLuminance > backgroundColorLuminance ? foregroundColorLuminance : backgroundColorLuminance; const L2 = foregroundColorLuminance > backgroundColorLuminance ? backgroundColorLuminance : foregroundColorLuminance; const contrastRatios = (L1 + 0.05) / (L2 + 0.05); return contrastRatios; } -/** - * 计算相对亮度 https://webaim.org/articles/contrast/ - * the relative brightness of any point in a colorspace, normalized to 0 for darkest black and 1 for lightest white - * Note 1: For the sRGB colorspace, the relative luminance of a color is defined as - * L = 0.2126 * R + 0.7152 * G + 0.0722 * B where R, G and B are defined as: - * if RsRGB <= 0.03928 then R = RsRGB/12.92 else R = ((RsRGB+0.055)/1.055) ^ 2.4 - * if GsRGB <= 0.03928 then G = GsRGB/12.92 else G = ((GsRGB+0.055)/1.055) ^ 2.4 - * if BsRGB <= 0.03928 then B = BsRGB/12.92 else B = ((BsRGB+0.055)/1.055) ^ 2.4 - * and RsRGB, GsRGB, and BsRGB are defined as: - * RsRGB = R8bit/255 - * GsRGB = G8bit/255 - * BsRGB = B8bit/255 - * @param color - * @returns - */ -function getColorLuminance(color: string): number { - const rgb8bit = hexToRgb(color); - const RsRGB = rgb8bit[0] / 255; - const GsRGB = rgb8bit[1] / 255; - const BsRGB = rgb8bit[2] / 255; - let R; - let G; - let B; - if (RsRGB <= 0.03928) { - R = RsRGB / 12.92; - } else { - R = Math.pow((RsRGB + 0.055) / 1.055, 2.4); - } - if (GsRGB <= 0.03928) { - G = GsRGB / 12.92; - } else { - G = Math.pow((GsRGB + 0.055) / 1.055, 2.4); - } - if (BsRGB <= 0.03928) { - B = BsRGB / 12.92; - } else { - B = Math.pow((BsRGB + 0.055) / 1.055, 2.4); - } - const L = 0.2126 * R + 0.7152 * G + 0.0722 * B; - return L; -} - export function smartInvertStrategy( fillStrategy: string, baseColor: IColor, From 55affc699fff84dc4c157120ed37d2158ae084e4 Mon Sep 17 00:00:00 2001 From: xiaoluoHe Date: Wed, 15 Jan 2025 17:14:29 +0800 Subject: [PATCH 09/10] fix: params omitted when compute accessibility --- packages/vrender-components/src/label/base.ts | 28 ++++++++----------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/packages/vrender-components/src/label/base.ts b/packages/vrender-components/src/label/base.ts index d35203bf1..892179576 100644 --- a/packages/vrender-components/src/label/base.ts +++ b/packages/vrender-components/src/label/base.ts @@ -1043,21 +1043,23 @@ export class LabelBase extends AbstractComponent { foregroundColor = firstStopColor; // 渐变色的时候,标签的颜色可能会和背景色不一致,所以需要设置为相同的颜色 } } - + const smartInvertParams = { + textType, + contrastRatiosThreshold, + alternativeColors, + mode, + underlyingColor + }; const invertColor = labelSmartInvert( foregroundColor, backgroundColor, foregroundFillOpacity * foregroundOpacity, backgroundFillOpacity * backgroundOpacity, - { - textType, - contrastRatiosThreshold, - alternativeColors, - mode, - underlyingColor - } + smartInvertParams ); - const similarColor = contrastAccessibilityChecker(invertColor, brightColor) ? brightColor : darkColor; + const similarColor = contrastAccessibilityChecker(invertColor, brightColor, smartInvertParams) + ? brightColor + : darkColor; const isInside = this._canPlaceInside(label.AABBBounds, baseMark.AABBBounds); const isIntersect = !isInside && label.AABBBounds && baseMark.AABBBounds && baseMark.AABBBounds.intersects(label.AABBBounds); @@ -1088,13 +1090,7 @@ export class LabelBase extends AbstractComponent { label.attribute.stroke as IColor, foregroundFillOpacity * foregroundOpacity, foregroundStrokeOpacity * foregroundOpacity, - { - textType, - contrastRatiosThreshold, - alternativeColors, - mode, - underlyingColor - } + smartInvertParams ) }); continue; From 8520ea99d8898a5ad8e008e1912031a9d887b87c Mon Sep 17 00:00:00 2001 From: xiaoluoHe Date: Thu, 16 Jan 2025 14:06:15 +0800 Subject: [PATCH 10/10] feat: upgrade vutils --- common/config/rush/pnpm-lock.yaml | 55 ++++++++++++----------- docs/demos/package.json | 2 +- docs/package.json | 2 +- packages/react-vrender-utils/package.json | 2 +- packages/react-vrender/package.json | 2 +- packages/vrender-components/package.json | 6 +-- packages/vrender-core/package.json | 2 +- packages/vrender-kits/package.json | 2 +- packages/vrender/package.json | 2 +- 9 files changed, 40 insertions(+), 35 deletions(-) diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index 33a9c01a1..8bb3647bd 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -15,7 +15,7 @@ importers: '@visactor/vchart': 1.3.0 '@visactor/vgrammar': ~0.5.7 '@visactor/vrender': workspace:0.21.11 - '@visactor/vutils': ~0.19.3 + '@visactor/vutils': 0.19.4-alpha.0 '@vitejs/plugin-react': 3.1.0 axios: ^1.4.0 chalk: ^3.0.0 @@ -38,7 +38,7 @@ importers: '@visactor/vchart': 1.3.0 '@visactor/vgrammar': 0.5.7 '@visactor/vrender': link:../packages/vrender - '@visactor/vutils': 0.19.3 + '@visactor/vutils': 0.19.4-alpha.0 axios: 1.7.9 highlight.js: 11.11.1 lodash: 4.17.21 @@ -72,7 +72,7 @@ importers: '@types/react-dom': ^18.0.0 '@types/react-reconciler': ^0.28.2 '@visactor/vrender': workspace:0.21.11 - '@visactor/vutils': ~0.19.3 + '@visactor/vutils': 0.19.4-alpha.0 '@vitejs/plugin-react': 3.1.0 cross-env: ^7.0.3 eslint: ~8.18.0 @@ -84,7 +84,7 @@ importers: vite: 3.2.6 dependencies: '@visactor/vrender': link:../vrender - '@visactor/vutils': 0.19.3 + '@visactor/vutils': 0.19.4-alpha.0 react-reconciler: 0.29.2_react@18.3.1 tslib: 2.8.1 devDependencies: @@ -113,7 +113,7 @@ importers: '@types/react-dom': ^18.0.0 '@visactor/react-vrender': workspace:0.21.11 '@visactor/vrender': workspace:0.21.11 - '@visactor/vutils': ~0.19.3 + '@visactor/vutils': 0.19.4-alpha.0 '@vitejs/plugin-react': 3.1.0 cross-env: ^7.0.3 eslint: ~8.18.0 @@ -126,7 +126,7 @@ importers: dependencies: '@visactor/react-vrender': link:../react-vrender '@visactor/vrender': link:../vrender - '@visactor/vutils': 0.19.3 + '@visactor/vutils': 0.19.4-alpha.0 react-reconciler: 0.29.2_react@18.3.1 tslib: 2.8.1 devDependencies: @@ -155,7 +155,7 @@ importers: '@types/react-dom': ^18.0.0 '@visactor/vrender-core': workspace:0.21.11 '@visactor/vrender-kits': workspace:0.21.11 - '@visactor/vutils': ~0.19.3 + '@visactor/vutils': 0.19.4-alpha.0 '@vitejs/plugin-react': 3.1.0 canvas: 2.11.2 cross-env: ^7.0.3 @@ -179,7 +179,7 @@ importers: '@types/jest': 26.0.24 '@types/react': 18.3.18 '@types/react-dom': 18.3.5_@types+react@18.3.18 - '@visactor/vutils': 0.19.3 + '@visactor/vutils': 0.19.4-alpha.0 '@vitejs/plugin-react': 3.1.0_vite@3.2.6 canvas: 2.11.2 cross-env: 7.0.3 @@ -202,8 +202,8 @@ importers: '@types/jest': ^26.0.0 '@visactor/vrender-core': workspace:0.21.11 '@visactor/vrender-kits': workspace:0.21.11 - '@visactor/vscale': ~0.19.3 - '@visactor/vutils': ~0.19.3 + '@visactor/vscale': 0.19.4-alpha.0 + '@visactor/vutils': 0.19.4-alpha.0 cross-env: ^7.0.3 eslint: ~8.18.0 jest: ^26.0.0 @@ -215,8 +215,8 @@ importers: dependencies: '@visactor/vrender-core': link:../vrender-core '@visactor/vrender-kits': link:../vrender-kits - '@visactor/vscale': 0.19.3 - '@visactor/vutils': 0.19.3 + '@visactor/vscale': 0.19.4-alpha.0 + '@visactor/vutils': 0.19.4-alpha.0 devDependencies: '@internal/bundler': link:../../tools/bundler '@internal/eslint-config': link:../../share/eslint-config @@ -241,7 +241,7 @@ importers: '@types/jest': ^26.0.0 '@types/react': ^18.0.0 '@types/react-dom': ^18.0.0 - '@visactor/vutils': ~0.19.3 + '@visactor/vutils': 0.19.4-alpha.0 '@vitejs/plugin-react': 3.1.0 color-convert: 2.0.1 cross-env: ^7.0.3 @@ -255,7 +255,7 @@ importers: typescript: 4.9.5 vite: 3.2.6 dependencies: - '@visactor/vutils': 0.19.3 + '@visactor/vutils': 0.19.4-alpha.0 color-convert: 2.0.1 devDependencies: '@internal/bundler': link:../../tools/bundler @@ -288,7 +288,7 @@ importers: '@types/react': ^18.0.0 '@types/react-dom': ^18.0.0 '@visactor/vrender-core': workspace:0.21.11 - '@visactor/vutils': ~0.19.3 + '@visactor/vutils': 0.19.4-alpha.0 '@vitejs/plugin-react': 3.1.0 canvas: 2.11.2 cross-env: ^7.0.3 @@ -304,7 +304,7 @@ importers: dependencies: '@resvg/resvg-js': 2.4.1 '@visactor/vrender-core': link:../vrender-core - '@visactor/vutils': 0.19.3 + '@visactor/vutils': 0.19.4-alpha.0 gifuct-js: 2.1.2 lottie-web: 5.12.2 roughjs: 4.5.2 @@ -2077,7 +2077,7 @@ packages: jest-resolve: 26.6.2 jest-resolve-dependencies: 26.6.3 jest-runner: 26.6.3_canvas@2.11.2 - jest-runtime: 26.6.3 + jest-runtime: 26.6.3_canvas@2.11.2 jest-snapshot: 26.6.2 jest-util: 26.6.2 jest-validate: 26.6.2 @@ -2248,7 +2248,7 @@ packages: graceful-fs: 4.2.11 jest-haste-map: 26.6.2 jest-runner: 26.6.3_canvas@2.11.2 - jest-runtime: 26.6.3 + jest-runtime: 26.6.3_canvas@2.11.2 transitivePeerDependencies: - bufferutil - canvas @@ -3393,10 +3393,10 @@ packages: '@visactor/vutils': 0.15.14 dev: false - /@visactor/vscale/0.19.3: - resolution: {integrity: sha512-gLf1ocsgDXcavGqtYYE62N6fH9vXRV/Cd+TeSt0eh2SR1swvi4z5effLS0rpUzjAnGr97h6QaUmhJ1acShLA8Q==} + /@visactor/vscale/0.19.4-alpha.0: + resolution: {integrity: sha512-i4v5voLbN5RjBvZWg1rfjELqoUUW9NwOkgaFs4hToZx9Dpl90JKTthX20nFuMRRX69SPGHwJ7RuDAO5rdAAQRw==} dependencies: - '@visactor/vutils': 0.19.3 + '@visactor/vutils': 0.19.4-alpha.0 dev: false /@visactor/vutils/0.13.3: @@ -3415,8 +3415,8 @@ packages: eventemitter3: 4.0.7 dev: false - /@visactor/vutils/0.19.3: - resolution: {integrity: sha512-tJAn7HWSX4hv9cDuCg4wGUvXWO7/zHwA4PLfJ45C0n4SJa0HPgIPJ2TtyYfsj54Mt7gkUx0XZpaeAVr6N4wWug==} + /@visactor/vutils/0.19.4-alpha.0: + resolution: {integrity: sha512-KPsN6MhgYaq4u+dvjUG9Zs+RctVU3XEQB2sTK6zPY5y7+UST7KmkkS3RUrZ8755pIRGmrJGJB7qk/tB3kUx/gg==} dependencies: '@turf/helpers': 6.5.0 '@turf/invariant': 6.5.0 @@ -8053,7 +8053,7 @@ packages: jest-leak-detector: 26.6.2 jest-message-util: 26.6.2 jest-resolve: 26.6.2 - jest-runtime: 26.6.3 + jest-runtime: 26.6.3_canvas@2.11.2 jest-util: 26.6.2 jest-worker: 26.6.2 source-map-support: 0.5.21 @@ -8117,7 +8117,7 @@ packages: exit: 0.1.2 glob: 7.2.3 graceful-fs: 4.2.11 - jest-config: 26.6.3_canvas@2.11.2 + jest-config: 26.6.3 jest-haste-map: 26.6.2 jest-message-util: 26.6.2 jest-mock: 26.6.2 @@ -8130,7 +8130,12 @@ packages: strip-bom: 4.0.0 yargs: 15.4.1 transitivePeerDependencies: + - bufferutil + - canvas - supports-color + - ts-node + - utf-8-validate + dev: true /jest-runtime/26.6.3_canvas@2.11.2: resolution: {integrity: sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw==} diff --git a/docs/demos/package.json b/docs/demos/package.json index cb21b2bd3..b774740ff 100644 --- a/docs/demos/package.json +++ b/docs/demos/package.json @@ -12,7 +12,7 @@ "@internal/eslint-config": "workspace:*", "@internal/ts-config": "workspace:*", "@visactor/vrender-kits": "workspace:0.14.8", - "@visactor/vutils": "~0.19.3", + "@visactor/vutils": "0.19.4-alpha.0", "d3-scale-chromatic": "^3.0.0", "lodash": "4.17.21", "dat.gui": "^0.7.9", diff --git a/docs/package.json b/docs/package.json index a92fbb445..725be4cbd 100644 --- a/docs/package.json +++ b/docs/package.json @@ -11,7 +11,7 @@ "dependencies": { "@arco-design/web-react": "2.46.1", "@visactor/vchart": "1.3.0", - "@visactor/vutils": "~0.19.3", + "@visactor/vutils": "0.19.4-alpha.0", "@visactor/vgrammar": "~0.5.7", "@visactor/vrender": "workspace:0.21.11", "markdown-it": "^13.0.0", diff --git a/packages/react-vrender-utils/package.json b/packages/react-vrender-utils/package.json index 28cd77eaa..c9b51ece8 100644 --- a/packages/react-vrender-utils/package.json +++ b/packages/react-vrender-utils/package.json @@ -26,7 +26,7 @@ "dependencies": { "@visactor/vrender": "workspace:0.21.11", "@visactor/react-vrender": "workspace:0.21.11", - "@visactor/vutils": "~0.19.3", + "@visactor/vutils": "0.19.4-alpha.0", "react-reconciler": "^0.29.0", "tslib": "^2.3.1" }, diff --git a/packages/react-vrender/package.json b/packages/react-vrender/package.json index 557b4a910..bea2c9e7a 100644 --- a/packages/react-vrender/package.json +++ b/packages/react-vrender/package.json @@ -24,7 +24,7 @@ }, "dependencies": { "@visactor/vrender": "workspace:0.21.11", - "@visactor/vutils": "~0.19.3", + "@visactor/vutils": "0.19.4-alpha.0", "react-reconciler": "^0.29.0", "tslib": "^2.3.1" }, diff --git a/packages/vrender-components/package.json b/packages/vrender-components/package.json index 84cfdeaae..91fc3e284 100644 --- a/packages/vrender-components/package.json +++ b/packages/vrender-components/package.json @@ -25,8 +25,8 @@ "build:spec-types": "rm -rf ./spec-types && tsc -p ./tsconfig.spec.json --declaration --emitDeclarationOnly --outDir ./spec-types" }, "dependencies": { - "@visactor/vutils": "~0.19.3", - "@visactor/vscale": "~0.19.3", + "@visactor/vutils": "0.19.4-alpha.0", + "@visactor/vscale": "0.19.4-alpha.0", "@visactor/vrender-core": "workspace:0.21.11", "@visactor/vrender-kits": "workspace:0.21.11" }, @@ -35,7 +35,7 @@ "@internal/eslint-config": "workspace:*", "@internal/ts-config": "workspace:*", "@rushstack/eslint-patch": "~1.1.4", - "@visactor/vscale": "~0.19.3", + "@visactor/vscale": "0.19.4-alpha.0", "@types/jest": "^26.0.0", "jest": "^26.0.0", "jest-electron": "^0.1.12", diff --git a/packages/vrender-core/package.json b/packages/vrender-core/package.json index 412c41247..22d18a67a 100644 --- a/packages/vrender-core/package.json +++ b/packages/vrender-core/package.json @@ -30,7 +30,7 @@ }, "dependencies": { "color-convert": "2.0.1", - "@visactor/vutils": "~0.19.3" + "@visactor/vutils": "0.19.4-alpha.0" }, "devDependencies": { "@internal/bundler": "workspace:*", diff --git a/packages/vrender-kits/package.json b/packages/vrender-kits/package.json index 7ae5e05dd..3ac1443c3 100644 --- a/packages/vrender-kits/package.json +++ b/packages/vrender-kits/package.json @@ -20,7 +20,7 @@ "test": "" }, "dependencies": { - "@visactor/vutils": "~0.19.3", + "@visactor/vutils": "0.19.4-alpha.0", "@visactor/vrender-core": "workspace:0.21.11", "@resvg/resvg-js": "2.4.1", "roughjs": "4.5.2", diff --git a/packages/vrender/package.json b/packages/vrender/package.json index dfbdddca5..978343a49 100644 --- a/packages/vrender/package.json +++ b/packages/vrender/package.json @@ -32,7 +32,7 @@ "@internal/eslint-config": "workspace:*", "@internal/ts-config": "workspace:*", "@rushstack/eslint-patch": "~1.1.4", - "@visactor/vutils": "~0.19.3", + "@visactor/vutils": "0.19.4-alpha.0", "canvas": "2.11.2", "react": "^18.0.0", "react-dom": "^18.0.0",