diff --git a/packages/s2-core/package.json b/packages/s2-core/package.json index 71a9549577..9d367bd214 100644 --- a/packages/s2-core/package.json +++ b/packages/s2-core/package.json @@ -62,6 +62,7 @@ }, "devDependencies": { "d3-dsv": "^1.1.1", + "tinycolor2": "^1.4.2", "inquirer": "^8.2.0", "inquirer-autocomplete-prompt": "^1.4.0" }, diff --git a/packages/s2-core/src/common/interface/theme.ts b/packages/s2-core/src/common/interface/theme.ts index 492652793a..3ee364c153 100644 --- a/packages/s2-core/src/common/interface/theme.ts +++ b/packages/s2-core/src/common/interface/theme.ts @@ -15,9 +15,13 @@ export interface Palette { semanticColors: { red?: string; green?: string; - /* 额外颜色字段 */ [key: string]: string; }; + /* 用于标记生成色板时固定不变的色值索引 */ + fixedColorIndex?: number[]; + /* 主题色索引 */ + brandColorIndex?: number; + /* 额外颜色字段 */ } export interface Padding { diff --git a/packages/s2-core/src/theme/palette/colorful.ts b/packages/s2-core/src/theme/palette/colorful.ts index 20ab172a5a..7493a966bd 100644 --- a/packages/s2-core/src/theme/palette/colorful.ts +++ b/packages/s2-core/src/theme/palette/colorful.ts @@ -4,6 +4,7 @@ export const paletteColorful = { '#FFFFFF', '#F4F7FE', '#DDE7FD', + // brand color '#3471F9', '#2C60D3', '#2C60D3', @@ -23,4 +24,9 @@ export const paletteColorful = { red: '#FF4D4F', green: '#29A294', }, + + // 用于标记生成色板时固定不变的色值索引 + fixedColorIndex: [0, 13, 14], + // 主题色索引 + brandColorIndex: 3, }; diff --git a/packages/s2-core/src/theme/palette/default.ts b/packages/s2-core/src/theme/palette/default.ts index 434a0abe00..f205115d8c 100644 --- a/packages/s2-core/src/theme/palette/default.ts +++ b/packages/s2-core/src/theme/palette/default.ts @@ -8,6 +8,7 @@ export const paletteDefault = { '#CCDBFD', '#2C60D3', '#0000EE', + // brand color '#326EF4', '#FFFFFF', '#EBF2FF', @@ -23,4 +24,9 @@ export const paletteDefault = { red: '#FF4D4F', green: '#29A294', }, + + // 用于标记生成色板时固定不变的色值索引 + fixedColorIndex: [0, 13, 14], + // 主题色索引 + brandColorIndex: 7, }; diff --git a/packages/s2-core/src/theme/palette/gray.ts b/packages/s2-core/src/theme/palette/gray.ts index d8fccc2e73..736b3b26b8 100644 --- a/packages/s2-core/src/theme/palette/gray.ts +++ b/packages/s2-core/src/theme/palette/gray.ts @@ -8,6 +8,7 @@ export const paletteGray = { '#E7E8EA', '#CECFD1', '#A9AAAB', + // brand color '#616162', '#FFFFFF', '#F2F2F2', @@ -22,4 +23,9 @@ export const paletteGray = { red: '#FF4D4F', green: '#29A294', }, + + // 用于标记生成色板时固定不变的色值索引 + fixedColorIndex: [0, 13, 14], + // 主题色索引 + brandColorIndex: 7, }; diff --git a/packages/s2-core/src/utils/color.ts b/packages/s2-core/src/utils/color.ts new file mode 100644 index 0000000000..ef6bac3d8a --- /dev/null +++ b/packages/s2-core/src/utils/color.ts @@ -0,0 +1,32 @@ +import tinycolor from 'tinyColor2'; +import { includes, map } from 'lodash'; +import { Palette } from '@/common'; + +export const generatePalette = (palette: Palette, brandColor: string) => { + const { basicColors, ...restParams } = palette; + const preBrandColor = tinycolor( + basicColors[restParams?.brandColorIndex], + ).toRgb(); + const newBrandColor = tinycolor(brandColor).toRgb(); + const distance = { + r: newBrandColor.r - preBrandColor.r, + g: newBrandColor.g - preBrandColor.g, + b: newBrandColor.b - preBrandColor.b, + }; + const newColors = map(basicColors, (color: string, key) => { + if (includes(restParams?.fixedColorIndex, key)) { + return color; + } + const preColor = tinycolor(color).toRgb(); + const newColor = tinycolor({ + r: preColor.r + distance.r, + g: preColor.g + distance.g, + b: preColor.b + distance.b, + }); + return `#${newColor.toHex().toUpperCase()}`; + }); + return { + basicColors: newColors, + ...restParams, + }; +}; diff --git a/packages/s2-core/src/utils/index.ts b/packages/s2-core/src/utils/index.ts index 198cdbf651..c697c9aafc 100644 --- a/packages/s2-core/src/utils/index.ts +++ b/packages/s2-core/src/utils/index.ts @@ -2,6 +2,7 @@ export { splitTotal } from './data-set-operate'; export { auto } from './formatter'; export * from './layout'; export * from './text'; +export * from './color'; export * from './theme'; export * from './export/index'; export * from './export/copy'; diff --git a/packages/s2-react/package.json b/packages/s2-react/package.json index ffe05ce57b..a35961b4c4 100644 --- a/packages/s2-react/package.json +++ b/packages/s2-react/package.json @@ -69,7 +69,8 @@ "antd": "^4.16.13", "concurrently": "^7.0.0", "react": "^17.0.2", - "react-dom": "^17.0.2" + "react-dom": "^17.0.2", + "react-color": "^2.19.3" }, "bundlesize": [ { diff --git a/packages/s2-react/playground/index.tsx b/packages/s2-react/playground/index.tsx index 2ef1302ce9..173c9717d8 100644 --- a/packages/s2-react/playground/index.tsx +++ b/packages/s2-react/playground/index.tsx @@ -16,6 +16,7 @@ import { } from 'antd'; import React from 'react'; import ReactDOM from 'react-dom'; +import { ChromePicker } from 'react-color'; import { HeaderActionIconProps, S2Options, @@ -29,6 +30,8 @@ import { ThemeCfg, S2Theme, DataType, + generatePalette, + getPalette, } from '@antv/s2'; import corePkg from '@antv/s2/package.json'; import { forEach, random } from 'lodash'; @@ -147,6 +150,7 @@ function MainLayout() { const [showPagination, setShowPagination] = React.useState(false); const [showTotals, setShowTotals] = React.useState(false); const [themeCfg, setThemeCfg] = React.useState({ name: 'default' }); + const [themeColor, setThemeColor] = React.useState('#FFF'); const [showCustomTooltip, setShowCustomTooltip] = React.useState(false); const [adaptive, setAdaptive] = React.useState(false); const [options, setOptions] = @@ -210,11 +214,9 @@ function MainLayout() { }; const onThemeChange = (e: RadioChangeEvent) => { - setThemeCfg( - customMerge({}, themeCfg, { - name: e.target.value, - }), - ); + setThemeCfg({ + name: e.target.value, + }); }; const onSheetTypeChange = (e: RadioChangeEvent) => { @@ -415,6 +417,33 @@ function MainLayout() { + + + { + setThemeColor(color.hex); + const palette = getPalette(themeCfg.name); + const newPalette = generatePalette( + palette, + color.hex, + ); + setThemeCfg({ + palette: newPalette, + }); + }} + /> + + } + > + + +