echarts modelHelper 源码
echarts modelHelper 代码
文件路径:/src/component/axisPointer/modelHelper.ts
/*
* 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 Model from '../../model/Model';
import GlobalModel from '../../model/Global';
import ExtensionAPI from '../../core/ExtensionAPI';
import { each, curry, clone, defaults, isArray, indexOf } from 'zrender/src/core/util';
import AxisPointerModel, { AxisPointerOption } from './AxisPointerModel';
import Axis from '../../coord/Axis';
import { TooltipOption } from '../tooltip/TooltipModel';
import SeriesModel from '../../model/Series';
import {
SeriesOption,
SeriesTooltipOption,
CommonAxisPointerOption,
Dictionary,
ComponentOption
} from '../../util/types';
import { AxisBaseModel } from '../../coord/AxisBaseModel';
import ComponentModel from '../../model/Component';
import { CoordinateSystemMaster } from '../../coord/CoordinateSystem';
interface LinkGroup {
mapper: AxisPointerOption['link'][number]['mapper']
/**
* { [axisKey]: AxisInfo }
*/
axesInfo: Dictionary<AxisInfo>
}
interface AxisInfo {
axis: Axis
key: string
coordSys: CoordinateSystemMaster
axisPointerModel: Model<CommonAxisPointerOption>
triggerTooltip: boolean
involveSeries: boolean
snap: boolean
useHandle: boolean
seriesModels: SeriesModel[]
linkGroup?: LinkGroup
seriesDataCount?: number
}
interface CollectionResult {
/**
* { [coordSysKey]: { [axisKey]: AxisInfo } }
*/
coordSysAxesInfo: Dictionary<Dictionary<AxisInfo>>
/**
* { [axisKey]: AxisInfo }
*/
axesInfo: Dictionary<AxisInfo>
/**
* { [coordSysKey]: { CoordinateSystemMaster } }
*/
coordSysMap: Dictionary<CoordinateSystemMaster>
seriesInvolved: boolean
}
// Build axisPointerModel, mergin tooltip.axisPointer model for each axis.
// allAxesInfo should be updated when setOption performed.
export function collect(ecModel: GlobalModel, api: ExtensionAPI) {
const result: CollectionResult = {
/**
* key: makeKey(axis.model)
* value: {
* axis,
* coordSys,
* axisPointerModel,
* triggerTooltip,
* involveSeries,
* snap,
* seriesModels,
* seriesDataCount
* }
*/
axesInfo: {},
seriesInvolved: false,
/**
* key: makeKey(coordSys.model)
* value: Object: key makeKey(axis.model), value: axisInfo
*/
coordSysAxesInfo: {},
coordSysMap: {}
};
collectAxesInfo(result, ecModel, api);
// Check seriesInvolved for performance, in case too many series in some chart.
result.seriesInvolved && collectSeriesInfo(result, ecModel);
return result;
}
function collectAxesInfo(result: CollectionResult, ecModel: GlobalModel, api: ExtensionAPI) {
const globalTooltipModel = ecModel.getComponent('tooltip');
const globalAxisPointerModel = ecModel.getComponent('axisPointer') as AxisPointerModel;
// links can only be set on global.
const linksOption = globalAxisPointerModel.get('link', true) || [];
const linkGroups: LinkGroup[] = [];
// Collect axes info.
each(api.getCoordinateSystems(), function (coordSys) {
// Some coordinate system do not support axes, like geo.
if (!coordSys.axisPointerEnabled) {
return;
}
const coordSysKey = makeKey(coordSys.model);
const axesInfoInCoordSys: CollectionResult['coordSysAxesInfo'][string] =
result.coordSysAxesInfo[coordSysKey] = {};
result.coordSysMap[coordSysKey] = coordSys;
// Set tooltip (like 'cross') is a convienent way to show axisPointer
// for user. So we enable seting tooltip on coordSys model.
const coordSysModel = coordSys.model as ComponentModel<ComponentOption & {
tooltip: TooltipOption // TODO: Same with top level tooltip?
}>;
const baseTooltipModel = coordSysModel.getModel('tooltip', globalTooltipModel);
each(coordSys.getAxes(), curry(saveTooltipAxisInfo, false, null));
// If axis tooltip used, choose tooltip axis for each coordSys.
// Notice this case: coordSys is `grid` but not `cartesian2D` here.
if (coordSys.getTooltipAxes
&& globalTooltipModel
// If tooltip.showContent is set as false, tooltip will not
// show but axisPointer will show as normal.
&& baseTooltipModel.get('show')
) {
// Compatible with previous logic. But series.tooltip.trigger: 'axis'
// or series.data[n].tooltip.trigger: 'axis' are not support any more.
const triggerAxis = baseTooltipModel.get('trigger') === 'axis';
const cross = baseTooltipModel.get(['axisPointer', 'type']) === 'cross';
const tooltipAxes = coordSys.getTooltipAxes(baseTooltipModel.get(['axisPointer', 'axis']));
if (triggerAxis || cross) {
each(tooltipAxes.baseAxes, curry(
saveTooltipAxisInfo, cross ? 'cross' : true, triggerAxis
));
}
if (cross) {
each(tooltipAxes.otherAxes, curry(saveTooltipAxisInfo, 'cross', false));
}
}
// fromTooltip: true | false | 'cross'
// triggerTooltip: true | false | null
function saveTooltipAxisInfo(
fromTooltip: boolean | 'cross',
triggerTooltip: boolean,
axis: Axis
) {
let axisPointerModel = axis.model.getModel(
'axisPointer', globalAxisPointerModel
) as Model<CommonAxisPointerOption>;
const axisPointerShow = axisPointerModel.get('show');
if (!axisPointerShow || (
axisPointerShow === 'auto'
&& !fromTooltip
&& !isHandleTrigger(axisPointerModel)
)) {
return;
}
if (triggerTooltip == null) {
triggerTooltip = axisPointerModel.get('triggerTooltip');
}
axisPointerModel = fromTooltip
? makeAxisPointerModel(
axis, baseTooltipModel, globalAxisPointerModel, ecModel,
fromTooltip, triggerTooltip
)
: axisPointerModel;
const snap = axisPointerModel.get('snap');
const axisKey = makeKey(axis.model);
const involveSeries = triggerTooltip || snap || axis.type === 'category';
// If result.axesInfo[key] exist, override it (tooltip has higher priority).
const axisInfo: AxisInfo = result.axesInfo[axisKey] = {
key: axisKey,
axis: axis,
coordSys: coordSys,
axisPointerModel: axisPointerModel,
triggerTooltip: triggerTooltip,
involveSeries: involveSeries,
snap: snap,
useHandle: isHandleTrigger(axisPointerModel),
seriesModels: [],
linkGroup: null
};
axesInfoInCoordSys[axisKey] = axisInfo;
result.seriesInvolved = result.seriesInvolved || involveSeries;
const groupIndex = getLinkGroupIndex(linksOption, axis);
if (groupIndex != null) {
const linkGroup: LinkGroup = linkGroups[groupIndex]
|| (linkGroups[groupIndex] = {axesInfo: {}} as LinkGroup);
linkGroup.axesInfo[axisKey] = axisInfo;
linkGroup.mapper = linksOption[groupIndex].mapper;
axisInfo.linkGroup = linkGroup;
}
}
});
}
function makeAxisPointerModel(
axis: Axis,
baseTooltipModel: Model<TooltipOption>,
globalAxisPointerModel: AxisPointerModel,
ecModel: GlobalModel,
fromTooltip: boolean | 'cross',
triggerTooltip: boolean
) {
const tooltipAxisPointerModel = baseTooltipModel.getModel('axisPointer');
const fields = [
'type', 'snap', 'lineStyle', 'shadowStyle', 'label',
'animation', 'animationDurationUpdate', 'animationEasingUpdate', 'z'
] as const;
const volatileOption = {} as Pick<AxisPointerOption, typeof fields[number]>;
each(fields, function (field) {
(volatileOption as any)[field] = clone(tooltipAxisPointerModel.get(field));
});
// category axis do not auto snap, otherwise some tick that do not
// has value can not be hovered. value/time/log axis default snap if
// triggered from tooltip and trigger tooltip.
volatileOption.snap = axis.type !== 'category' && !!triggerTooltip;
// Compatibel with previous behavior, tooltip axis do not show label by default.
// Only these properties can be overrided from tooltip to axisPointer.
if (tooltipAxisPointerModel.get('type') === 'cross') {
volatileOption.type = 'line';
}
const labelOption = volatileOption.label || (volatileOption.label = {});
// Follow the convention, do not show label when triggered by tooltip by default.
labelOption.show == null && (labelOption.show = false);
if (fromTooltip === 'cross') {
// When 'cross', both axes show labels.
const tooltipAxisPointerLabelShow = tooltipAxisPointerModel.get(['label', 'show']);
labelOption.show = tooltipAxisPointerLabelShow != null ? tooltipAxisPointerLabelShow : true;
// If triggerTooltip, this is a base axis, which should better not use cross style
// (cross style is dashed by default)
if (!triggerTooltip) {
const crossStyle = volatileOption.lineStyle = tooltipAxisPointerModel.get('crossStyle');
crossStyle && defaults(labelOption, crossStyle.textStyle);
}
}
return axis.model.getModel(
'axisPointer',
new Model(volatileOption, globalAxisPointerModel, ecModel)
);
}
function collectSeriesInfo(result: CollectionResult, ecModel: GlobalModel) {
// Prepare data for axis trigger
ecModel.eachSeries(function (seriesModel: SeriesModel<SeriesOption & {
tooltip?: SeriesTooltipOption
axisPointer?: CommonAxisPointerOption
}>) {
// Notice this case: this coordSys is `cartesian2D` but not `grid`.
const coordSys = seriesModel.coordinateSystem;
const seriesTooltipTrigger = seriesModel.get(['tooltip', 'trigger'], true);
const seriesTooltipShow = seriesModel.get(['tooltip', 'show'], true);
if (!coordSys
|| seriesTooltipTrigger === 'none'
|| seriesTooltipTrigger === false
|| seriesTooltipTrigger === 'item'
|| seriesTooltipShow === false
|| seriesModel.get(['axisPointer', 'show'], true) === false
) {
return;
}
each(result.coordSysAxesInfo[makeKey(coordSys.model)], function (axisInfo) {
const axis = axisInfo.axis;
if (coordSys.getAxis(axis.dim) === axis) {
axisInfo.seriesModels.push(seriesModel);
axisInfo.seriesDataCount == null && (axisInfo.seriesDataCount = 0);
axisInfo.seriesDataCount += seriesModel.getData().count();
}
});
});
}
/**
* For example:
* {
* axisPointer: {
* links: [{
* xAxisIndex: [2, 4],
* yAxisIndex: 'all'
* }, {
* xAxisId: ['a5', 'a7'],
* xAxisName: 'xxx'
* }]
* }
* }
*/
function getLinkGroupIndex(linksOption: AxisPointerOption['link'], axis: Axis): number {
const axisModel = axis.model;
const dim = axis.dim;
for (let i = 0; i < linksOption.length; i++) {
const linkOption = linksOption[i] || {};
if (checkPropInLink(linkOption[dim + 'AxisId' as 'xAxisId'], axisModel.id)
|| checkPropInLink(linkOption[dim + 'AxisIndex' as 'xAxisIndex'], axisModel.componentIndex)
|| checkPropInLink(linkOption[dim + 'AxisName' as 'xAxisName'], axisModel.name)
) {
return i;
}
}
}
function checkPropInLink(linkPropValue: number[] | number | string | string[] | 'all', axisPropValue: number | string) {
return linkPropValue === 'all'
|| (isArray(linkPropValue) && indexOf(linkPropValue, axisPropValue) >= 0)
|| linkPropValue === axisPropValue;
}
export function fixValue(axisModel: AxisBaseModel) {
const axisInfo = getAxisInfo(axisModel);
if (!axisInfo) {
return;
}
const axisPointerModel = axisInfo.axisPointerModel;
const scale = axisInfo.axis.scale;
const option = axisPointerModel.option;
const status = axisPointerModel.get('status');
let value = axisPointerModel.get('value');
// Parse init value for category and time axis.
if (value != null) {
value = scale.parse(value);
}
const useHandle = isHandleTrigger(axisPointerModel);
// If `handle` used, `axisPointer` will always be displayed, so value
// and status should be initialized.
if (status == null) {
option.status = useHandle ? 'show' : 'hide';
}
const extent = scale.getExtent().slice();
extent[0] > extent[1] && extent.reverse();
if (// Pick a value on axis when initializing.
value == null
// If both `handle` and `dataZoom` are used, value may be out of axis extent,
// where we should re-pick a value to keep `handle` displaying normally.
|| value > extent[1]
) {
// Make handle displayed on the end of the axis when init, which looks better.
value = extent[1];
}
if (value < extent[0]) {
value = extent[0];
}
option.value = value;
if (useHandle) {
option.status = axisInfo.axis.scale.isBlank() ? 'hide' : 'show';
}
}
export function getAxisInfo(axisModel: AxisBaseModel) {
const coordSysAxesInfo = (axisModel.ecModel.getComponent('axisPointer') as AxisPointerModel || {})
.coordSysAxesInfo as CollectionResult;
return coordSysAxesInfo && coordSysAxesInfo.axesInfo[makeKey(axisModel)];
}
export function getAxisPointerModel(axisModel: AxisBaseModel) {
const axisInfo = getAxisInfo(axisModel);
return axisInfo && axisInfo.axisPointerModel;
}
function isHandleTrigger(axisPointerModel: Model<CommonAxisPointerOption>) {
return !!axisPointerModel.get(['handle', 'show']);
}
/**
* @param {module:echarts/model/Model} model
* @return {string} unique key
*/
export function makeKey(model: ComponentModel) {
return model.type + '||' + model.id;
}
相关信息
相关文章
echarts CartesianAxisPointer 源码
0
赞
热门推荐
-
2、 - 优质文章
-
3、 gate.io
-
8、 golang
-
9、 openharmony
-
10、 Vue中input框自动聚焦