Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Maps] show vector tile labels on top #69444

Merged
merged 16 commits into from
Jul 3, 2020
1 change: 1 addition & 0 deletions x-pack/plugins/maps/common/descriptor_types/sources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ export type LayerDescriptor = {
alpha?: number;
id: string;
label?: string | null;
labelsOnTop?: boolean;
nreese marked this conversation as resolved.
Show resolved Hide resolved
minZoom?: number;
maxZoom?: number;
sourceDescriptor: SourceDescriptor | null;
Expand Down
9 changes: 9 additions & 0 deletions x-pack/plugins/maps/public/actions/layer_actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,15 @@ export function updateLayerAlpha(id: string, alpha: number) {
};
}

export function updateLabelsOnTop(id: string, labelsOnTop: boolean) {
return {
type: UPDATE_LAYER_PROP,
id,
propName: 'labelsOnTop',
newValue: labelsOnTop,
};
}

export function setLayerQuery(id: string, query: Query) {
return (dispatch: Dispatch) => {
dispatch({
Expand Down
10 changes: 10 additions & 0 deletions x-pack/plugins/maps/public/classes/layers/layer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ export interface ILayer {
getPrevRequestToken(dataId: string): symbol | undefined;
destroy: () => void;
isPreviewLayer: () => boolean;
labelsOnTop: () => boolean;
supportsLabelsOnTop: () => boolean;
}
export type Footnote = {
icon: ReactElement<any>;
Expand Down Expand Up @@ -483,4 +485,12 @@ export class AbstractLayer implements ILayer {
getType(): string | undefined {
return this._descriptor.type;
}

labelsOnTop(): boolean {
return false;
}

supportsLabelsOnTop(): boolean {
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -277,4 +277,12 @@ export class VectorTileLayer extends TileLayer {
this._setOpacityForType(mbMap, mbLayer, mbLayerId);
});
}

labelsOnTop() {
return !!this._descriptor.labelsOnTop;
}

supportsLabelsOnTop() {
return true;
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { AnyAction, Dispatch } from 'redux';
import { connect } from 'react-redux';
import { LayerSettings } from './layer_settings';
import { getSelectedLayer } from '../../../selectors/map_selectors';
import {
updateLayerLabel,
updateLayerMaxZoom,
updateLayerMinZoom,
updateLayerAlpha,
updateLabelsOnTop,
} from '../../../actions';
import { MapStoreState } from '../../../reducers/store';

function mapStateToProps(state: MapStoreState) {
const selectedLayer = getSelectedLayer(state);
return {
layer: selectedLayer ? selectedLayer : null,
};
}

function mapDispatchToProps(dispatch: Dispatch<AnyAction>) {
return {
updateLabel: (id: string, label: string) => dispatch(updateLayerLabel(id, label)),
updateMinZoom: (id: string, minZoom: number) => dispatch(updateLayerMinZoom(id, minZoom)),
updateMaxZoom: (id: string, maxZoom: number) => dispatch(updateLayerMaxZoom(id, maxZoom)),
updateAlpha: (id: string, alpha: number) => dispatch(updateLayerAlpha(id, alpha)),
updateLabelsOnTop: (id: string, labelsOnTop: boolean) =>
dispatch(updateLabelsOnTop(id, labelsOnTop)),
};
}

const connectedLayerSettings = connect(mapStateToProps, mapDispatchToProps)(LayerSettings);
export { connectedLayerSettings as LayerSettings };

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/*
nreese marked this conversation as resolved.
Show resolved Hide resolved
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import React, { ChangeEvent, Fragment } from 'react';
import {
EuiTitle,
EuiPanel,
EuiFormRow,
EuiFieldText,
EuiSpacer,
EuiSwitch,
EuiSwitchEvent,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { MAX_ZOOM } from '../../../../common/constants';
import { AlphaSlider } from '../../../components/alpha_slider';
import { ValidatedDualRange } from '../../../../../../../src/plugins/kibana_react/public';
import { ILayer } from '../../../classes/layers/layer';

interface Props {
layer: ILayer | null;
updateLabel: (layerId: string, label: string) => void;
updateMinZoom: (layerId: string, minZoom: number) => void;
updateMaxZoom: (layerId: string, maxZoom: number) => void;
updateAlpha: (layerId: string, alpha: number) => void;
updateLabelsOnTop: (layerId: string, labelsOnTop: boolean) => void;
}

export function LayerSettings(props: Props) {
if (!props.layer) {
nreese marked this conversation as resolved.
Show resolved Hide resolved
return null;
}

const minVisibilityZoom = props.layer.getMinSourceZoom();
const maxVisibilityZoom = MAX_ZOOM;
const layerId = props.layer.getId();

const onLabelChange = (event: ChangeEvent<HTMLInputElement>) => {
const label = event.target.value;
props.updateLabel(layerId, label);
};

const onZoomChange = (value: [string, string]) => {
props.updateMinZoom(layerId, Math.max(minVisibilityZoom, parseInt(value[0], 10)));
props.updateMaxZoom(layerId, Math.min(maxVisibilityZoom, parseInt(value[1], 10)));
};

const onAlphaChange = (alpha: number) => {
props.updateAlpha(layerId, alpha);
};

const onLabelsOnTopChange = (event: EuiSwitchEvent) => {
props.updateLabelsOnTop(layerId, event.target.checked);
};

const renderZoomSliders = () => {
return (
<ValidatedDualRange
label={i18n.translate('xpack.maps.layerPanel.settingsPanel.visibleZoomLabel', {
defaultMessage: 'Visibility',
})}
formRowDisplay="columnCompressed"
min={minVisibilityZoom}
max={maxVisibilityZoom}
value={[props.layer!.getMinZoom(), props.layer!.getMaxZoom()]}
showInput="inputWithPopover"
showRange
showLabels
onChange={onZoomChange}
allowEmptyRange={false}
compressed
prepend={i18n.translate('xpack.maps.layerPanel.settingsPanel.visibleZoom', {
defaultMessage: 'Zoom levels',
})}
/>
);
};

const renderLabel = () => {
return (
<EuiFormRow
label={i18n.translate('xpack.maps.layerPanel.settingsPanel.layerNameLabel', {
defaultMessage: 'Name',
})}
display="columnCompressed"
>
<EuiFieldText value={props.layer!.getLabel()} onChange={onLabelChange} compressed />
</EuiFormRow>
);
};

const renderShowLabelsOnTop = () => {
if (!props.layer!.supportsLabelsOnTop()) {
return null;
}

return (
<EuiFormRow display="columnCompressedSwitch">
<EuiSwitch
label={i18n.translate('xpack.maps.layerPanel.settingsPanel.labelsOnTop', {
defaultMessage: `Show labels on top`,
})}
checked={props.layer!.labelsOnTop()}
onChange={onLabelsOnTopChange}
data-test-subj="mapLayerPanelApplyGlobalQueryCheckbox"
compressed
/>
</EuiFormRow>
);
};

return (
<Fragment>
<EuiPanel>
<EuiTitle size="xs">
<h5>
<FormattedMessage
id="xpack.maps.layerPanel.layerSettingsTitle"
defaultMessage="Layer settings"
/>
</h5>
</EuiTitle>

<EuiSpacer size="m" />
{renderLabel()}
{renderZoomSliders()}
<AlphaSlider alpha={props.layer.getAlpha()} onChange={onAlphaChange} />
{renderShowLabelsOnTop()}
</EuiPanel>

<EuiSpacer size="s" />
</Fragment>
);
}
Loading