diff --git a/packages/vstory/demo/src/demos/VChartGraphic.tsx b/packages/vstory/demo/src/demos/VChartGraphic.tsx index eb33f863..423e186a 100644 --- a/packages/vstory/demo/src/demos/VChartGraphic.tsx +++ b/packages/vstory/demo/src/demos/VChartGraphic.tsx @@ -526,46 +526,279 @@ const spec = { }; const spec1 = { - type: 'bar', - background: 'transparent', - data: { - values: [ - { type: 'Nail polish', country: 'Africa', value: 4229 }, - { type: 'Nail polish', country: 'EU', value: 4376 }, - { type: 'Nail polish', country: 'China', value: 3054 }, - { type: 'Nail polish', country: 'USA', value: 12814 }, - { type: 'Eyebrow pencil', country: 'Africa', value: 3932 }, - { type: 'Eyebrow pencil', country: 'EU', value: 3987 }, - { type: 'Eyebrow pencil', country: 'China', value: 5067 }, - { type: 'Eyebrow pencil', country: 'USA', value: 13012 }, - { type: 'Rouge', country: 'Africa', value: 5221 }, - { type: 'Rouge', country: 'EU', value: 3574 }, - { type: 'Rouge', country: 'China', value: 7004 }, - { type: 'Rouge', country: 'USA', value: 11624 }, - { type: 'Lipstick', country: 'Africa', value: 9256 }, - { type: 'Lipstick', country: 'EU', value: 4376 }, - { type: 'Lipstick', country: 'China', value: 9054 }, - { type: 'Lipstick', country: 'USA', value: 8814 }, - { type: 'Eyeshadows', country: 'Africa', value: 3308 }, - { type: 'Eyeshadows', country: 'EU', value: 4572 }, - { type: 'Eyeshadows', country: 'China', value: 12043 }, - { type: 'Eyeshadows', country: 'USA', value: 12998 } - ] + direction: 'vertical', + type: 'common', + color: ['#00295C', '#2568BD', '#9F9F9F', '#C5C5C5', '#00B0F0', '#4BCFFF', '#C2C2C2', '#D7D7D7'], + series: [ + { + type: 'bar', + stack: true, + direction: 'vertical', + bar: { + style: { + stroke: '', + lineWidth: 1 + }, + state: { + hover: { + stroke: '#000', + lineWidth: 1 + } + } + }, + barBackground: { + style: { + stroke: '', + lineWidth: 1 + } + }, + label: { + visible: true, + position: 'inside', + style: { + lineHeight: '100%', + fontSize: 16, + fontWeight: 'bold' + }, + overlap: { + strategy: [] + }, + smartInvert: true, + formatConfig: {}, + interactive: true + }, + xField: ['_editor_dimension_field', '_editor_type_field'], + yField: '_editor_value_field', + dataId: '0', + id: 'series-0', + EDITOR_SERIES_DATA_KEY: 'a', + seriesField: '_editor_type_field' + }, + { + type: 'bar', + stack: true, + direction: 'vertical', + bar: { + style: { + stroke: '', + lineWidth: 1 + }, + state: { + hover: { + stroke: '#000', + lineWidth: 1 + } + } + }, + barBackground: { + style: { + stroke: '', + lineWidth: 1 + } + }, + label: { + visible: true, + position: 'inside', + style: { + lineHeight: '100%', + fontSize: 16, + fontWeight: 'bold' + }, + overlap: { + strategy: [] + }, + smartInvert: true, + formatConfig: {}, + interactive: true + }, + xField: ['_editor_dimension_field', '_editor_type_field'], + yField: '_editor_value_field', + dataId: '1', + id: 'series-1', + EDITOR_SERIES_DATA_KEY: 'b', + seriesField: '_editor_type_field' + } + ], + legends: { + id: 'legend-discrete', + visible: false, + autoPage: false, + position: 'start', + interactive: false, + item: { + label: { + style: { + fill: '#1F2329', + fontSize: 16 + } + } + }, + _originalVisible: false + }, + region: [ + { + id: 'region-0' + } + ], + tooltip: { + visible: true, + mark: { + content: [{}], + title: {} + }, + dimension: { + content: [{}], + title: {} + } }, - xField: ['type', 'country'], - yField: 'value', - seriesField: 'country', - legends: [{ visible: true, position: 'middle', orient: 'bottom' }], axes: [ { orient: 'left', + id: 'axis-left', + type: 'linear', label: { - formatMethod(val) { - return `${(val * 100).toFixed(2)}%`; + autoLimit: false, + style: { + fill: '#1F2329', + fontSize: 16 + }, + formatConfig: {} + }, + domainLine: { + visible: true, + style: { + stroke: '#000000' + } + }, + tick: { + visible: true, + style: { + stroke: '#000000' + } + }, + grid: { + visible: false, + style: { + stroke: '#bbbfc4' + } + }, + autoIndent: false, + maxWidth: null, + maxHeight: null + }, + { + orient: 'bottom', + id: 'axis-bottom', + type: 'band', + label: { + autoLimit: false, + style: { + fill: '#1F2329', + fontSize: 16 + }, + formatConfig: {} + }, + domainLine: { + visible: true, + style: { + stroke: '#000000' + }, + onZero: true + }, + tick: { + visible: true, + style: { + stroke: '#000000' + } + }, + grid: { + visible: false, + style: { + stroke: '#bbbfc4' + } + }, + autoIndent: false, + maxWidth: null, + maxHeight: null, + trimPadding: false, + paddingInner: [0.18791312559017942, 0], + paddingOuter: [0.18791312559017942, 0] + } + ], + data: [ + { + id: '0', + sourceKey: 'a', + values: [ + { + _editor_dimension_field: 'x1', + _editor_value_field: 20, + _editor_type_field: 'a' + }, + { + _editor_dimension_field: 'x2', + _editor_value_field: 23, + _editor_type_field: 'a' + }, + { + _editor_dimension_field: 'x3', + _editor_value_field: 26, + _editor_type_field: 'a' + } + ], + specField: { + _editor_dimension_field: { + type: 'dimension', + order: 0 + }, + _editor_type_field: { + type: 'series', + order: 0 + }, + _editor_value_field: { + type: 'value', + order: 0 + } + } + }, + { + id: '1', + sourceKey: 'b', + values: [ + { + _editor_dimension_field: 'x1', + _editor_value_field: 20, + _editor_type_field: 'b' + }, + { + _editor_dimension_field: 'x2', + _editor_value_field: 24, + _editor_type_field: 'b' + }, + { + _editor_dimension_field: 'x3', + _editor_value_field: 29, + _editor_type_field: 'b' + } + ], + specField: { + _editor_dimension_field: { + type: 'dimension', + order: 0 + }, + _editor_type_field: { + type: 'series', + order: 0 + }, + _editor_value_field: { + type: 'value', + order: 0 } } } - ] + ], + labelLayout: 'region', + background: 'transparent' }; const storySpec: IStorySpec = { @@ -673,7 +906,7 @@ const storySpec: IStorySpec = { height: 400 }, options: { - spec: spec, + spec: spec1, initOption: { animation: false, interactive: true, diff --git a/packages/vstory/src/edit/edit-component/base-selection.ts b/packages/vstory/src/edit/edit-component/base-selection.ts index f72b472f..294c2ee7 100644 --- a/packages/vstory/src/edit/edit-component/base-selection.ts +++ b/packages/vstory/src/edit/edit-component/base-selection.ts @@ -26,7 +26,7 @@ export abstract class BaseSelection implements IEditComponent { declare type: string; protected _initOverGraphic() { - this._overGraphic = createGroup({ pickable: false }); + this._overGraphic = createGroup({ pickable: false, visible: false }); } endEdit(emitEvent: boolean = true): void { diff --git a/packages/vstory/src/edit/edit-component/edit-control/series-mark-control/bar.ts b/packages/vstory/src/edit/edit-component/edit-control/series-mark-control/bar.ts index 90de07d0..fcf8e819 100644 --- a/packages/vstory/src/edit/edit-component/edit-control/series-mark-control/bar.ts +++ b/packages/vstory/src/edit/edit-component/edit-control/series-mark-control/bar.ts @@ -1,21 +1,15 @@ -import type { CharacterChart } from './../../../../story/character/chart/character'; import { Bounds, type IPointLike } from '@visactor/vutils'; import type { IGroup, IGroupGraphicAttribute, IRect, IRectGraphicAttribute } from '@visactor/vrender-core'; import { createGroup, createRect } from '@visactor/vrender-core'; -import { MaxAxisPaddingOuter, PickGraphicAttribute } from '../../../const'; +import { EditEditingState, MaxAxisPaddingOuter, PickGraphicAttribute } from '../../../const'; import type { Edit } from '../../../edit'; import type { IEditSelectionInfo } from '../../../interface'; import { BaseMarkControl } from './base'; import { SHAPE_HOVER_COLOR } from '../constants'; import type { ICartesianSeries } from '@visactor/vchart'; -import { getVChartFromCharacter } from '../../../utils/chart'; +import { getChartRenderMatrix, getVChartFromCharacter } from '../../../utils/chart'; import type { BandScale } from '@visactor/vscale'; -import { - getChartToGlobalMatrix, - transformBoundsWithMatrix, - transformPointToEditGroup, - transformPointWithMatrix -} from '../../../utils/space'; +import { transformPointWithMatrix } from '../../../utils/space'; import type { StoryEvent } from '../../../../story/interface'; import { computeScalePadding } from '../../../utils/scale'; @@ -36,12 +30,12 @@ const defaultEditGroupAttribute: IGroupGraphicAttribute = { pickable: true, visible: true, zIndex: 10, + boundsPadding: 4, x: 0, y: 0, height: 100 }; -// Todo 修改柱宽度,柱高度 export class BarMarkControl extends BaseMarkControl { private _startGroup: IGroup; private _endGroup: IGroup; @@ -109,21 +103,24 @@ export class BarMarkControl extends BaseMarkControl { }); h.addEventListener('pointerover', (e: StoryEvent) => { - const borderIsVisible = this._barBorder.attribute.visible; this._showHandleGraphic(); - this._barBorder.setAttributes({ visible: borderIsVisible }); }); h.addEventListener('pointerout', (e: StoryEvent) => { if (this._editState === 'dragging') { return; } this._hideHandleGraphic(); + this._hideBorderGraphic(); }); }); } startWithActionInfo(actionInfo: IEditSelectionInfo) { super.startWithActionInfo(actionInfo); + // 设置绘图变换矩阵 + const matrix = getChartRenderMatrix(actionInfo.character.graphic.graphic); + this._graphicGroup.setAttributes({ postMatrix: matrix }); + this._setCurrentEditData(actionInfo); this._setEditGraphic(); } @@ -134,18 +131,19 @@ export class BarMarkControl extends BaseMarkControl { this._graphicGroup.setAttribute('visible', true); this._graphicGroup.showAll(); + this._hideBorderGraphic(); } private _setBorderAttribute() { const currentEditorElements = this._getAllElementInDimension(); if (currentEditorElements.length) { - const matrix = getChartToGlobalMatrix(this._actionInfo.character as CharacterChart, this.edit); + // const matrix = getChartToGlobalMatrix(this._actionInfo.character as CharacterChart, this.edit); // 重新设置border属性 - let bounds = new Bounds(); + const bounds = new Bounds(); currentEditorElements.forEach(e => { bounds.union(e.graphicItem.globalAABBBounds); }); - bounds = transformBoundsWithMatrix(matrix, bounds) as unknown as Bounds; + // bounds = transformBoundsWithMatrix(matrix, bounds) as unknown as Bounds; this._barBorder.setAttributes({ x: bounds.x1, x1: bounds.x2, @@ -222,10 +220,13 @@ export class BarMarkControl extends BaseMarkControl { onMarkPointOver(actionInfo: IEditSelectionInfo) { super.onMarkPointOver(actionInfo); this._setCurrentEditData(actionInfo); + this._setEditGraphic(); } onMarkPointOut(actionInfo: IEditSelectionInfo) { super.onMarkPointOut(actionInfo); + this._hideBorderGraphic(); + this._hideHandleGraphic(); } private _setCurrentEditData(actionInfo: IEditSelectionInfo) { @@ -235,19 +236,23 @@ export class BarMarkControl extends BaseMarkControl { } private _showHandleGraphic() { - // TODO: 显示手柄 + this._startHandle.setAttributes({ visible: true }); + this._endHandle.setAttributes({ visible: true }); } private _hideHandleGraphic() { - // TODO: 隐藏手柄 - } - - private _showBorderGraphic() { - // TODO: 显示边框 + if (this._editState === 'dragging') { + return; + } + this._startHandle.setAttributes({ visible: false }); + this._endHandle.setAttributes({ visible: false }); } private _hideBorderGraphic() { - // TODO: 隐藏边框 + if (this._editState === 'dragging') { + return; + } + this._barBorder.setAttributes({ visible: false }); } private _onResizeStart(h: IGroup, e: StoryEvent) { @@ -292,10 +297,11 @@ export class BarMarkControl extends BaseMarkControl { } this._barBorder.setAttributes({ visible: true }); this._editState = 'dragging'; + this.edit.setEditGlobalState(EditEditingState.continuingEditing, true); // drag 使用的临时数据 // @ts-ignore this._dragInfo.handle = h === this._startGroup ? 'start' : 'end'; - const layerPos = transformPointToEditGroup(this.edit, e.canvas); + const layerPos = transformPointWithMatrix(this._graphicGroup.globalTransMatrix, e.canvas); this._dragInfo.startPos.x = layerPos.x; this._dragInfo.startPos.y = layerPos.y; this._dragInfo.series = series; @@ -316,7 +322,7 @@ export class BarMarkControl extends BaseMarkControl { } private _handleMove = (e: StoryEvent) => { - const layerPos = transformPointToEditGroup(this.edit, e.canvas); + const layerPos = transformPointWithMatrix(this._graphicGroup.globalTransMatrix, e.canvas); const dx = layerPos.x - this._dragInfo.startPos.x; const dy = layerPos.y - this._dragInfo.startPos.y; @@ -370,10 +376,10 @@ export class BarMarkControl extends BaseMarkControl { } else { start = currentValue - this._dragInfo.tempScale[0].bandwidth(); } - const matrix = getChartToGlobalMatrix(this._actionInfo.character as CharacterChart, this.edit); + // const matrix = getChartToGlobalMatrix(this._actionInfo.character as CharacterChart, this.edit); if (this._dragInfo.series.direction === 'vertical') { - start = transformPointWithMatrix(matrix, { x: start, y: 0 }).x; - end = transformPointWithMatrix(matrix, { x: end, y: 0 }).x; + // start = transformPointWithMatrix(matrix, { x: start, y: 0 }).x; + // end = transformPointWithMatrix(matrix, { x: end, y: 0 }).x; // console.log(`start = `, start - handlerSize * 0.5, 'end = ', end - handlerSize * 0.5); this._startGroup.setAttributes({ x: start - handlerSize * 0.5 @@ -386,8 +392,8 @@ export class BarMarkControl extends BaseMarkControl { x1: end }); } else { - start = transformPointWithMatrix(matrix, { x: 0, y: start }).y; - end = transformPointWithMatrix(matrix, { x: 0, y: end }).y; + // start = transformPointWithMatrix(matrix, { x: 0, y: start }).y; + // end = transformPointWithMatrix(matrix, { x: 0, y: end }).y; this._startGroup.setAttributes({ y: start - handlerSize * 0.5 }); @@ -434,9 +440,12 @@ export class BarMarkControl extends BaseMarkControl { private _handleUp = (e: StoryEvent) => { this._barBorder.setAttributes({ visible: false }); this._editState = 'none'; + this.edit.setEditGlobalState(EditEditingState.continuingEditing, false); this.edit.getStage().removeEventListener('pointermove', this._handleMove as any); window.removeEventListener('pointerup', this._handleUp, true); if (this._dragInfo.hasChange) { + // TODO 设置对应的轴 padding + // 这里的 setConfig 方法需要是增量设置 this._actionInfo.character.setConfig({ option: { axes: [ @@ -451,23 +460,13 @@ export class BarMarkControl extends BaseMarkControl { ] } }); + // 更新属性 - // this._dragInfo.series = null; - // this._dragInfo.axis = null; - // this._dragInfo.rawScale = []; - // this.chart.reRenderWithUpdateSpec(); - // // upgrade 更新当前的一些图表数据 - // this._upgradeVChartLink(); - // // 柱宽编辑事件 - // CONTEXT.TeaEvent('edit_element', { - // element_type: 'chart', - // part: 'series', - // chart_type: this._chart.vchartType, - // data_source_type: this._chart.dataSourceType, - // action_type: 'update', - // edit_property: 'barWidth', - // trigger_by: 'chart_interaction' - // }); + this._dragInfo.series = null; + this._dragInfo.axis = null; + this._dragInfo.rawScale = []; + this._dragInfo.tempScale = []; + this._dragInfo.hasChange = false; } }; diff --git a/packages/vstory/src/edit/edit-component/edit-control/series-mark-control/base.ts b/packages/vstory/src/edit/edit-component/edit-control/series-mark-control/base.ts index cefde615..ae5cdea0 100644 --- a/packages/vstory/src/edit/edit-component/edit-control/series-mark-control/base.ts +++ b/packages/vstory/src/edit/edit-component/edit-control/series-mark-control/base.ts @@ -12,7 +12,7 @@ export class BaseMarkControl { protected _graphicGroup: IGroup; constructor(public readonly edit: Edit) { - this._graphicGroup = createGroup({ visible: false }); + this._graphicGroup = createGroup({ visible: false, zIndex: 10 }); this.edit.getEditGroup().add(this._graphicGroup); } diff --git a/packages/vstory/src/edit/edit-component/series-mark/series-mark-selection.ts b/packages/vstory/src/edit/edit-component/series-mark/series-mark-selection.ts index d56db7bf..dd5a8cf3 100644 --- a/packages/vstory/src/edit/edit-component/series-mark/series-mark-selection.ts +++ b/packages/vstory/src/edit/edit-component/series-mark/series-mark-selection.ts @@ -1,6 +1,5 @@ import { EditEditingState, SeriesMarkMode } from './../../const'; import { Logger } from './../../../util/logger'; -import type { CharacterChart } from './../../../story/character/chart/character'; import { SeriesMarkControl } from './../edit-control/series-mark-control/index'; import type { BaseMarkControl } from './../edit-control/series-mark-control/base'; import type { IEditOverActionInfo } from './../../interface'; @@ -10,11 +9,15 @@ import type { IEditSelectionInfo } from '../../interface'; import { EditActionEnum, type IEditActionInfo, type IEditComponent } from '../../interface'; import { BaseSelection } from './../base-selection'; -import { getChartToGlobalMatrix } from '../../utils/space'; import { cloneEditGraphic } from '../../utils/graphic'; import { SHAPE_OVER_COLOR, SHAPE_SELECT_COLOR } from '../../const'; import type { Edit } from '../../edit'; -import { getKeyValueMapWithScaleMap, getSeriesKeyField, getSeriesKeyScalesMap } from '../../utils/chart'; +import { + getChartRenderMatrix, + getKeyValueMapWithScaleMap, + getSeriesKeyField, + getSeriesKeyScalesMap +} from '../../utils/chart'; export class SeriesMarkSelection extends BaseSelection implements IEditComponent { readonly level = 4; @@ -111,6 +114,11 @@ export class SeriesMarkSelection extends BaseSelection implements IEditComponent startEdit(actionInfo: IEditSelectionInfo) { Logger.debug('series mark startEdit'); super.startEdit(actionInfo, false); + // 设置绘图变换矩阵 + const matrix = getChartRenderMatrix(this._actionInfo.character.graphic.graphic); + this._selectGraphic.setAttributes({ postMatrix: matrix }); + this._overGraphic.setAttributes({ postMatrix: matrix }); + const seriesMarkInfo: { selectMode: string; markName?: string; @@ -220,6 +228,9 @@ export class SeriesMarkSelection extends BaseSelection implements IEditComponent checkOver?(action: IEditActionInfo): void { // action if (action.type === EditActionEnum.pointerOverCharacter && action.detail?.part === 'seriesMark') { + // 设置绘图变换矩阵 + const matrix = getChartRenderMatrix(action.character.graphic.graphic); + this._overGraphic.setAttributes({ postMatrix: matrix }); // show over graphic this._showOverGraphic(action as IEditOverActionInfo); } @@ -285,9 +296,9 @@ export class SeriesMarkSelection extends BaseSelection implements IEditComponent protected _addPickGraphic(action: IEditOverActionInfo, parent: IGroup, attr?: any) { const itemList = this._getChartItemInSeriesMark(action); - const matrix = getChartToGlobalMatrix(action.character as CharacterChart, this.edit); + // const matrix = getChartToGlobalMatrix(action.character as CharacterChart, this.edit); itemList.forEach((item: IGraphic) => { - const graphic = cloneEditGraphic(item, matrix, { ...(attr ?? {}) }); + const graphic = cloneEditGraphic(item, null, { ...(attr ?? {}) }); parent.add(graphic); }); } diff --git a/packages/vstory/src/edit/edit.ts b/packages/vstory/src/edit/edit.ts index ca8f0f2e..68de4175 100644 --- a/packages/vstory/src/edit/edit.ts +++ b/packages/vstory/src/edit/edit.ts @@ -70,7 +70,7 @@ export class Edit { editLayer.clipInViewBox = false; editLayer.add(this._editGroup); - this._overGraphicGroup = createGroup({}); + this._overGraphicGroup = createGroup({ pickable: false }); this._overGraphicGroup.name = 'over_group'; editLayer.add(this._overGraphicGroup); } diff --git a/packages/vstory/src/edit/utils/chart.ts b/packages/vstory/src/edit/utils/chart.ts index f13b3503..47156609 100644 --- a/packages/vstory/src/edit/utils/chart.ts +++ b/packages/vstory/src/edit/utils/chart.ts @@ -1,8 +1,10 @@ import type { ICartesianSeries, ISeries, IVChart } from '@visactor/vchart'; import { isContinuous } from '@visactor/vscale'; +import type { Matrix } from '@visactor/vutils'; import { isArray } from '@visactor/vutils'; import { VCHART_DATA_INDEX } from '../const'; import type { ICharacter } from '../../story/character'; +import type { VChartGraphic } from '../../story/character/chart/graphic/vrender/vchart-graphic'; // 特殊系列,会在获取系列数据的唯一key时,增加index const SpecialSeriesMap: { [key: string]: boolean } = { @@ -77,3 +79,10 @@ export function getKeyValueMapWithScaleMap(keys: string[], scaleMap: { [key: str export function getVChartFromCharacter(character: ICharacter): IVChart { return character.graphic.graphic.vchart; } + +export function getChartRenderMatrix(chart: VChartGraphic): Matrix { + const matrix = chart.globalTransMatrix.clone(); + const stageMatrix = chart.stage.window.getViewBoxTransform().clone(); + stageMatrix.multiply(matrix.a, matrix.b, matrix.c, matrix.d, matrix.e, matrix.f); + return stageMatrix; +} diff --git a/packages/vstory/src/edit/utils/graphic.ts b/packages/vstory/src/edit/utils/graphic.ts index 90a4266b..20c92e9d 100644 --- a/packages/vstory/src/edit/utils/graphic.ts +++ b/packages/vstory/src/edit/utils/graphic.ts @@ -12,7 +12,7 @@ export function cloneEditGraphic(graphic: IGraphic, matrix: Matrix, attribute?: cornerRadius: 0, ...attribute }); - transformGraphicWithMatrix(cloneItem, matrix); + matrix && transformGraphicWithMatrix(cloneItem, matrix); if (cloneItem.type === 'text') { return createRect({ ...PickGraphicAttribute,