Skip to content

Commit

Permalink
Add support to draw rectangle shape to filter documents (#348)
Browse files Browse the repository at this point in the history
* Add rectangle ui tool bar

Signed-off-by: Vijayan Balasubramanian <[email protected]>
  • Loading branch information
VijayanB authored Mar 22, 2023
1 parent d2c818f commit a42c915
Show file tree
Hide file tree
Showing 9 changed files with 266 additions and 6 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
* Update max supported layer count ([#332](https://github.com/opensearch-project/dashboards-maps/pull/332))
* BWC for document layer label textType ([#340](https://github.com/opensearch-project/dashboards-maps/pull/340))
* Add mapbox-gl draw mode ([#347](https://github.com/opensearch-project/dashboards-maps/pull/347))
* Add support to draw rectangle shape to filter documents ([#348](https://github.com/opensearch-project/dashboards-maps/pull/348))
* Avoid trigger tooltip from label ([#350](https://github.com/opensearch-project/dashboards-maps/pull/350))

### Bug Fixes
Expand Down
4 changes: 4 additions & 0 deletions common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,12 +158,14 @@ export enum TOOLTIP_STATE {
export enum FILTER_DRAW_MODE {
NONE = 'none', // draw filter is inactive
POLYGON = 'polygon', // Filter is active and set to draw polygon
RECTANGLE = 'rectangle', // Filter is active and set to draw rectangle
}

export const MAPBOX_GL_DRAW_CREATE_LISTENER = 'draw.create';

export enum MAPBOX_GL_DRAW_MODES {
DRAW_POLYGON = 'draw_polygon',
DRAW_RECTANGLE = 'draw_rectangle',
SIMPLE_SELECT = 'simple_select',
}

Expand All @@ -175,5 +177,7 @@ export interface DrawFilterProperties {

export const DRAW_FILTER_SHAPE_TITLE = 'DRAW SHAPE';
export const DRAW_FILTER_POLYGON_DEFAULT_LABEL = 'polygon';
export const DRAW_FILTER_RECTANGLE_DEFAULT_LABEL = 'rectangle';
export const DRAW_FILTER_POLYGON = 'Draw Polygon';
export const DRAW_FILTER_RECTANGLE = 'Draw Rectangle';
export const DRAW_FILTER_SPATIAL_RELATIONS = ['intersects', 'disjoint', 'within'];
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`renders filter by rectangle button 1`] = `
<EuiPopover
anchorPosition="leftUp"
button={
<EuiPanel
className="spatialFilterToolbar__shape"
paddingSize="none"
>
<EuiButtonIcon
aria-label="draw_filter_rectangle"
color="text"
iconType={Object {}}
isDisabled={false}
onClick={[Function]}
size="s"
title="Draw Rectangle"
/>
</EuiPanel>
}
closePopover={[Function]}
data-test-subj="drawRectanglePopOver"
display="inlineBlock"
hasArrow={true}
id="drawRectangleId"
isOpen={false}
ownFocus={true}
panelPaddingSize="none"
>
<EuiContextMenu
initialPanelId={0}
panels={
Array [
Object {
"content": <FilterInputPanel
defaultFilterLabel="rectangle"
drawLabel="Draw Rectangle"
mode="rectangle"
onSubmit={[Function]}
relations={
Array [
"intersects",
"disjoint",
"within",
]
}
/>,
"id": 0,
"title": "DRAW SHAPE",
},
]
}
size="m"
/>
</EuiPopover>
`;

exports[`renders filter by rectangle in middle of drawing 1`] = `
<EuiPopover
anchorPosition="leftUp"
button={
<EuiPanel
className="spatialFilterToolbar__shape"
paddingSize="none"
>
<EuiButtonIcon
aria-label="draw_filter_rectangle"
color="text"
iconType={Object {}}
isDisabled={true}
onClick={[Function]}
size="s"
title="Draw Rectangle"
/>
</EuiPanel>
}
closePopover={[Function]}
data-test-subj="drawRectanglePopOver"
display="inlineBlock"
hasArrow={true}
id="drawRectangleId"
isOpen={false}
ownFocus={true}
panelPaddingSize="none"
>
<EuiContextMenu
initialPanelId={0}
panels={
Array [
Object {
"content": <FilterInputPanel
defaultFilterLabel="rectangle"
drawLabel="Draw Rectangle"
mode="rectangle"
onSubmit={[Function]}
relations={
Array [
"intersects",
"disjoint",
"within",
]
}
/>,
"id": 0,
"title": "DRAW SHAPE",
},
]
}
size="m"
/>
</EuiPopover>
`;
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ exports[`renders spatial filter before drawing 1`] = `
isDrawActive={false}
setDrawFilterProperties={[MockFunction]}
/>
<FilterByRectangle
isDrawActive={false}
setDrawFilterProperties={[MockFunction]}
/>
</EuiFlexItem>
</EuiFlexGroup>
`;
Expand All @@ -36,6 +40,10 @@ exports[`renders spatial filter while drawing 1`] = `
isDrawActive={true}
setDrawFilterProperties={[MockFunction]}
/>
<FilterByRectangle
isDrawActive={true}
setDrawFilterProperties={[MockFunction]}
/>
</EuiFlexItem>
</EuiFlexGroup>
`;
24 changes: 18 additions & 6 deletions public/components/toolbar/spatial_filter/draw_filter_shape.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,25 @@ import {
MAPBOX_GL_DRAW_MODES,
MAPBOX_GL_DRAW_CREATE_LISTENER,
} from '../../../../common';
import { DrawRectangle } from '../../draw/modes/rectangle';

interface DrawFilterShapeProps {
filterProperties: DrawFilterProperties;
map: Maplibre;
updateFilterProperties: (properties: DrawFilterProperties) => void;
}

function getMapboxDrawMode(mode: FILTER_DRAW_MODE): string {
switch (mode) {
case FILTER_DRAW_MODE.POLYGON:
return MAPBOX_GL_DRAW_MODES.DRAW_POLYGON;
case FILTER_DRAW_MODE.RECTANGLE:
return MAPBOX_GL_DRAW_MODES.DRAW_RECTANGLE;
default:
return MAPBOX_GL_DRAW_MODES.SIMPLE_SELECT;
}
}

export const DrawFilterShape = ({
filterProperties,
map,
Expand All @@ -33,6 +45,10 @@ export const DrawFilterShape = ({
const mapboxDrawRef = useRef<MapboxDraw>(
new MapboxDraw({
displayControlsDefault: false,
modes: {
...MapboxDraw.modes,
[MAPBOX_GL_DRAW_MODES.DRAW_RECTANGLE]: DrawRectangle,
},
})
);

Expand All @@ -51,12 +67,8 @@ export const DrawFilterShape = ({
}, []);

useEffect(() => {
if (filterProperties.mode === FILTER_DRAW_MODE.POLYGON) {
mapboxDrawRef.current.changeMode(MAPBOX_GL_DRAW_MODES.DRAW_POLYGON);
} else {
// default mode
mapboxDrawRef.current.changeMode(MAPBOX_GL_DRAW_MODES.SIMPLE_SELECT);
}
const mapboxDrawMode: string = getMapboxDrawMode(filterProperties.mode);
mapboxDrawRef.current.changeMode(mapboxDrawMode);
}, [filterProperties.mode]);

return <Fragment />;
Expand Down
4 changes: 4 additions & 0 deletions public/components/toolbar/spatial_filter/draw_tooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ const getTooltipContent = (mode: FILTER_DRAW_MODE): string => {
return i18n.translate('maps.drawFilterPolygon.tooltipContent', {
defaultMessage: 'Click to start shape. Click for vertex. Double click to finish.',
});
case FILTER_DRAW_MODE.RECTANGLE:
return i18n.translate('maps.drawFilterRectangle.tooltipContent', {
defaultMessage: 'Click and drag to draw rectangle.',
});
default:
return i18n.translate('maps.drawFilterDefault.tooltipContent', {
defaultMessage: 'Click to start shape. Double click to finish.',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/
import { shallow } from 'enzyme';
import React from 'react';
import { FilterByRectangle } from './filter_by_rectangle';

it('renders filter by rectangle button', () => {
const mockCallback = jest.fn();
const component = shallow(
<FilterByRectangle setDrawFilterProperties={mockCallback} isDrawActive={false} />
);
expect(component).toMatchSnapshot();
});

it('renders filter by rectangle in middle of drawing', () => {
const mockCallback = jest.fn();
const component = shallow(
<FilterByRectangle setDrawFilterProperties={mockCallback} isDrawActive={true} />
);
expect(component).toMatchSnapshot();
});
90 changes: 90 additions & 0 deletions public/components/toolbar/spatial_filter/filter_by_rectangle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import React, { useState } from 'react';
import { EuiPopover, EuiContextMenu, EuiPanel, EuiButtonIcon } from '@elastic/eui';
import { FilterInputPanel } from './filter_input_panel';
// TODO: replace with rectangle image file once available
import rectangle from '../../../images/polygon.svg';
import {
DrawFilterProperties,
DRAW_FILTER_SPATIAL_RELATIONS,
DRAW_FILTER_SHAPE_TITLE,
DRAW_FILTER_RECTANGLE,
DRAW_FILTER_RECTANGLE_DEFAULT_LABEL,
} from '../../../../common';
import { FILTER_DRAW_MODE } from '../../../../common';

interface FilterByRectangleProps {
setDrawFilterProperties: (properties: DrawFilterProperties) => void;
isDrawActive: boolean;
}

export const FilterByRectangle = ({
setDrawFilterProperties,
isDrawActive,
}: FilterByRectangleProps) => {
const [isPopoverOpen, setPopover] = useState(false);

const onClick = () => {
setPopover(!isPopoverOpen);
};

const closePopover = () => {
setPopover(false);
};

const onSubmit = (input: { relation: string; label: string; mode: FILTER_DRAW_MODE }) => {
setDrawFilterProperties({
mode: input.mode,
relation: input.relation,
filterLabel: input.label,
});
closePopover();
};

const panels = [
{
id: 0,
title: DRAW_FILTER_SHAPE_TITLE,
content: (
<FilterInputPanel
drawLabel={DRAW_FILTER_RECTANGLE}
defaultFilterLabel={DRAW_FILTER_RECTANGLE_DEFAULT_LABEL}
relations={DRAW_FILTER_SPATIAL_RELATIONS}
onSubmit={onSubmit}
mode={FILTER_DRAW_MODE.RECTANGLE}
/>
),
},
];

const drawRectangleButton = (
<EuiPanel paddingSize="none" className="spatialFilterToolbar__shape">
<EuiButtonIcon
color="text"
size={'s'}
iconType={rectangle}
onClick={onClick}
aria-label={'draw_filter_rectangle'}
title={DRAW_FILTER_RECTANGLE}
isDisabled={isDrawActive}
/>
</EuiPanel>
);
return (
<EuiPopover
id="drawRectangleId"
button={drawRectangleButton}
isOpen={isPopoverOpen}
closePopover={closePopover}
panelPaddingSize="none"
anchorPosition="leftUp"
data-test-subj="drawRectanglePopOver"
>
<EuiContextMenu initialPanelId={0} panels={panels} />
</EuiPopover>
);
};
5 changes: 5 additions & 0 deletions public/components/toolbar/spatial_filter/filter_toolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import React from 'react';
import { EuiButton, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { FilterByPolygon } from './filter_by_polygon';
import { FILTER_DRAW_MODE, DrawFilterProperties } from '../../../../common';
import {FilterByRectangle} from "./filter_by_rectangle";

interface SpatialFilterToolBarProps {
setFilterProperties: (properties: DrawFilterProperties) => void;
Expand All @@ -25,6 +26,10 @@ export const SpatialFilterToolbar = ({
const filterIconGroups = (
<EuiFlexItem>
<FilterByPolygon setDrawFilterProperties={setFilterProperties} isDrawActive={isDrawActive} />
<FilterByRectangle
setDrawFilterProperties={setFilterProperties}
isDrawActive={isDrawActive}
/>
</EuiFlexItem>
);
if (isDrawActive) {
Expand Down

0 comments on commit a42c915

Please sign in to comment.