From 4b200adf94560d54ceeca1543aa627fdecdceb2f Mon Sep 17 00:00:00 2001 From: Antik <94498092+fengyxz@users.noreply.github.com> Date: Mon, 7 Aug 2023 11:47:12 +0800 Subject: [PATCH] feat: add background&independence control (#107) * feat: add background&independence control * fix: text color * fix: delete the reduntant ref * fix: add toJS --------- Co-authored-by: k6sdevbob --- .../graphic-walker/src/components/toggle.tsx | 4 +- .../src/components/visualConfig/index.tsx | 86 +++++++++++++++++-- packages/graphic-walker/src/config.ts | 14 ++- packages/graphic-walker/src/interfaces.ts | 9 ++ .../graphic-walker/src/locales/en-US.json | 10 ++- .../graphic-walker/src/locales/ja-JP.json | 10 ++- .../graphic-walker/src/locales/zh-CN.json | 10 ++- .../src/renderer/specRenderer.tsx | 27 ++++-- .../src/store/visualSpecStore.ts | 23 +++-- .../graphic-walker/src/vis/react-vega.tsx | 16 +++- 10 files changed, 182 insertions(+), 27 deletions(-) diff --git a/packages/graphic-walker/src/components/toggle.tsx b/packages/graphic-walker/src/components/toggle.tsx index f3fda869..c4f0dcaf 100644 --- a/packages/graphic-walker/src/components/toggle.tsx +++ b/packages/graphic-walker/src/components/toggle.tsx @@ -20,7 +20,7 @@ export default function Toggle(props: ToggleProps) { checked={enabled} onChange={onChange} className={classNames( - enabled ? 'bg-indigo-600' : 'bg-gray-200', + enabled ? 'bg-indigo-600' : 'bg-gray-200 dark:bg-gray-700', 'relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2' )} > @@ -33,7 +33,7 @@ export default function Toggle(props: ToggleProps) { /> - {label} + {label} ); diff --git a/packages/graphic-walker/src/components/visualConfig/index.tsx b/packages/graphic-walker/src/components/visualConfig/index.tsx index b24ac553..3a8ecdb2 100644 --- a/packages/graphic-walker/src/components/visualConfig/index.tsx +++ b/packages/graphic-walker/src/components/visualConfig/index.tsx @@ -1,13 +1,15 @@ import { observer } from 'mobx-react-lite'; -import React, { useState } from 'react'; +import React, { useEffect, useRef, useState } from 'react'; import { useGlobalStore } from '../../store'; +import { NonPositionChannelConfigList,PositionChannelConfigList } from '../../config'; + import Modal from '../modal'; import { IVisualConfig } from '../../interfaces'; import PrimaryButton from '../button/primary'; import DefaultButton from '../button/default'; import { useTranslation } from 'react-i18next'; import Toggle from '../toggle'; -import { runInAction } from 'mobx'; +import { runInAction, toJS } from 'mobx'; const VisualConfigPanel: React.FC = (props) => { const { commonStore, vizStore } = useGlobalStore(); @@ -24,7 +26,27 @@ const VisualConfigPanel: React.FC = (props) => { timeFormat: visualConfig.format.timeFormat, normalizedNumberFormat: visualConfig.format.normalizedNumberFormat, }); + const [resolve, setResolve] = useState({ + x: visualConfig.resolve.x, + y: visualConfig.resolve.y, + color: visualConfig.resolve.color, + opacity: visualConfig.resolve.opacity, + shape: visualConfig.resolve.shape, + size: visualConfig.resolve.size, + }); const [zeroScale, setZeroScale] = useState(visualConfig.zeroScale); + const [background, setBackground] = useState(visualConfig.background); + + useEffect(() => { + setZeroScale(visualConfig.zeroScale); + setBackground(visualConfig.background); + setResolve(toJS(visualConfig.resolve)); + setFormat({ + numberFormat: visualConfig.format.numberFormat, + timeFormat: visualConfig.format.timeFormat, + normalizedNumberFormat: visualConfig.format.normalizedNumberFormat, + }); + }, [showVisualConfigPanel]); return ( {

{t('config.format')}

- Format guides docs:{' '} + {t(`config.formatGuidesDocs`)}:{' '} - read here + {t(`config.readHere`)}

{formatConfigList.map((fc) => (
- +
{ setFormat((f) => ({ @@ -63,9 +85,55 @@ const VisualConfigPanel: React.FC = (props) => {
))} +

{t('config.background')}

+
+ +
+ { + setBackground(e.target.value); + }} + /> +
+
+

{t('config.independence')}

+
+
+ {PositionChannelConfigList.map((pc) => ( + { + setResolve((r) => ({ + ...r, + [pc]: e, + })); + }} + /> + ))} + {NonPositionChannelConfigList.map((npc) => ( + { + setResolve((r) => ({ + ...r, + [npc]: e, + })); + }} + /> + ))} +
+
+

{t('config.zeroScale')}

{ setZeroScale(en); @@ -80,8 +148,10 @@ const VisualConfigPanel: React.FC = (props) => { runInAction(() => { vizStore.setVisualConfig('format', format); vizStore.setVisualConfig('zeroScale', zeroScale); + vizStore.setVisualConfig('background', background); + vizStore.setVisualConfig('resolve', resolve); commonStore.setShowVisualConfigPanel(false); - }) + }); }} /> = [ 'auto', @@ -57,4 +57,16 @@ export const CHANNEL_LIMIT = { export const MetaFieldKeys: Array = [ 'dimensions', 'measures', +] + +export const PositionChannelConfigList: Array = [ + 'x', + 'y', +] + +export const NonPositionChannelConfigList: Array = [ + 'color', + 'opacity', + 'shape', + 'size' ] \ No newline at end of file diff --git a/packages/graphic-walker/src/interfaces.ts b/packages/graphic-walker/src/interfaces.ts index 32a32e5d..96605ebb 100644 --- a/packages/graphic-walker/src/interfaces.ts +++ b/packages/graphic-walker/src/interfaces.ts @@ -202,11 +202,20 @@ export interface IVisualConfig { interactiveScale: boolean; sorted: 'none' | 'ascending' | 'descending'; zeroScale: boolean; + background?: string; format: { numberFormat?: string; timeFormat?: string; normalizedNumberFormat?: string; }; + resolve: { + x?: boolean; + y?: boolean; + color?: boolean; + opacity?: boolean; + shape?: boolean; + size?: boolean; + }; size: { mode: 'auto' | 'fixed'; width: number; diff --git a/packages/graphic-walker/src/locales/en-US.json b/packages/graphic-walker/src/locales/en-US.json index 1155e9bf..17d0ee97 100644 --- a/packages/graphic-walker/src/locales/en-US.json +++ b/packages/graphic-walker/src/locales/en-US.json @@ -3,7 +3,15 @@ "format": "Format", "numberFormat": "Number format", "timeFormat": "Time format", - "normalizedNumberFormat": "Normalized number format" + "normalizedNumberFormat": "Normalized number format", + "background": "Background", + "color":"Color", + "independence": "Independence", + "x": "x-Axis", + "y": "y-Axis", + "zeroScale": "Zero Scale", + "formatGuidesDocs": "Format guides docs", + "readHere": "read here" }, "constant": { "row_count": "Row count", diff --git a/packages/graphic-walker/src/locales/ja-JP.json b/packages/graphic-walker/src/locales/ja-JP.json index 06b30ee9..753274a5 100644 --- a/packages/graphic-walker/src/locales/ja-JP.json +++ b/packages/graphic-walker/src/locales/ja-JP.json @@ -3,7 +3,15 @@ "format": "形式", "numberFormat": "数字の形式", "timeFormat": "時間の形式", - "normalizedNumberFormat": "正規化された数字の形式" + "normalizedNumberFormat": "正規化された数字の形式", + "background": "背景", + "color":"色", + "independence": "独立性", + "x": "x軸", + "y": "y軸", + "zeroScale": "ゼロ目盛", + "formatGuidesDocs": "フォーマットガイド", + "readHere": "ここを読む" }, "constant": { "row_count": "行数", diff --git a/packages/graphic-walker/src/locales/zh-CN.json b/packages/graphic-walker/src/locales/zh-CN.json index 6ee7823a..7e4bda08 100644 --- a/packages/graphic-walker/src/locales/zh-CN.json +++ b/packages/graphic-walker/src/locales/zh-CN.json @@ -3,7 +3,15 @@ "format": "格式", "numberFormat": "数字格式", "timeFormat": "时间格式", - "normalizedNumberFormat": "标准化数字格式" + "normalizedNumberFormat": "标准化数字格式", + "background": "背景", + "color":"颜色", + "independence": "独立性", + "x": "x轴", + "y": "y轴", + "zeroScale": "零刻度", + "formatGuidesDocs": "格式指南", + "readHere": "阅读此处" }, "constant": { "row_count": "行数", diff --git a/packages/graphic-walker/src/renderer/specRenderer.tsx b/packages/graphic-walker/src/renderer/specRenderer.tsx index eedec861..8a9f913b 100644 --- a/packages/graphic-walker/src/renderer/specRenderer.tsx +++ b/packages/graphic-walker/src/renderer/specRenderer.tsx @@ -29,7 +29,7 @@ const SpecRenderer = forwardRef(function ( ref ) { // const { draggableFieldState, visualConfig } = vizStore; - const { geoms, interactiveScale, defaultAggregated, stack, showActions, size, format: _format, zeroScale } = visualConfig; + const { geoms, interactiveScale, defaultAggregated, stack, showActions, size, format: _format, background, zeroScale, resolve } = visualConfig; const rows = draggableFieldState.rows; const columns = draggableFieldState.columns; @@ -41,7 +41,7 @@ const SpecRenderer = forwardRef(function ( const sizeChannel = draggableFieldState.size; const details = draggableFieldState.details; const text = draggableFieldState.text; - const format = toJS(_format) + const format = toJS(_format); const rowLeftFacetFields = useMemo(() => rows.slice(0, -1).filter((f) => f.analyticType === 'dimension'), [rows]); const colLeftFacetFields = useMemo( @@ -59,8 +59,9 @@ const SpecRenderer = forwardRef(function ( const vegaConfig = useMemo(() => { const config: VegaGlobalConfig = { - ...themeConfig, - } + ...themeConfig, + background: mediaTheme === 'dark' ? '#18181f' : '#ffffff', + }; if (format.normalizedNumberFormat && format.normalizedNumberFormat.length > 0) { // @ts-ignore config.normalizedNumberFormat = format.normalizedNumberFormat; @@ -79,9 +80,23 @@ const SpecRenderer = forwardRef(function ( config.scale = {}; } // @ts-ignore - config.scale.zero = Boolean(zeroScale) + config.scale.zero = Boolean(zeroScale); + // @ts-ignore + config.resolve = resolve; + if (background) { + config.background = background; + } + return config; - }, [themeConfig, zeroScale, format.normalizedNumberFormat, format.numberFormat, format.timeFormat]) + }, [ + themeConfig, + zeroScale, + resolve, + background, + format.normalizedNumberFormat, + format.numberFormat, + format.timeFormat, + ]); if (isPivotTable) { return ( diff --git a/packages/graphic-walker/src/store/visualSpecStore.ts b/packages/graphic-walker/src/store/visualSpecStore.ts index c2d16d9f..1b673ea4 100644 --- a/packages/graphic-walker/src/store/visualSpecStore.ts +++ b/packages/graphic-walker/src/store/visualSpecStore.ts @@ -71,6 +71,7 @@ export function initVisualConfig(): IVisualConfig { interactiveScale: false, sorted: "none", zeroScale: true, + background: undefined, size: { mode: "auto", width: 320, @@ -79,8 +80,16 @@ export function initVisualConfig(): IVisualConfig { format: { numberFormat: undefined, timeFormat: undefined, - normalizedNumberFormat: undefined - } + normalizedNumberFormat: undefined, + }, + resolve: { + x: false, + y: false, + color: false, + opacity: false, + shape: false, + size: false, + }, }; } @@ -205,7 +214,7 @@ export class VizSpecStore { if (this.__dangerous_is_inside_useMutable__) { throw new Error( "A recursive call of useMutable() is detected, " + - "this is prevented because update will be overwritten by parent execution context." + "this is prevented because update will be overwritten by parent execution context." ); } @@ -299,7 +308,7 @@ export class VizSpecStore { return state.filters; } - + public addVisualization(defaultName?: string) { const name = defaultName || 'Chart ' + (this.visList.length + 1); this.visList.push( @@ -375,11 +384,13 @@ export class VizSpecStore { case configKey === "size" && typeof value === "object": case configKey === "sorted": case configKey === "zeroScale": + case configKey === "background": case configKey === "stack": { return (config[configKey] = value); } - case configKey === 'format' && typeof value === "object": { - return config[configKey] = value + case configKey === "format" && typeof value === "object": + case configKey === "resolve" && typeof value === "object": { + return (config[configKey] = value); } default: { diff --git a/packages/graphic-walker/src/vis/react-vega.tsx b/packages/graphic-walker/src/vis/react-vega.tsx index ad5bef88..fadd3ba6 100644 --- a/packages/graphic-walker/src/vis/react-vega.tsx +++ b/packages/graphic-walker/src/vis/react-vega.tsx @@ -4,7 +4,7 @@ import { Subject, Subscription } from 'rxjs' import * as op from 'rxjs/operators'; import type { ScenegraphEvent } from 'vega'; import styled from 'styled-components'; - +import { NonPositionChannelConfigList, PositionChannelConfigList } from '../config'; import { useVegaExportApi } from '../utils/vegaApiExport'; import { IViewField, IRow, IStackMode, VegaGlobalConfig, IVegaChartRef } from '../interfaces'; import { useTranslation } from 'react-i18next'; @@ -221,6 +221,20 @@ const ReactVega = forwardRef(function ReactVe spec.encoding = singleView.encoding; } + spec.resolve ||= {}; + // @ts-ignore + let resolve = vegaConfig.resolve; + for (let v in resolve) { + let value = resolve[v] ? 'independent' : 'shared'; + // @ts-ignore + spec.resolve.scale = { ...spec.resolve.scale, [v]: value }; + if((PositionChannelConfigList as string[]).includes(v)) { + spec.resolve.axis = { ...spec.resolve.axis, [v]: value }; + }else if((NonPositionChannelConfigList as string[]).includes(v)){ + spec.resolve.legend = { ...spec.resolve.legend, [v]: value }; + } + } + if (viewPlaceholders.length > 0 && viewPlaceholders[0].current) { const task = embed(viewPlaceholders[0].current, spec, { mode: 'vega-lite', actions: showActions, timeFormatLocale: getVegaTimeFormatRules(i18n.language), config: vegaConfig }).then(res => { const container = res.view.container();