/*
|
* Licensed to the Apache Software Foundation (ASF) under one
|
* or more contributor license agreements. See the NOTICE file
|
* distributed with this work for additional information
|
* regarding copyright ownership. The ASF licenses this file
|
* to you under the Apache License, Version 2.0 (the
|
* "License"); you may not use this file except in compliance
|
* with the License. You may obtain a copy of the License at
|
*
|
* http://www.apache.org/licenses/LICENSE-2.0
|
*
|
* Unless required by applicable law or agreed to in writing,
|
* software distributed under the License is distributed on an
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
* KIND, either express or implied. See the License for the
|
* specific language governing permissions and limitations
|
* under the License.
|
*/
|
|
import * as echarts from '../../../core/echarts';
|
import * as zrUtil from 'zrender/src/core/util';
|
import {ToolboxFeature, ToolboxFeatureOption, ToolboxFeatureModel} from '../featureManager';
|
import { SeriesOption, ECUnitOption } from '../../../util/types';
|
import GlobalModel from '../../../model/Global';
|
import ExtensionAPI from '../../../core/ExtensionAPI';
|
import SeriesModel from '../../../model/Series';
|
import { SINGLE_REFERRING } from '../../../util/model';
|
|
const INNER_STACK_KEYWORD = '__ec_magicType_stack__' as const;
|
|
const ICON_TYPES = ['line', 'bar', 'stack'] as const;
|
// stack and tiled appears in pair for the title
|
const TITLE_TYPES = ['line', 'bar', 'stack', 'tiled'] as const;
|
|
const radioTypes = [
|
['line', 'bar'],
|
['stack']
|
] as const;
|
|
type IconType = typeof ICON_TYPES[number];
|
type TitleType = typeof TITLE_TYPES[number];
|
|
export interface ToolboxMagicTypeFeatureOption extends ToolboxFeatureOption {
|
type?: IconType[]
|
/**
|
* Icon group
|
*/
|
icon?: {[key in IconType]?: string}
|
title?: {[key in TitleType]?: string}
|
|
// TODO LineSeriesOption, BarSeriesOption
|
option?: {[key in IconType]?: SeriesOption}
|
|
/**
|
* Map of seriesType: seriesIndex
|
*/
|
seriesIndex?: {
|
line?: number
|
bar?: number
|
}
|
}
|
|
|
class MagicType extends ToolboxFeature<ToolboxMagicTypeFeatureOption> {
|
|
getIcons() {
|
const model = this.model;
|
const availableIcons = model.get('icon');
|
const icons: ToolboxMagicTypeFeatureOption['icon'] = {};
|
zrUtil.each(model.get('type'), function (type) {
|
if (availableIcons[type]) {
|
icons[type] = availableIcons[type];
|
}
|
});
|
return icons;
|
}
|
|
static getDefaultOption(ecModel: GlobalModel) {
|
const defaultOption: ToolboxMagicTypeFeatureOption = {
|
show: true,
|
type: [],
|
// Icon group
|
icon: {
|
line: 'M4.1,28.9h7.1l9.3-22l7.4,38l9.7-19.7l3,12.8h14.9M4.1,58h51.4',
|
bar: 'M6.7,22.9h10V48h-10V22.9zM24.9,13h10v35h-10V13zM43.2,2h10v46h-10V2zM3.1,58h53.7',
|
// eslint-disable-next-line
|
stack: 'M8.2,38.4l-8.4,4.1l30.6,15.3L60,42.5l-8.1-4.1l-21.5,11L8.2,38.4z M51.9,30l-8.1,4.2l-13.4,6.9l-13.9-6.9L8.2,30l-8.4,4.2l8.4,4.2l22.2,11l21.5-11l8.1-4.2L51.9,30z M51.9,21.7l-8.1,4.2L35.7,30l-5.3,2.8L24.9,30l-8.4-4.1l-8.3-4.2l-8.4,4.2L8.2,30l8.3,4.2l13.9,6.9l13.4-6.9l8.1-4.2l8.1-4.1L51.9,21.7zM30.4,2.2L-0.2,17.5l8.4,4.1l8.3,4.2l8.4,4.2l5.5,2.7l5.3-2.7l8.1-4.2l8.1-4.2l8.1-4.1L30.4,2.2z' // jshint ignore:line
|
},
|
// `line`, `bar`, `stack`, `tiled`
|
title: ecModel.getLocale(['toolbox', 'magicType', 'title']),
|
option: {},
|
seriesIndex: {}
|
};
|
|
return defaultOption;
|
}
|
|
onclick(ecModel: GlobalModel, api: ExtensionAPI, type: IconType) {
|
const model = this.model;
|
const seriesIndex = model.get(['seriesIndex', type as 'line' | 'bar']);
|
// Not supported magicType
|
if (!seriesOptGenreator[type]) {
|
return;
|
}
|
const newOption: ECUnitOption = {
|
series: []
|
};
|
const generateNewSeriesTypes = function (seriesModel: SeriesModel<MegicTypeSeriesOption>) {
|
const seriesType = seriesModel.subType;
|
const seriesId = seriesModel.id;
|
const newSeriesOpt = seriesOptGenreator[type](
|
seriesType, seriesId, seriesModel, model
|
);
|
if (newSeriesOpt) {
|
// PENDING If merge original option?
|
zrUtil.defaults(newSeriesOpt, seriesModel.option);
|
(newOption.series as SeriesOption[]).push(newSeriesOpt);
|
}
|
// Modify boundaryGap
|
const coordSys = seriesModel.coordinateSystem;
|
if (coordSys && coordSys.type === 'cartesian2d' && (type === 'line' || type === 'bar')) {
|
const categoryAxis = coordSys.getAxesByScale('ordinal')[0];
|
if (categoryAxis) {
|
const axisDim = categoryAxis.dim;
|
const axisType = axisDim + 'Axis';
|
const axisModel = seriesModel.getReferringComponents(axisType, SINGLE_REFERRING).models[0];
|
const axisIndex = axisModel.componentIndex;
|
|
newOption[axisType] = newOption[axisType] || [];
|
for (let i = 0; i <= axisIndex; i++) {
|
(newOption[axisType] as any)[axisIndex] = (newOption[axisType] as any)[axisIndex] || {};
|
}
|
(newOption[axisType] as any)[axisIndex].boundaryGap = type === 'bar';
|
}
|
}
|
};
|
|
zrUtil.each(radioTypes, function (radio) {
|
if (zrUtil.indexOf(radio, type) >= 0) {
|
zrUtil.each(radio, function (item) {
|
model.setIconStatus(item, 'normal');
|
});
|
}
|
});
|
|
model.setIconStatus(type, 'emphasis');
|
|
ecModel.eachComponent(
|
{
|
mainType: 'series',
|
query: seriesIndex == null ? null : {
|
seriesIndex: seriesIndex
|
}
|
}, generateNewSeriesTypes
|
);
|
|
let newTitle;
|
// Change title of stack
|
if (type === 'stack') {
|
// use titles in model instead of ecModel
|
// as stack and tiled appears in pair, just flip them
|
// no need of checking stack state
|
newTitle = zrUtil.merge({
|
stack: model.option.title.tiled,
|
tiled: model.option.title.stack
|
}, model.option.title)
|
}
|
|
api.dispatchAction({
|
type: 'changeMagicType',
|
currentType: type,
|
newOption: newOption,
|
newTitle: newTitle,
|
featureName: 'magicType'
|
});
|
}
|
}
|
|
type MegicTypeSeriesOption = SeriesOption & {
|
// TODO: TYPE More specified series option
|
stack?: boolean | string
|
data?: unknown[]
|
markPoint?: unknown
|
markLine?: unknown
|
};
|
|
type SeriesOptGenreator = (
|
seriesType: string,
|
seriesId: string,
|
seriesModel: SeriesModel<MegicTypeSeriesOption>,
|
model: ToolboxFeatureModel<ToolboxMagicTypeFeatureOption>
|
) => SeriesOption;
|
|
const seriesOptGenreator: Record<IconType, SeriesOptGenreator> = {
|
'line': function (seriesType, seriesId, seriesModel, model) {
|
if (seriesType === 'bar') {
|
return zrUtil.merge({
|
id: seriesId,
|
type: 'line',
|
// Preserve data related option
|
data: seriesModel.get('data'),
|
stack: seriesModel.get('stack'),
|
markPoint: seriesModel.get('markPoint'),
|
markLine: seriesModel.get('markLine')
|
}, model.get(['option', 'line']) || {}, true);
|
}
|
},
|
'bar': function (seriesType, seriesId, seriesModel, model) {
|
if (seriesType === 'line') {
|
return zrUtil.merge({
|
id: seriesId,
|
type: 'bar',
|
// Preserve data related option
|
data: seriesModel.get('data'),
|
stack: seriesModel.get('stack'),
|
markPoint: seriesModel.get('markPoint'),
|
markLine: seriesModel.get('markLine')
|
}, model.get(['option', 'bar']) || {}, true);
|
}
|
},
|
'stack': function (seriesType, seriesId, seriesModel, model) {
|
const isStack = seriesModel.get('stack') === INNER_STACK_KEYWORD;
|
if (seriesType === 'line' || seriesType === 'bar') {
|
model.setIconStatus('stack', isStack ? 'normal' : 'emphasis');
|
return zrUtil.merge({
|
id: seriesId,
|
stack: isStack ? '' : INNER_STACK_KEYWORD
|
}, model.get(['option', 'stack']) || {}, true);
|
}
|
}
|
};
|
|
|
// TODO: SELF REGISTERED.
|
echarts.registerAction({
|
type: 'changeMagicType',
|
event: 'magicTypeChanged',
|
update: 'prepareAndUpdate'
|
}, function (payload, ecModel) {
|
ecModel.mergeOption(payload.newOption);
|
});
|
|
export default MagicType;
|