/*
|
* 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 zrUtil from 'zrender/src/core/util';
|
import env from 'zrender/src/core/env';
|
import { DataFormatMixin } from '../../model/mixin/dataFormat';
|
import ComponentModel from '../../model/Component';
|
import SeriesModel from '../../model/Series';
|
import {
|
DisplayStateHostOption,
|
ComponentOption,
|
AnimationOptionMixin,
|
Dictionary,
|
CommonTooltipOption,
|
ScaleDataValue
|
} from '../../util/types';
|
import Model from '../../model/Model';
|
import GlobalModel from '../../model/Global';
|
import List from '../../data/List';
|
import { makeInner, defaultEmphasis } from '../../util/model';
|
import { createTooltipMarkup } from '../tooltip/tooltipMarkup';
|
|
function fillLabel(opt: DisplayStateHostOption) {
|
defaultEmphasis(opt, 'label', ['show']);
|
}
|
|
export type MarkerStatisticType = 'average' | 'min' | 'max' | 'median';
|
|
/**
|
* Option to specify where to put the marker.
|
*/
|
export interface MarkerPositionOption {
|
// Priority: x/y > coord(xAxis, yAxis) > type
|
|
// Absolute position, px or percent string
|
x?: number | string
|
y?: number | string
|
|
/**
|
* Coord on any coordinate system
|
*/
|
coord?: (ScaleDataValue | MarkerStatisticType)[]
|
|
// On cartesian coordinate system
|
xAxis?: ScaleDataValue
|
yAxis?: ScaleDataValue
|
|
// On polar coordinate system
|
radiusAxis?: ScaleDataValue
|
angleAxis?: ScaleDataValue
|
|
// Use statistic method
|
type?: MarkerStatisticType
|
/**
|
* When using statistic method with type.
|
* valueIndex and valueDim can be specify which dim the statistic is used on.
|
*/
|
valueIndex?: number
|
valueDim?: string
|
|
|
/**
|
* Value to be displayed as label. Totally optional
|
*/
|
value?: string | number
|
}
|
|
export interface MarkerOption extends ComponentOption, AnimationOptionMixin {
|
|
silent?: boolean
|
|
data?: unknown[]
|
|
tooltip?: CommonTooltipOption<unknown> & {
|
trigger?: 'item' | 'axis' | boolean | 'none'
|
}
|
}
|
|
// { [componentType]: MarkerModel }
|
const inner = makeInner<Dictionary<MarkerModel>, SeriesModel>();
|
|
abstract class MarkerModel<Opts extends MarkerOption = MarkerOption> extends ComponentModel<Opts> {
|
|
static type = 'marker';
|
type = MarkerModel.type;
|
|
/**
|
* If marker model is created by self from series
|
*/
|
createdBySelf = false;
|
|
static readonly dependencies = ['series', 'grid', 'polar', 'geo'];
|
|
__hostSeries: SeriesModel;
|
|
private _data: List;
|
|
/**
|
* @overrite
|
*/
|
init(option: Opts, parentModel: Model, ecModel: GlobalModel) {
|
|
if (__DEV__) {
|
if (this.type === 'marker') {
|
throw new Error('Marker component is abstract component. Use markLine, markPoint, markArea instead.');
|
}
|
}
|
this.mergeDefaultAndTheme(option, ecModel);
|
this._mergeOption(option, ecModel, false, true);
|
}
|
|
isAnimationEnabled(): boolean {
|
if (env.node) {
|
return false;
|
}
|
|
const hostSeries = this.__hostSeries;
|
return this.getShallow('animation') && hostSeries && hostSeries.isAnimationEnabled();
|
}
|
|
/**
|
* @overrite
|
*/
|
mergeOption(newOpt: Opts, ecModel: GlobalModel) {
|
this._mergeOption(newOpt, ecModel, false, false);
|
}
|
|
_mergeOption(newOpt: Opts, ecModel: GlobalModel, createdBySelf?: boolean, isInit?: boolean) {
|
const componentType = this.mainType;
|
if (!createdBySelf) {
|
ecModel.eachSeries(function (seriesModel) {
|
|
// mainType can be markPoint, markLine, markArea
|
const markerOpt = seriesModel.get(
|
this.mainType as any, true
|
) as Opts;
|
|
let markerModel = inner(seriesModel)[componentType];
|
if (!markerOpt || !markerOpt.data) {
|
inner(seriesModel)[componentType] = null;
|
return;
|
}
|
if (!markerModel) {
|
if (isInit) {
|
// Default label emphasis `position` and `show`
|
fillLabel(markerOpt);
|
}
|
zrUtil.each(markerOpt.data, function (item) {
|
// FIXME Overwrite fillLabel method ?
|
if (item instanceof Array) {
|
fillLabel(item[0]);
|
fillLabel(item[1]);
|
}
|
else {
|
fillLabel(item);
|
}
|
});
|
|
markerModel = this.createMarkerModelFromSeries(
|
markerOpt, this, ecModel
|
);
|
// markerModel = new ImplementedMarkerModel(
|
// markerOpt, this, ecModel
|
// );
|
|
zrUtil.extend(markerModel, {
|
mainType: this.mainType,
|
// Use the same series index and name
|
seriesIndex: seriesModel.seriesIndex,
|
name: seriesModel.name,
|
createdBySelf: true
|
});
|
|
markerModel.__hostSeries = seriesModel;
|
}
|
else {
|
markerModel._mergeOption(markerOpt, ecModel, true);
|
}
|
inner(seriesModel)[componentType] = markerModel;
|
}, this);
|
}
|
}
|
|
formatTooltip(
|
dataIndex: number,
|
multipleSeries: boolean,
|
dataType: string
|
) {
|
const data = this.getData();
|
const value = this.getRawValue(dataIndex);
|
const itemName = data.getName(dataIndex);
|
|
return createTooltipMarkup('section', {
|
header: this.name,
|
blocks: [createTooltipMarkup('nameValue', {
|
name: itemName,
|
value: value,
|
noName: !itemName,
|
noValue: value == null
|
})]
|
});
|
}
|
|
getData(): List<this> {
|
return this._data as List<this>;
|
}
|
|
setData(data: List) {
|
this._data = data;
|
}
|
|
/**
|
* Create slave marker model from series.
|
*/
|
abstract createMarkerModelFromSeries(
|
markerOpt: Opts,
|
masterMarkerModel: MarkerModel,
|
ecModel: GlobalModel
|
): MarkerModel;
|
|
static getMarkerModelFromSeries(
|
seriesModel: SeriesModel,
|
// Support three types of markers. Strict check.
|
componentType: 'markLine' | 'markPoint' | 'markArea'
|
) {
|
return inner(seriesModel)[componentType];
|
}
|
}
|
|
interface MarkerModel<Opts extends MarkerOption = MarkerOption> extends DataFormatMixin {}
|
zrUtil.mixin(MarkerModel, DataFormatMixin.prototype);
|
|
export default MarkerModel;
|