blob: 3b1e20e088424ed9a00419569bc289ef1b987612 [file] [log] [blame]
/*
* 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 { EventProcessor, EventQuery } from 'zrender/src/core/Eventful';
import { ECActionEvent, NormalizedEventQuery, EventQueryItem, ECElementEvent } from './types';
import ComponentModel from '../model/Component';
import ComponentView from '../view/Component';
import ChartView from '../view/Chart';
import * as zrUtil from 'zrender/src/core/util';
import { parseClassType } from './clazz';
import Element from 'zrender/src/Element';
/**
* Usage of query:
* `chart.on('click', query, handler);`
* The `query` can be:
* + The component type query string, only `mainType` or `mainType.subType`,
* like: 'xAxis', 'series', 'xAxis.category' or 'series.line'.
* + The component query object, like:
* `{seriesIndex: 2}`, `{seriesName: 'xx'}`, `{seriesId: 'some'}`,
* `{xAxisIndex: 2}`, `{xAxisName: 'xx'}`, `{xAxisId: 'some'}`.
* + The data query object, like:
* `{dataIndex: 123}`, `{dataType: 'link'}`, `{name: 'some'}`.
* + The other query object (cmponent customized query), like:
* `{element: 'some'}` (only available in custom series).
*
* Caveat: If a prop in the `query` object is `null/undefined`, it is the
* same as there is no such prop in the `query` object.
*/
export class ECEventProcessor implements EventProcessor {
// These info required: targetEl, packedEvent, model, view
eventInfo: {
targetEl: Element;
packedEvent: ECActionEvent | ECElementEvent;
model: ComponentModel;
view: ComponentView | ChartView;
};
normalizeQuery(query: EventQuery): NormalizedEventQuery {
const cptQuery: EventQueryItem = {};
const dataQuery: EventQueryItem = {};
const otherQuery: EventQueryItem = {};
// `query` is `mainType` or `mainType.subType` of component.
if (zrUtil.isString(query)) {
const condCptType = parseClassType(query);
// `.main` and `.sub` may be ''.
cptQuery.mainType = condCptType.main || null;
cptQuery.subType = condCptType.sub || null;
}
// `query` is an object, convert to {mainType, index, name, id}.
else {
// `xxxIndex`, `xxxName`, `xxxId`, `name`, `dataIndex`, `dataType` is reserved,
// can not be used in `compomentModel.filterForExposedEvent`.
const suffixes = ['Index', 'Name', 'Id'];
const dataKeys = {name: 1, dataIndex: 1, dataType: 1};
zrUtil.each(query, function (val, key) {
let reserved = false;
for (let i = 0; i < suffixes.length; i++) {
const propSuffix = suffixes[i];
const suffixPos = key.lastIndexOf(propSuffix);
if (suffixPos > 0 && suffixPos === key.length - propSuffix.length) {
const mainType = key.slice(0, suffixPos);
// Consider `dataIndex`.
if (mainType !== 'data') {
cptQuery.mainType = mainType;
cptQuery[propSuffix.toLowerCase()] = val;
reserved = true;
}
}
}
if (dataKeys.hasOwnProperty(key)) {
dataQuery[key] = val;
reserved = true;
}
if (!reserved) {
otherQuery[key] = val;
}
});
}
return {
cptQuery: cptQuery,
dataQuery: dataQuery,
otherQuery: otherQuery
};
}
filter(eventType: string, query: NormalizedEventQuery): boolean {
// They should be assigned before each trigger call.
const eventInfo = this.eventInfo;
if (!eventInfo) {
return true;
}
const targetEl = eventInfo.targetEl;
const packedEvent = eventInfo.packedEvent;
const model = eventInfo.model;
const view = eventInfo.view;
// For event like 'globalout'.
if (!model || !view) {
return true;
}
const cptQuery = query.cptQuery;
const dataQuery = query.dataQuery;
return check(cptQuery, model, 'mainType')
&& check(cptQuery, model, 'subType')
&& check(cptQuery, model, 'index', 'componentIndex')
&& check(cptQuery, model, 'name')
&& check(cptQuery, model, 'id')
&& check(dataQuery, packedEvent, 'name')
&& check(dataQuery, packedEvent, 'dataIndex')
&& check(dataQuery, packedEvent, 'dataType')
&& (!view.filterForExposedEvent || view.filterForExposedEvent(
eventType, query.otherQuery, targetEl, packedEvent
));
function check(
query: EventQueryItem, host: any, prop: string, propOnHost?: string
): boolean {
return query[prop] == null || host[propOnHost || prop] === query[prop];
}
}
afterTrigger() {
// Make sure the eventInfo wont be used in next trigger.
this.eventInfo = null;
}
};