| /* | 
 | * 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 polygonContain from 'zrender/src/contain/polygon'; | 
 | import BoundingRect, { RectLike } from 'zrender/src/core/BoundingRect'; | 
 | import {linePolygonIntersect} from '../../util/graphic'; | 
 | import { BrushType, BrushDimensionMinMax } from '../helper/BrushController'; | 
 | import { BrushAreaParamInternal } from './BrushModel'; | 
 |  | 
 |  | 
 | export interface BrushSelectableArea extends BrushAreaParamInternal { | 
 |     boundingRect: BoundingRect; | 
 |     selectors: BrushCommonSelectorsForSeries | 
 | } | 
 |  | 
 | /** | 
 |  * Key of the first level is brushType: `line`, `rect`, `polygon`. | 
 |  * See moudule:echarts/component/helper/BrushController | 
 |  * function param: | 
 |  *      {Object} itemLayout fetch from data.getItemLayout(dataIndex) | 
 |  *      {Object} selectors {point: selector, rect: selector, ...} | 
 |  *      {Object} area {range: [[], [], ..], boudingRect} | 
 |  * function return: | 
 |  *      {boolean} Whether in the given brush. | 
 |  */ | 
 | interface BrushSelectorOnBrushType { | 
 |     // For chart element type "point" | 
 |     point( | 
 |         // fetch from data.getItemLayout(dataIndex) | 
 |         itemLayout: number[], | 
 |         selectors: BrushCommonSelectorsForSeries, | 
 |         area: BrushSelectableArea | 
 |     ): boolean; | 
 |     // For chart element type "rect" | 
 |     rect( | 
 |         // fetch from data.getItemLayout(dataIndex) | 
 |         itemLayout: RectLike, | 
 |         selectors: BrushCommonSelectorsForSeries, | 
 |         area: BrushSelectableArea | 
 |     ): boolean; | 
 | } | 
 |  | 
 | /** | 
 |  * This methods are corresponding to `BrushSelectorOnBrushType`, | 
 |  * but `area: BrushSelectableArea` is binded to each method. | 
 |  */ | 
 | export interface BrushCommonSelectorsForSeries { | 
 |     // For chart element type "point" | 
 |     point(itemLayout: number[]): boolean; | 
 |     // For chart element type "rect" | 
 |     rect(itemLayout: RectLike): boolean; | 
 | } | 
 |  | 
 | export function makeBrushCommonSelectorForSeries( | 
 |     area: BrushSelectableArea | 
 | ): BrushCommonSelectorsForSeries { | 
 |     const brushType = area.brushType; | 
 |     // Do not use function binding or curry for performance. | 
 |     const selectors: BrushCommonSelectorsForSeries = { | 
 |         point(itemLayout: number[]) { | 
 |             return selector[brushType].point(itemLayout, selectors, area); | 
 |         }, | 
 |         rect(itemLayout: RectLike) { | 
 |             return selector[brushType].rect(itemLayout, selectors, area); | 
 |         } | 
 |     }; | 
 |     return selectors; | 
 | } | 
 |  | 
 | const selector: Record<BrushType, BrushSelectorOnBrushType> = { | 
 |     lineX: getLineSelectors(0), | 
 |     lineY: getLineSelectors(1), | 
 |     rect: { | 
 |         point: function (itemLayout, selectors, area) { | 
 |             return itemLayout && area.boundingRect.contain(itemLayout[0], itemLayout[1]); | 
 |         }, | 
 |         rect: function (itemLayout, selectors, area) { | 
 |             return itemLayout && area.boundingRect.intersect(itemLayout); | 
 |         } | 
 |     }, | 
 |     polygon: { | 
 |         point: function (itemLayout, selectors, area) { | 
 |             return itemLayout | 
 |                 && area.boundingRect.contain( | 
 |                     itemLayout[0], itemLayout[1] | 
 |                 ) | 
 |                 && polygonContain.contain( | 
 |                     area.range as BrushDimensionMinMax[], itemLayout[0], itemLayout[1] | 
 |                 ); | 
 |         }, | 
 |         rect: function (itemLayout, selectors, area) { | 
 |             const points = area.range as BrushDimensionMinMax[]; | 
 |  | 
 |             if (!itemLayout || points.length <= 1) { | 
 |                 return false; | 
 |             } | 
 |  | 
 |             const x = itemLayout.x; | 
 |             const y = itemLayout.y; | 
 |             const width = itemLayout.width; | 
 |             const height = itemLayout.height; | 
 |             const p = points[0]; | 
 |  | 
 |             if (polygonContain.contain(points, x, y) | 
 |                 || polygonContain.contain(points, x + width, y) | 
 |                 || polygonContain.contain(points, x, y + height) | 
 |                 || polygonContain.contain(points, x + width, y + height) | 
 |                 || BoundingRect.create(itemLayout).contain(p[0], p[1]) | 
 |                 || linePolygonIntersect(x, y, x + width, y, points) | 
 |                 || linePolygonIntersect(x, y, x, y + height, points) | 
 |                 || linePolygonIntersect(x + width, y, x + width, y + height, points) | 
 |                 || linePolygonIntersect(x, y + height, x + width, y + height, points) | 
 |             ) { | 
 |                 return true; | 
 |             } | 
 |         } | 
 |     } | 
 | }; | 
 |  | 
 | function getLineSelectors(xyIndex: 0 | 1): BrushSelectorOnBrushType { | 
 |     const xy = ['x', 'y'] as const; | 
 |     const wh = ['width', 'height'] as const; | 
 |  | 
 |     return { | 
 |         point: function (itemLayout, selectors, area) { | 
 |             if (itemLayout) { | 
 |                 const range = area.range as BrushDimensionMinMax; | 
 |                 const p = itemLayout[xyIndex]; | 
 |                 return inLineRange(p, range); | 
 |             } | 
 |         }, | 
 |         rect: function (itemLayout, selectors, area) { | 
 |             if (itemLayout) { | 
 |                 const range = area.range as BrushDimensionMinMax; | 
 |                 const layoutRange = [ | 
 |                     itemLayout[xy[xyIndex]], | 
 |                     itemLayout[xy[xyIndex]] + itemLayout[wh[xyIndex]] | 
 |                 ]; | 
 |                 layoutRange[1] < layoutRange[0] && layoutRange.reverse(); | 
 |                 return inLineRange(layoutRange[0], range) | 
 |                     || inLineRange(layoutRange[1], range) | 
 |                     || inLineRange(range[0], layoutRange) | 
 |                     || inLineRange(range[1], layoutRange); | 
 |             } | 
 |         } | 
 |     }; | 
 | } | 
 |  | 
 | function inLineRange(p: number, range: BrushDimensionMinMax): boolean { | 
 |     return range[0] <= p && p <= range[1]; | 
 | } | 
 |  | 
 | export default selector; |