|  | /* | 
|  | * 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 SeriesData from '../../data/SeriesData'; | 
|  | 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: SeriesData; | 
|  |  | 
|  | /** | 
|  | * @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(): SeriesData<this> { | 
|  | return this._data as SeriesData<this>; | 
|  | } | 
|  |  | 
|  | setData(data: SeriesData) { | 
|  | 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; |