mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[Maps] Design/SASS cleanup (#28716)
* Separating out GIS styles from _main to their respective components * Clean up some styles and try to use more EUI where possible * Change “landing page” to url * Change dynamic switch into toggle button # Conflicts: # x-pack/plugins/gis/public/shared/layers/styles/components/vector/size/size_range_selector.js * Copy clean up * Add comment * remove dynmaic style description from heatmap style * Some fixes to new data source selector and copy changes * A couple more copy edits * update oridinal fields when layer changes * A couple of fixes * rector static_dynamic_styling_option.js so it makes sense * fix range selector not showing style * Specific browser fixes
This commit is contained in:
parent
a38c888351
commit
2bea9afbfe
49 changed files with 674 additions and 670 deletions
|
@ -1,10 +1,3 @@
|
|||
// Makes sure the listing page is full height with proper background
|
||||
map-listing, .gisListingPage {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
|
||||
#gis-plugin {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
@ -19,284 +12,25 @@ map-listing, .gisListingPage {
|
|||
flex-direction: column;
|
||||
}
|
||||
|
||||
.gisMapWrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.layerToast {
|
||||
margin-top: -150px !important;
|
||||
pointer-events: none;
|
||||
}
|
||||
// MapBox
|
||||
|
||||
.mapContainer {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. The overlay captures mouse events even if it's empty space. To counter-act this,
|
||||
* we remove all pointer events from the overlay then add them back on the
|
||||
* individual widgets.
|
||||
*/
|
||||
|
||||
.gisWidgetOverlay {
|
||||
position: absolute;
|
||||
z-index: $euiZLevel1;
|
||||
top: $euiSizeM;
|
||||
right: $euiSizeM;
|
||||
bottom: $euiSizeM;
|
||||
// left: $euiSizeM;
|
||||
pointer-events: none; /* 1 */
|
||||
}
|
||||
|
||||
.gisWidgetOverlay__rightSide {
|
||||
min-width: 17rem;
|
||||
max-width: 24rem;
|
||||
}
|
||||
|
||||
.gisWidgetControl {
|
||||
max-height: 100%;
|
||||
overflow: hidden;
|
||||
padding-bottom: $euiSizeS; // ensures the scrollbar doesn't appear unnecessarily because of flex group negative margins
|
||||
border-color: transparent !important;
|
||||
flex-direction: column;
|
||||
display: flex;
|
||||
pointer-events: all; /* 1 */
|
||||
|
||||
&.euiPanel--shadow {
|
||||
@include euiBottomShadowLarge;
|
||||
}
|
||||
|
||||
.gisWidgetControl__header {
|
||||
padding: $euiSizeS $euiSize;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.gisAttributionControl {
|
||||
padding: 0 $euiSizeXS;
|
||||
}
|
||||
|
||||
.gisViewControl__coordinates {
|
||||
padding: $euiSizeXS $euiSizeS;
|
||||
justify-content: center;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.gisViewControl__gotoButton {
|
||||
min-width: 0;
|
||||
pointer-events: all; /* 1 */
|
||||
}
|
||||
|
||||
.gisWidgetControl__tocHolder {
|
||||
@include euiScrollBar;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.layerEntry {
|
||||
padding: $euiSizeS $euiSize;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.alphaRange {
|
||||
.euiFieldNumber {
|
||||
max-width: 5.5em !important;
|
||||
}
|
||||
}
|
||||
|
||||
.colorPicker {
|
||||
.euiColorPickerPopUp {
|
||||
z-index: 3000;
|
||||
}
|
||||
}
|
||||
|
||||
.colorGradient {
|
||||
width: 100%;
|
||||
height: 20px;
|
||||
position: relative;
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
bottom: 0px;
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
.layerEntry > .visible {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.layerEntry > .notvisible { //ugh, already global classname named `invisible`
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.layerEntry .grab:hover {
|
||||
cursor: -webkit-grab;
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
.layerSettings__type {
|
||||
.euiIcon {
|
||||
margin-top: -2px;
|
||||
}
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none
|
||||
}
|
||||
|
||||
// HOTFIX coming from EUI
|
||||
.sourceSelectItem {
|
||||
width: 374px;
|
||||
}
|
||||
|
||||
.mapboxgl-popup {
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.gisLayerPanel {
|
||||
background-color: $euiColorLightestShade;
|
||||
width: 0;
|
||||
overflow: hidden;
|
||||
|
||||
> * {
|
||||
width: $euiSizeXXL * 11;
|
||||
}
|
||||
|
||||
&-isVisible {
|
||||
width: $euiSizeXXL * 11;
|
||||
transition: width $euiAnimSpeedNormal $euiAnimSlightResistance;
|
||||
}
|
||||
}
|
||||
|
||||
.gisViewPanel__header,
|
||||
.gisViewPanel__body,
|
||||
.gisViewPanel__footer {
|
||||
padding: $euiSize;
|
||||
}
|
||||
|
||||
.gisViewPanel__header {
|
||||
padding-bottom: 0;
|
||||
flex-shrink: 0;
|
||||
z-index: 2;
|
||||
box-shadow: 0 $euiSize $euiSize (-$euiSize / 2) $euiColorLightestShade;
|
||||
}
|
||||
|
||||
.gisViewPanel__title {
|
||||
svg {
|
||||
margin: -.1em .5em 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
.gisViewPanel__body {
|
||||
overflow: hidden;
|
||||
overflow-y: auto;
|
||||
@include euiScrollBar;
|
||||
|
||||
> * {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
> *:not(:last-child) {
|
||||
margin-bottom: $euiSize;
|
||||
}
|
||||
}
|
||||
|
||||
.gisViewPanel__footer {
|
||||
padding-top: 0;
|
||||
flex-shrink: 0;
|
||||
z-index: 2;
|
||||
box-shadow: 0 ($euiSize *-1) $euiSize (-$euiSize / 2) $euiColorLightestShade;
|
||||
}
|
||||
// This is not good practice to create such a generic class.
|
||||
// I can't seem to find it being applied anywhere in GIS
|
||||
// .hidden {
|
||||
// display: none
|
||||
// }
|
||||
|
||||
// EUIFIXTODO:
|
||||
|
||||
.euiColorPicker__emptySwatch {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.visibilityToggle {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
min-height: 20px;
|
||||
color: $euiColorMediumShade;
|
||||
|
||||
.visibilityToggle__body {
|
||||
line-height: 19px;
|
||||
|
||||
> * {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
}
|
||||
|
||||
.visibilityToggle__content {
|
||||
svg {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.filter {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.visibilityToggle__eye,
|
||||
.visibilityToggle__eyeClosed,
|
||||
.visibilityToggle__content {
|
||||
transition: opacity .2s ease-in-out;
|
||||
}
|
||||
|
||||
.visibilityToggle__eye,
|
||||
.visibilityToggle__eyeClosed {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
opacity: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.euiSwitch__input {
|
||||
z-index: 2;
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.visibilityToggle__body {
|
||||
display: block;
|
||||
display: block;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
cursor: pointer;
|
||||
color: $euiColorPrimary;
|
||||
|
||||
.visibilityToggle__content {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.euiSwitch__input:checked {
|
||||
+ .visibilityToggle__body > .visibilityToggle__eye {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.euiSwitch__input:not(:checked) {
|
||||
+ .visibilityToggle__body > .visibilityToggle__content {
|
||||
opacity: 0;
|
||||
}
|
||||
+ .visibilityToggle__body > .visibilityToggle__eyeClosed {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.euiComboBox {
|
||||
.euiComboBox__inputWrap {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1,5 @@
|
|||
@import './layer_panel/join_editor/resources/join';
|
||||
@import './gis_map/gis_map';
|
||||
@import './layer_addpanel/layer_addpanel';
|
||||
@import './layer_panel/index';
|
||||
@import './toasts/toasts';
|
||||
@import './widget_overlay/index';
|
||||
|
|
18
x-pack/plugins/gis/public/components/gis_map/_gis_map.scss
Normal file
18
x-pack/plugins/gis/public/components/gis_map/_gis_map.scss
Normal file
|
@ -0,0 +1,18 @@
|
|||
.gisMapWrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.gisMapLayerPanel {
|
||||
background-color: $euiColorLightestShade;
|
||||
width: 0;
|
||||
overflow: hidden;
|
||||
|
||||
> * {
|
||||
width: $euiSizeXXL * 11;
|
||||
}
|
||||
|
||||
&-isVisible {
|
||||
width: $euiSizeXXL * 11;
|
||||
transition: width $euiAnimSpeedNormal $euiAnimSlightResistance;
|
||||
}
|
||||
}
|
|
@ -66,10 +66,10 @@ export class GisMap extends Component {
|
|||
if (noFlyoutVisible) {
|
||||
currentPanel = null;
|
||||
} else if (addLayerVisible) {
|
||||
currentPanelClassName = "gisLayerPanel-isVisible";
|
||||
currentPanelClassName = "gisMapLayerPanel-isVisible";
|
||||
currentPanel = <AddLayerPanel/>;
|
||||
} else if (layerDetailsVisible) {
|
||||
currentPanelClassName = "gisLayerPanel-isVisible";
|
||||
currentPanelClassName = "gisMapLayerPanel-isVisible";
|
||||
currentPanel = (
|
||||
<LayerPanel/>
|
||||
);
|
||||
|
@ -81,7 +81,7 @@ export class GisMap extends Component {
|
|||
<WidgetOverlay/>
|
||||
</EuiFlexItem>
|
||||
|
||||
<EuiFlexItem className={`gisLayerPanel ${currentPanelClassName}`} grow={false}>
|
||||
<EuiFlexItem className={`gisMapLayerPanel ${currentPanelClassName}`} grow={false}>
|
||||
{currentPanel}
|
||||
</EuiFlexItem>
|
||||
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
.gisLayerAddpanel__card {
|
||||
// EUITODO: Fix horizontal layout so it works with any size icon
|
||||
.euiCard__content {
|
||||
padding-top: 0 !important;
|
||||
}
|
||||
|
||||
.euiCard__top + .euiCard__content {
|
||||
padding-top: 2px !important;
|
||||
}
|
||||
}
|
|
@ -7,16 +7,18 @@
|
|||
import React, { Component, Fragment } from 'react';
|
||||
import { ALL_SOURCES } from '../../shared/layers/sources/all_sources';
|
||||
import {
|
||||
EuiSpacer,
|
||||
EuiButton,
|
||||
EuiHorizontalRule,
|
||||
EuiButtonEmpty,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiTitle,
|
||||
EuiPanel,
|
||||
EuiSpacer,
|
||||
EuiCard,
|
||||
EuiIcon,
|
||||
EuiFlyoutHeader,
|
||||
EuiFlyoutBody,
|
||||
EuiFlyoutFooter,
|
||||
} from '@elastic/eui';
|
||||
|
||||
export class AddLayerPanel extends Component {
|
||||
|
@ -67,7 +69,7 @@ export class AddLayerPanel extends Component {
|
|||
}}
|
||||
fill
|
||||
>
|
||||
Create layer
|
||||
Add layer
|
||||
</EuiButton>
|
||||
);
|
||||
}
|
||||
|
@ -75,17 +77,20 @@ export class AddLayerPanel extends Component {
|
|||
_renderSourceCards() {
|
||||
return ALL_SOURCES.map(Source => {
|
||||
const icon = Source.icon
|
||||
? <EuiIcon type={Source.icon} size="xl" />
|
||||
? <EuiIcon type={Source.icon} size="l" />
|
||||
: null;
|
||||
return (
|
||||
<EuiCard
|
||||
key={Source.type}
|
||||
title={Source.title}
|
||||
icon={icon}
|
||||
onClick={() => this._onSourceTypeChange(Source.type)}
|
||||
description={Source.description}
|
||||
layout="horizontal"
|
||||
/>
|
||||
<Fragment key={Source.type}>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiCard
|
||||
className="gisLayerAddpanel__card"
|
||||
title={Source.title}
|
||||
icon={icon}
|
||||
onClick={() => this._onSourceTypeChange(Source.type)}
|
||||
description={Source.description}
|
||||
layout="horizontal"
|
||||
/>
|
||||
</Fragment>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@ -117,12 +122,14 @@ export class AddLayerPanel extends Component {
|
|||
return (
|
||||
<Fragment>
|
||||
<EuiButtonEmpty
|
||||
contentProps={{ style: { justifyContent: 'left' } }}
|
||||
size="xs"
|
||||
flush="left"
|
||||
onClick={this._clearSource}
|
||||
iconType="arrowLeft"
|
||||
>
|
||||
Change data source
|
||||
</EuiButtonEmpty>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiPanel>
|
||||
{Source.renderEditor(editorProperties)}
|
||||
</EuiPanel>
|
||||
|
@ -144,21 +151,17 @@ export class AddLayerPanel extends Component {
|
|||
direction="column"
|
||||
gutterSize="none"
|
||||
>
|
||||
<EuiFlexItem grow={false} className="gisViewPanel__header">
|
||||
<EuiFlyoutHeader hasBorder className="gisLayerPanel__header">
|
||||
<EuiTitle size="s">
|
||||
<h1>Add layer</h1>
|
||||
<h2>Add layer</h2>
|
||||
</EuiTitle>
|
||||
<EuiSpacer size="m"/>
|
||||
<EuiHorizontalRule margin="none"/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlyoutHeader>
|
||||
|
||||
<EuiFlexItem className="gisViewPanel__body">
|
||||
<EuiFlyoutBody className="gisLayerPanel__body">
|
||||
{this._renderAddLayerForm()}
|
||||
</EuiFlexItem>
|
||||
</EuiFlyoutBody>
|
||||
|
||||
<EuiFlexItem grow={false} className="gisViewPanel__footer">
|
||||
<EuiHorizontalRule margin="none"/>
|
||||
<EuiSpacer size="m"/>
|
||||
<EuiFlyoutFooter className="gisLayerPanel__footer">
|
||||
<EuiFlexGroup justifyContent="spaceBetween" responsive={false}>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonEmpty
|
||||
|
@ -172,7 +175,7 @@ export class AddLayerPanel extends Component {
|
|||
{this._renderNextBtn()}
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
</EuiFlyoutFooter>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
@import './layer_panel';
|
||||
@import './join_editor/resources/join';
|
||||
@import './settings_panel/settings_panel';
|
|
@ -0,0 +1,29 @@
|
|||
/**
|
||||
* 1. Firefox and IE don't respect bottom padding of overflow scrolling flex items.
|
||||
* So we instead strip out the bottom padding and add the same amount as a margin
|
||||
* to the last child element.
|
||||
*/
|
||||
|
||||
.gisLayerPanel__header,
|
||||
.gisLayerPanel__body,
|
||||
.gisLayerPanel__footer {
|
||||
padding: $euiSize;
|
||||
}
|
||||
|
||||
.gisLayerPanel__body {
|
||||
flex-basis: 1px; /* Fixes scrolling for Firefox */
|
||||
padding-bottom: 0; /* 1 */
|
||||
|
||||
> *:last-child {
|
||||
margin-bottom: $euiSize; /* 1 */
|
||||
}
|
||||
}
|
||||
|
||||
.gisLayerPanel__header {
|
||||
box-shadow: 0 $euiSize $euiSize (-$euiSize / 2) $euiColorLightestShade;
|
||||
}
|
||||
|
||||
.gisLayerPanel__footer {
|
||||
border-top: $euiBorderThin;
|
||||
box-shadow: 0 ($euiSize *-1) $euiSize (-$euiSize / 2) $euiColorLightestShade;
|
||||
}
|
|
@ -1,14 +1,9 @@
|
|||
.gisJoinItem {
|
||||
background: tintOrShade($euiColorLightShade, 85%, 0);
|
||||
border-radius: $euiBorderRadius;
|
||||
margin: $euiSizeXS 0;
|
||||
padding: $euiSizeXS;
|
||||
position: relative;
|
||||
|
||||
&:last-of-type {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
.gisJoinItem__delete {
|
||||
|
@ -19,13 +14,13 @@
|
|||
}
|
||||
|
||||
.gisJoinItem__delete {
|
||||
@include euiBottomShadowSmall;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
margin-right: -8px;
|
||||
margin-top: -12px;
|
||||
margin-right: -$euiSizeS;
|
||||
margin-top: -$euiSizeM;
|
||||
background: $euiColorEmptyShade;
|
||||
@include euiBottomShadowSmall;
|
||||
padding: $euiSizeXS;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React, { } from 'react';
|
||||
import React, { Fragment } from 'react';
|
||||
import uuid from 'uuid/v4';
|
||||
|
||||
import {
|
||||
|
@ -37,13 +37,15 @@ export function JoinEditor({ joins, layer, onChange }) {
|
|||
};
|
||||
|
||||
return (
|
||||
<Join
|
||||
key={index}
|
||||
join={joinDescriptor}
|
||||
layer={layer}
|
||||
onChange={handleOnChange}
|
||||
onRemove={handleOnRemove}
|
||||
/>
|
||||
<Fragment key={index}>
|
||||
<EuiSpacer size="m" />
|
||||
<Join
|
||||
join={joinDescriptor}
|
||||
layer={layer}
|
||||
onChange={handleOnChange}
|
||||
onRemove={handleOnRemove}
|
||||
/>
|
||||
</Fragment>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
@ -73,7 +75,6 @@ export function JoinEditor({ joins, layer, onChange }) {
|
|||
<EuiButtonIcon iconType="plusInCircle" onClick={addJoin} aria-label="Add join" title="Add join" />
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<EuiSpacer size="m" />
|
||||
|
||||
{renderJoins()}
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
.gisAlphaRange {
|
||||
// EUITODO: Fix range slider to calculate the max digits available
|
||||
.euiFieldNumber {
|
||||
max-width: 5.5em !important;
|
||||
}
|
||||
}
|
|
@ -58,7 +58,7 @@ export class SettingsPanel extends Component {
|
|||
renderZoomSliders() {
|
||||
return (
|
||||
<EuiFormRow
|
||||
helpText="Dislay layer when map is within zoom level range."
|
||||
helpText="Display layer when map is within zoom level range."
|
||||
>
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
|
@ -110,9 +110,9 @@ export class SettingsPanel extends Component {
|
|||
renderAlphaSlider() {
|
||||
return (
|
||||
<EuiFormRow
|
||||
label="Layer opacity"
|
||||
label="Layer transparency"
|
||||
>
|
||||
<div className="alphaRange">
|
||||
<div className="gisAlphaRange">
|
||||
<EuiRange
|
||||
min={.00}
|
||||
max={1.00}
|
||||
|
|
|
@ -9,58 +9,37 @@ import React from 'react';
|
|||
import {
|
||||
EuiTitle,
|
||||
EuiPanel,
|
||||
EuiSpacer
|
||||
EuiSpacer,
|
||||
EuiText
|
||||
} from '@elastic/eui';
|
||||
|
||||
export class StyleTabs extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super();
|
||||
this.state = {
|
||||
currentStyle: props.layer && props.layer.getCurrentStyle()
|
||||
};
|
||||
}
|
||||
|
||||
static getDerivedStateFromProps(nextProps, prevState) {
|
||||
const currentStyle = nextProps.layer.getCurrentStyle();
|
||||
if (currentStyle) {
|
||||
return {
|
||||
...prevState,
|
||||
currentStyle
|
||||
};
|
||||
} else {
|
||||
return {};
|
||||
export function StyleTabs({ layer, reset, updateStyle }) {
|
||||
return layer.getSupportedStyles().map((Style, index) => {
|
||||
let description;
|
||||
if (Style.description) {
|
||||
description = (
|
||||
<EuiText size="s">
|
||||
<p>{Style.description}</p>
|
||||
</EuiText>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { currentStyle } = this.state;
|
||||
const supportedStyles = this.props.layer.getSupportedStyles();
|
||||
|
||||
const styleEditors = supportedStyles.map((style, index) => {
|
||||
const seedStyle = (style.canEdit(currentStyle)) ? currentStyle : null;
|
||||
|
||||
const editorHeader = (
|
||||
<EuiTitle size="xs"><h5>{style.getDisplayName()}</h5></EuiTitle>
|
||||
);
|
||||
|
||||
const styleEditor = this.props.layer.renderStyleEditor(style, {
|
||||
handleStyleChange: (styleDescriptor) => {
|
||||
this.props.updateStyle(styleDescriptor);
|
||||
},
|
||||
style: seedStyle,
|
||||
resetStyle: () => this.props.reset()
|
||||
});
|
||||
|
||||
return (
|
||||
<EuiPanel key={index}>
|
||||
{editorHeader}
|
||||
<EuiSpacer margin="m"/>
|
||||
{styleEditor}
|
||||
</EuiPanel>
|
||||
);
|
||||
const currentStyle = layer.getCurrentStyle();
|
||||
const styleEditor = layer.renderStyleEditor(Style, {
|
||||
handleStyleChange: (styleDescriptor) => {
|
||||
updateStyle(styleDescriptor);
|
||||
},
|
||||
style: (Style.canEdit(currentStyle)) ? currentStyle : null,
|
||||
resetStyle: () => reset()
|
||||
});
|
||||
|
||||
return (styleEditors);
|
||||
}
|
||||
return (
|
||||
<EuiPanel key={index}>
|
||||
<EuiTitle size="xs"><h5>{Style.getDisplayName()}</h5></EuiTitle>
|
||||
{description}
|
||||
<EuiSpacer margin="m"/>
|
||||
{styleEditor}
|
||||
</EuiPanel>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React, { Fragment } from 'react';
|
||||
|
||||
import { StyleTabs } from './style_tabs';
|
||||
import { JoinEditor } from './join_editor';
|
||||
|
@ -12,12 +12,14 @@ import { FlyoutFooter } from './flyout_footer';
|
|||
import { SettingsPanel } from './settings_panel';
|
||||
|
||||
import {
|
||||
EuiHorizontalRule,
|
||||
EuiFlexItem,
|
||||
EuiTitle,
|
||||
EuiSpacer,
|
||||
EuiPanel,
|
||||
EuiFlexGroup,
|
||||
EuiFlyoutHeader,
|
||||
EuiFlyoutBody,
|
||||
EuiFlyoutFooter,
|
||||
EuiSpacer,
|
||||
} from '@elastic/eui';
|
||||
|
||||
export class LayerPanel extends React.Component {
|
||||
|
@ -48,9 +50,12 @@ export class LayerPanel extends React.Component {
|
|||
}
|
||||
|
||||
return (
|
||||
<EuiPanel>
|
||||
<JoinEditor/>
|
||||
</EuiPanel>
|
||||
<Fragment>
|
||||
<EuiPanel>
|
||||
<JoinEditor/>
|
||||
</EuiPanel>
|
||||
<EuiSpacer size="s" />
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -62,28 +67,29 @@ export class LayerPanel extends React.Component {
|
|||
direction="column"
|
||||
gutterSize="none"
|
||||
>
|
||||
<EuiFlexItem grow={false} className="gisViewPanel__header">
|
||||
<EuiTitle size="s" className="gisViewPanel__title">
|
||||
<h1>
|
||||
<EuiFlyoutHeader hasBorder className="gisLayerPanel__header">
|
||||
<EuiFlexGroup responsive={false} alignItems="center" gutterSize="s">
|
||||
<EuiFlexItem grow={false}>
|
||||
{selectedLayer.getIcon()}
|
||||
{this.state.displayName}
|
||||
</h1>
|
||||
</EuiTitle>
|
||||
<EuiSpacer size="m"/>
|
||||
<EuiHorizontalRule margin="none"/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiTitle size="s">
|
||||
<h2>{this.state.displayName}</h2>
|
||||
</EuiTitle>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlyoutHeader>
|
||||
|
||||
<EuiFlexItem className="gisViewPanel__body">
|
||||
<EuiFlyoutBody className="gisLayerPanel__body">
|
||||
<SettingsPanel/>
|
||||
<EuiSpacer size="s" />
|
||||
{this._renderJoinSection()}
|
||||
<StyleTabs layer={selectedLayer}/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlyoutBody>
|
||||
|
||||
<EuiFlexItem grow={false} className="gisViewPanel__footer">
|
||||
<EuiHorizontalRule margin="none"/>
|
||||
<EuiSpacer size="m"/>
|
||||
<EuiFlyoutFooter className="gisLayerPanel__footer">
|
||||
<FlyoutFooter/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlyoutFooter>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
}
|
||||
|
|
4
x-pack/plugins/gis/public/components/toasts/_toasts.scss
Normal file
4
x-pack/plugins/gis/public/components/toasts/_toasts.scss
Normal file
|
@ -0,0 +1,4 @@
|
|||
.gisLayerToast {
|
||||
margin-top: -150px !important;
|
||||
pointer-events: none;
|
||||
}
|
|
@ -10,12 +10,12 @@ export function Toasts({ layerLoadToast, clearLayerLoadToast }) {
|
|||
if (layerLoadToast === 'success') {
|
||||
toastNotifications.add({
|
||||
title: 'Layer added',
|
||||
className: 'layerToast'
|
||||
className: 'gisLayerToast'
|
||||
}) && clearLayerLoadToast();
|
||||
} else if (layerLoadToast === 'error') {
|
||||
toastNotifications.addDanger({
|
||||
title: 'Error adding layer',
|
||||
className: 'layerToast'
|
||||
className: 'gisLayerToast'
|
||||
}) && clearLayerLoadToast();
|
||||
} else {
|
||||
// Do nothing
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
@import './widget_overlay';
|
||||
@import './attribution_control/attribution_control';
|
||||
@import './layer_control/index';
|
||||
@import './view_control/view_control';
|
|
@ -0,0 +1,40 @@
|
|||
/**
|
||||
* 1. The overlay captures mouse events even if it's empty space. To counter-act this,
|
||||
* we remove all pointer events from the overlay then add them back on the
|
||||
* individual widgets.
|
||||
*/
|
||||
|
||||
.gisWidgetOverlay {
|
||||
position: absolute;
|
||||
z-index: $euiZLevel1;
|
||||
top: $euiSizeM;
|
||||
right: $euiSizeM;
|
||||
bottom: $euiSizeM;
|
||||
pointer-events: none; /* 1 */
|
||||
}
|
||||
|
||||
.gisWidgetOverlay__rightSide {
|
||||
min-width: 17rem;
|
||||
max-width: 24rem;
|
||||
}
|
||||
|
||||
.gisWidgetControl {
|
||||
max-height: 100%;
|
||||
overflow: hidden;
|
||||
padding-bottom: $euiSizeS; // ensures the scrollbar doesn't appear unnecessarily because of flex group negative margins
|
||||
border-color: transparent !important;
|
||||
flex-direction: column;
|
||||
display: flex;
|
||||
pointer-events: all; /* 1 */
|
||||
|
||||
&.gisWidgetControl-hasShadow {
|
||||
@include euiBottomShadowLarge;
|
||||
}
|
||||
|
||||
.gisWidgetControl__header {
|
||||
padding: $euiSizeS $euiSize;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
.gisAttributionControl {
|
||||
padding: 0 $euiSizeXS;
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
@import './layer_control';
|
||||
@import './layer_toc/toc_entry/toc_entry';
|
|
@ -0,0 +1,5 @@
|
|||
.gisLayerControl {
|
||||
@include euiScrollBar;
|
||||
overflow-y: auto;
|
||||
flex-basis: auto !important; // Fixes IE and ensures the layer items are visible
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
.gisTocEntry {
|
||||
padding: $euiSizeS $euiSize;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.gisTocEntry-visible {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.gisTocEntry-notVisible {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.gisTocEntry__grab:hover {
|
||||
cursor: grab;
|
||||
}
|
||||
|
|
@ -101,7 +101,7 @@ export class TOCEntry extends React.Component {
|
|||
|
||||
return (
|
||||
<div
|
||||
className="layerEntry"
|
||||
className="gisTocEntry"
|
||||
id={layer.getId()}
|
||||
data-layerid={layer.getId()}
|
||||
>
|
||||
|
@ -109,9 +109,11 @@ export class TOCEntry extends React.Component {
|
|||
gutterSize="s"
|
||||
alignItems="center"
|
||||
responsive={false}
|
||||
className={layer.isVisible() && layer.showAtZoomLevel(zoom) && !layer.dataHasLoadError() ? 'visible' : 'notvisible'}
|
||||
className={
|
||||
layer.isVisible() && layer.showAtZoomLevel(zoom) && !layer.dataHasLoadError() ? 'gisTocEntry-visible' : 'gisTocEntry-notVisible'
|
||||
}
|
||||
>
|
||||
<EuiFlexItem grow={false} className="layerEntry--visibility">
|
||||
<EuiFlexItem grow={false}>
|
||||
{visibilityIndicator}
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
|
@ -125,7 +127,7 @@ export class TOCEntry extends React.Component {
|
|||
</button>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<span className="grab"><EuiIcon type="grab" className="grab"/></span>
|
||||
<span className="gisTocEntry__grab"><EuiIcon type="grab"/></span>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
{tocDetails}
|
||||
|
|
|
@ -21,7 +21,7 @@ export function LayerControl(props) {
|
|||
</EuiButtonEmpty>);
|
||||
|
||||
return (
|
||||
<EuiPanel className="gisWidgetControl" hasShadow paddingSize="none" grow={false}>
|
||||
<EuiPanel className="gisWidgetControl gisWidgetControl-hasShadow" paddingSize="none" grow={false}>
|
||||
<EuiFlexItem className="gisWidgetControl__header" grow={false}>
|
||||
<EuiFlexGroup
|
||||
justifyContent="spaceBetween"
|
||||
|
@ -30,8 +30,8 @@ export function LayerControl(props) {
|
|||
gutterSize="none"
|
||||
>
|
||||
<EuiFlexItem>
|
||||
<EuiTitle size="s">
|
||||
<h1>Layers</h1>
|
||||
<EuiTitle size="xs">
|
||||
<h2>Layers</h2>
|
||||
</EuiTitle>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
|
@ -40,7 +40,7 @@ export function LayerControl(props) {
|
|||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
|
||||
<EuiFlexItem className="gisWidgetControl__tocHolder">
|
||||
<EuiFlexItem className="gisLayerControl">
|
||||
<LayerTOC />
|
||||
</EuiFlexItem>
|
||||
</EuiPanel>
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
/**
|
||||
* 1. The overlay captures mouse events even if it's empty space. To counter-act this,
|
||||
* we remove all pointer events from the overlay then add them back on the
|
||||
* individual widgets.
|
||||
*/
|
||||
|
||||
.gisViewControl__coordinates {
|
||||
padding: $euiSizeXS $euiSizeS;
|
||||
justify-content: center;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.gisViewControl__gotoButton {
|
||||
min-width: 0;
|
||||
pointer-events: all; /* 1 */
|
||||
}
|
|
@ -12,4 +12,4 @@
|
|||
|
||||
@import './main';
|
||||
@import './components/index';
|
||||
@import './shared/layers/layers';
|
||||
@import './shared/index';
|
||||
|
|
3
x-pack/plugins/gis/public/shared/_index.scss
Normal file
3
x-pack/plugins/gis/public/shared/_index.scss
Normal file
|
@ -0,0 +1,3 @@
|
|||
@import './components/index';
|
||||
@import './icons/color_gradient';
|
||||
@import './layers/index';
|
2
x-pack/plugins/gis/public/shared/components/_index.scss
Normal file
2
x-pack/plugins/gis/public/shared/components/_index.scss
Normal file
|
@ -0,0 +1,2 @@
|
|||
@import './map_listing';
|
||||
@import './visibility_toggle';
|
|
@ -0,0 +1,5 @@
|
|||
// Makes sure the listing page is full height with proper background
|
||||
map-listing, {
|
||||
min-height: 100vh;
|
||||
background-color: $euiColorLightestShade;
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
.gisVisibilityToggle {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
min-height: 20px;
|
||||
|
||||
.gisVisibilityToggle__body {
|
||||
line-height: 19px;
|
||||
|
||||
> * {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
}
|
||||
|
||||
.gisVisibilityToggle__content {
|
||||
svg {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.filter {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.gisVisibilityToggle__eye,
|
||||
.gisVisibilityToggle__eyeClosed,
|
||||
.gisVisibilityToggle__content {
|
||||
transition: opacity .2s ease-in-out;
|
||||
}
|
||||
|
||||
.gisVisibilityToggle__eye,
|
||||
.gisVisibilityToggle__eyeClosed {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
opacity: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.gisVisibilityToggle__input {
|
||||
z-index: 2;
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.gisVisibilityToggle__body {
|
||||
@include size($euiSize);
|
||||
display: block;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
cursor: pointer;
|
||||
color: $euiColorPrimary;
|
||||
|
||||
.gisVisibilityToggle__content {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.gisVisibilityToggle__input:checked {
|
||||
+ .gisVisibilityToggle__body > .gisVisibilityToggle__eye {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.gisVisibilityToggle__input:not(:checked) {
|
||||
+ .gisVisibilityToggle__body > .gisVisibilityToggle__content {
|
||||
opacity: 0;
|
||||
}
|
||||
+ .gisVisibilityToggle__body > .gisVisibilityToggle__eyeClosed {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -373,8 +373,8 @@ export class MapListing extends React.Component {
|
|||
|
||||
render() {
|
||||
return (
|
||||
<EuiPage data-test-subj="gisListingPage" className="gisListingPage">
|
||||
<EuiPageBody restrictWidth>
|
||||
<EuiPage data-test-subj="gisListingPage" restrictWidth>
|
||||
<EuiPageBody>
|
||||
{this.renderPageContent()}
|
||||
</EuiPageBody>
|
||||
</EuiPage>
|
||||
|
|
|
@ -22,12 +22,12 @@ export const VisibilityToggle = ({
|
|||
children,
|
||||
className
|
||||
}) => {
|
||||
const classes = classNames('visibilityToggle', className);
|
||||
const classes = classNames('gisVisibilityToggle', className);
|
||||
|
||||
return (
|
||||
<div className={classes}>
|
||||
<input
|
||||
className="euiSwitch__input"
|
||||
className="gisVisibilityToggle__input"
|
||||
name={name}
|
||||
id={id}
|
||||
type="checkbox"
|
||||
|
@ -36,18 +36,18 @@ export const VisibilityToggle = ({
|
|||
onChange={onChange}
|
||||
/>
|
||||
|
||||
<span className="visibilityToggle__body">
|
||||
<span className="visibilityToggle__eye" >
|
||||
<span className="gisVisibilityToggle__body">
|
||||
<span className="gisVisibilityToggle__eye" >
|
||||
<EuiIcon
|
||||
type={'eye'}
|
||||
/>
|
||||
</span>
|
||||
<span className="visibilityToggle__eyeClosed" >
|
||||
<span className="gisVisibilityToggle__eyeClosed" >
|
||||
<EuiIcon
|
||||
type={'eyeClosed'}
|
||||
/>
|
||||
</span>
|
||||
<span className="visibilityToggle__content">
|
||||
<span className="gisVisibilityToggle__content">
|
||||
{children}
|
||||
</span>
|
||||
</span>
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
.gisColorGradient {
|
||||
width: 100%;
|
||||
height: $euiSize;
|
||||
position: relative;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
|
@ -19,7 +19,7 @@ export const ColorGradient = ({ color }) => {
|
|||
const background = getLinearGradient(rgbColorStrings, GRADIENT_INTERVALS);
|
||||
return (
|
||||
<div
|
||||
className="colorGradient"
|
||||
className="gisColorGradient"
|
||||
style={{ background }}
|
||||
/>
|
||||
);
|
||||
|
@ -33,4 +33,4 @@ function getLinearGradient(colorStrings, intervals) {
|
|||
${Math.floor(100 * i / (intervals - 1))}%,`;
|
||||
}
|
||||
return `${linearGradient} ${colorStrings.pop()} 100%)`;
|
||||
}
|
||||
}
|
||||
|
|
2
x-pack/plugins/gis/public/shared/layers/_index.scss
Normal file
2
x-pack/plugins/gis/public/shared/layers/_index.scss
Normal file
|
@ -0,0 +1,2 @@
|
|||
@import './styles/index';
|
||||
@import './layers';
|
|
@ -77,7 +77,7 @@ export class EMSFileSource extends VectorSource {
|
|||
<p className="gisLayerDetails">
|
||||
<strong className="gisLayerDetails__label">Source </strong><span>Elastic Maps Service</span><br/>
|
||||
<strong className="gisLayerDetails__label">Id </strong><span>{this._descriptor.id}</span><br/>
|
||||
<EuiLink href={emsHotLink} target="_blank">Preview on landing page</EuiLink><br/>
|
||||
<EuiLink href={emsHotLink} target="_blank">Preview on maps.elastic.co</EuiLink><br/>
|
||||
</p>
|
||||
</EuiText>
|
||||
);
|
||||
|
|
|
@ -68,10 +68,10 @@ export class UpdateSourceEditor extends Component {
|
|||
return (
|
||||
<Fragment>
|
||||
<EuiFormRow
|
||||
label="Fields displayed in tooltip"
|
||||
label="Fields to display in tooltip"
|
||||
>
|
||||
<MultiFieldSelect
|
||||
placeholder="Select field(s)"
|
||||
placeholder="Select fields"
|
||||
value={this.props.tooltipProperties}
|
||||
onChange={this.onTooltipPropertiesSelect}
|
||||
fields={this.state.fields}
|
||||
|
@ -80,7 +80,7 @@ export class UpdateSourceEditor extends Component {
|
|||
|
||||
<EuiFormRow>
|
||||
<EuiSwitch
|
||||
label="Use map extent to filter data"
|
||||
label="Only filter for data in the visible map area"
|
||||
checked={this.props.filterByMapBounds}
|
||||
onChange={this.onFilterByMapBoundsChange}
|
||||
/>
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
@import './components/static_dynamic_styling_option';
|
||||
@import './components/vector/color/static_color_selection';
|
|
@ -0,0 +1,3 @@
|
|||
.gisStaticDynamicSylingOption__dynamicSizeHack {
|
||||
width: calc(100% - #{$euiSizeXXL + $euiSizeS});
|
||||
}
|
|
@ -64,6 +64,7 @@ export function DynamicOrdinalStyleOption({ fields, selectedOptions, onChange, t
|
|||
|
||||
const renderAdditionalOptions = () => {
|
||||
if (!_.has(selectedOptions, 'field')) {
|
||||
// TODO: Don't hide the component
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -74,10 +75,13 @@ export function DynamicOrdinalStyleOption({ fields, selectedOptions, onChange, t
|
|||
switch (type) {
|
||||
case styleTypes.COLOR_RAMP:
|
||||
return (
|
||||
<ColorRampSelector
|
||||
onChange={onAdditionalOptionsChange}
|
||||
color={_.get(selectedOptions, 'color')}
|
||||
/>
|
||||
<Fragment>
|
||||
<ColorRampSelector
|
||||
onChange={onAdditionalOptionsChange}
|
||||
color={_.get(selectedOptions, 'color')}
|
||||
/>
|
||||
<EuiSpacer size="s" />
|
||||
</Fragment>
|
||||
);
|
||||
case styleTypes.SIZE_RANGE:
|
||||
return (
|
||||
|
@ -94,6 +98,8 @@ export function DynamicOrdinalStyleOption({ fields, selectedOptions, onChange, t
|
|||
|
||||
return (
|
||||
<Fragment>
|
||||
{renderAdditionalOptions()}
|
||||
|
||||
<EuiComboBox
|
||||
selectedOptions={
|
||||
_.has(selectedOptions, 'field')
|
||||
|
@ -102,15 +108,11 @@ export function DynamicOrdinalStyleOption({ fields, selectedOptions, onChange, t
|
|||
}
|
||||
options={groupFieldsByOrigin()}
|
||||
onChange={onFieldChange}
|
||||
singleSelection={true}
|
||||
singleSelection={{ asPlainText: true }}
|
||||
isClearable={false}
|
||||
fullWidth
|
||||
placeholder="Select a field"
|
||||
/>
|
||||
|
||||
<EuiSpacer size="m" />
|
||||
|
||||
{renderAdditionalOptions()}
|
||||
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -11,22 +11,22 @@ import _ from 'lodash';
|
|||
import {
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiSwitch,
|
||||
EuiFormLabel,
|
||||
EuiSpacer
|
||||
EuiToolTip,
|
||||
EuiFormRow,
|
||||
EuiButtonToggle
|
||||
} from '@elastic/eui';
|
||||
|
||||
|
||||
export class StaticDynamicStyleSelector extends React.Component {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this._isMounted = false;
|
||||
this.state = {
|
||||
ordinalFields: null,
|
||||
isDynamic: false,
|
||||
styleDescriptor: VectorStyle.STYLE_TYPE.STATIC
|
||||
};
|
||||
// Store previous options locally so when type is toggled,
|
||||
// previous style options can be used.
|
||||
prevOptions = {
|
||||
// TODO: Move default to central location with other defaults
|
||||
color: '#e6194b'
|
||||
}
|
||||
|
||||
_canBeDynamic() {
|
||||
return this.props.ordinalFields.length > 0;
|
||||
}
|
||||
|
||||
_isDynamic() {
|
||||
|
@ -36,127 +36,91 @@ export class StaticDynamicStyleSelector extends React.Component {
|
|||
return this.props.styleDescriptor.type === VectorStyle.STYLE_TYPE.DYNAMIC;
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this._isMounted = false;
|
||||
_getStyleOptions() {
|
||||
return _.get(this.props, 'styleDescriptor.options');
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this._isMounted = true;
|
||||
this._loadOrdinalFields();
|
||||
this.setState({
|
||||
isDynamic: this._isDynamic()
|
||||
});
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
const isDynamic = this._isDynamic();
|
||||
if (this.state.isDynamic !== isDynamic) {
|
||||
this.setState({
|
||||
isDynamic
|
||||
});
|
||||
}
|
||||
if (isDynamic) {
|
||||
this._loadOrdinalFields();
|
||||
}
|
||||
}
|
||||
|
||||
async _loadOrdinalFields() {
|
||||
if (!this._isMounted) {
|
||||
return;
|
||||
}
|
||||
//check if fields are the same..
|
||||
const ordinalFields = await this.props.layer.getOrdinalFields();
|
||||
const eqls = _.isEqual(ordinalFields, this.state.ordinalFields);
|
||||
if (!eqls) {
|
||||
this.setState({
|
||||
ordinalFields
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_getStyleUpdateFunction = type => {
|
||||
const { property } = this.props;
|
||||
return options => {
|
||||
const styleDescriptor = {
|
||||
type,
|
||||
options
|
||||
};
|
||||
this.props.handlePropertyChange(property, styleDescriptor);
|
||||
_onStaticStyleChange = options => {
|
||||
const styleDescriptor = {
|
||||
type: VectorStyle.STYLE_TYPE.STATIC,
|
||||
options
|
||||
};
|
||||
};
|
||||
this.props.handlePropertyChange(this.props.property, styleDescriptor);
|
||||
}
|
||||
|
||||
_onTypeToggle = (() => {
|
||||
let lastOptions = {
|
||||
// TODO: Move default to central location with other defaults
|
||||
color: 'rgba(0,0,0,0.4)'
|
||||
_onDynamicStyleChange = options => {
|
||||
const styleDescriptor = {
|
||||
type: VectorStyle.STYLE_TYPE.DYNAMIC,
|
||||
options
|
||||
};
|
||||
const { DYNAMIC, STATIC } = VectorStyle.STYLE_TYPE;
|
||||
return ({ target }, currentOptions) => {
|
||||
const selectedStyleType = target.checked ? DYNAMIC : STATIC;
|
||||
this.setState({
|
||||
isDynamic: target.checked
|
||||
}, () => {
|
||||
if (!_.isEqual(lastOptions, currentOptions)) {
|
||||
lastOptions && this._getStyleUpdateFunction(selectedStyleType)(lastOptions);
|
||||
lastOptions = currentOptions;
|
||||
}
|
||||
});
|
||||
};
|
||||
})();
|
||||
this.props.handlePropertyChange(this.props.property, styleDescriptor);
|
||||
}
|
||||
|
||||
_renderStyleSelector(currentOptions) {
|
||||
let styleSelector;
|
||||
if (this.state.isDynamic) {
|
||||
if (this.state.ordinalFields && this.state.ordinalFields.length) {
|
||||
const DynamicSelector = this.props.DynamicSelector;
|
||||
styleSelector = (
|
||||
<DynamicSelector
|
||||
fields={this.state.ordinalFields}
|
||||
onChange={this._getStyleUpdateFunction(VectorStyle.STYLE_TYPE.DYNAMIC)}
|
||||
selectedOptions={currentOptions}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
styleSelector = null;
|
||||
}
|
||||
_onTypeToggle = () => {
|
||||
if (this._isDynamic()) {
|
||||
// toggle to static style
|
||||
this._onStaticStyleChange(this.prevOptions);
|
||||
} else {
|
||||
const StaticSelector = this.props.StaticSelector;
|
||||
styleSelector = (
|
||||
<StaticSelector
|
||||
changeOptions={this._getStyleUpdateFunction(VectorStyle.STYLE_TYPE.STATIC)}
|
||||
selectedOptions={currentOptions}
|
||||
// toggle to dynamic style
|
||||
this._onDynamicStyleChange(this.prevOptions);
|
||||
}
|
||||
|
||||
this.prevOptions = this._getStyleOptions();
|
||||
}
|
||||
|
||||
_renderStyleSelector() {
|
||||
if (this._isDynamic()) {
|
||||
const DynamicSelector = this.props.DynamicSelector;
|
||||
return (
|
||||
<DynamicSelector
|
||||
fields={this.props.ordinalFields}
|
||||
onChange={this._onDynamicStyleChange}
|
||||
selectedOptions={this._getStyleOptions()}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return styleSelector;
|
||||
}
|
||||
|
||||
_renderStaticAndDynamicStyles = () => {
|
||||
const currentOptions = _.get(this.props, 'styleDescriptor.options');
|
||||
const StaticSelector = this.props.StaticSelector;
|
||||
return (
|
||||
<div>
|
||||
<EuiFlexGroup alignItems="center">
|
||||
<EuiFlexItem grow={true}>
|
||||
<EuiFormLabel style={{ marginBottom: 0 }}>
|
||||
{this.props.name}
|
||||
</EuiFormLabel>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiSwitch
|
||||
label={'Dynamic'}
|
||||
checked={this.state.isDynamic}
|
||||
onChange={e => this._onTypeToggle(e, currentOptions)}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
|
||||
<EuiSpacer size="m" />
|
||||
{this._renderStyleSelector(currentOptions)}
|
||||
</div>
|
||||
<StaticSelector
|
||||
changeOptions={this._onStaticStyleChange}
|
||||
selectedOptions={this._getStyleOptions()}
|
||||
/>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return this._renderStaticAndDynamicStyles();
|
||||
const isDynamic = this._isDynamic();
|
||||
const dynamicTooltipContent =
|
||||
isDynamic ? "Disable dynamic styling." : "Enable dynamic styling.";
|
||||
|
||||
return (
|
||||
<EuiFlexGroup gutterSize="s">
|
||||
<EuiFlexItem className={isDynamic ? 'gisStaticDynamicSylingOption__dynamicSizeHack' : undefined}>
|
||||
<EuiFormRow label={this.props.name && this.props.name}>
|
||||
{this._renderStyleSelector()}
|
||||
</EuiFormRow>
|
||||
</EuiFlexItem>
|
||||
{this._canBeDynamic() &&
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFormRow hasEmptyLabelSpace>
|
||||
<EuiToolTip
|
||||
content={dynamicTooltipContent}
|
||||
delay="long"
|
||||
>
|
||||
<EuiButtonToggle
|
||||
label={dynamicTooltipContent}
|
||||
iconType="link"
|
||||
onChange={this._onTypeToggle}
|
||||
isEmpty={!isDynamic}
|
||||
fill={isDynamic}
|
||||
isIconOnly
|
||||
/>
|
||||
</EuiToolTip>
|
||||
</EuiFormRow>
|
||||
</EuiFlexItem>
|
||||
}
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
@import './static_color_selection';
|
|
@ -0,0 +1,7 @@
|
|||
.gisColorPicker {
|
||||
padding-top: 9px;
|
||||
|
||||
.euiColorPickerPopUp {
|
||||
z-index: $euiZLevel3;
|
||||
}
|
||||
}
|
|
@ -6,7 +6,8 @@
|
|||
|
||||
import React from 'react';
|
||||
import {
|
||||
EuiColorPicker
|
||||
EuiColorPicker,
|
||||
EuiFormControlLayout
|
||||
} from '@elastic/eui';
|
||||
|
||||
export class StaticColorSelection extends React.Component {
|
||||
|
@ -18,10 +19,14 @@ export class StaticColorSelection extends React.Component {
|
|||
});
|
||||
};
|
||||
|
||||
return (<EuiColorPicker
|
||||
onChange={onOptionChange}
|
||||
color={this.props.selectedOptions ? this.props.selectedOptions.color : null}
|
||||
className="colorPicker"
|
||||
/>);
|
||||
return (
|
||||
<EuiFormControlLayout>
|
||||
<EuiColorPicker
|
||||
onChange={onOptionChange}
|
||||
color={this.props.selectedOptions ? this.props.selectedOptions.color : null}
|
||||
className="gisColorPicker euiFieldText"
|
||||
/>
|
||||
</EuiFormControlLayout>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,23 +10,16 @@ import { StaticDynamicStyleSelector } from '../../static_dynamic_styling_option'
|
|||
import { DynamicColorSelection } from './dynamic_color_selection';
|
||||
import { StaticColorSelection } from './static_color_selection';
|
||||
|
||||
export class VectorStyleColorEditor extends React.Component {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<StaticDynamicStyleSelector
|
||||
layer={this.props.layer}
|
||||
property={this.props.styleProperty}
|
||||
name={this.props.stylePropertyName}
|
||||
styleDescriptor={this.props.styleDescriptor}
|
||||
handlePropertyChange={this.props.handlePropertyChange}
|
||||
DynamicSelector={DynamicColorSelection}
|
||||
StaticSelector={StaticColorSelection}
|
||||
/>
|
||||
);
|
||||
}
|
||||
export function VectorStyleColorEditor(props) {
|
||||
return (
|
||||
<StaticDynamicStyleSelector
|
||||
ordinalFields={props.ordinalFields}
|
||||
property={props.styleProperty}
|
||||
name={props.stylePropertyName}
|
||||
styleDescriptor={props.styleDescriptor}
|
||||
handlePropertyChange={props.handlePropertyChange}
|
||||
DynamicSelector={DynamicColorSelection}
|
||||
StaticSelector={StaticColorSelection}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -29,6 +29,12 @@ export class SizeRangeSelector extends React.Component {
|
|||
return typeof this.props.minSize === 'number' && typeof this.props.maxSize === 'number';
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (!this._areSizesValid()) {
|
||||
this._onSizeChange(DEFAULT_MIN_SIZE, DEFAULT_MAX_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
if (!this._areSizesValid()) {
|
||||
this._onSizeChange(DEFAULT_MIN_SIZE, DEFAULT_MAX_SIZE);
|
||||
|
@ -52,40 +58,38 @@ export class SizeRangeSelector extends React.Component {
|
|||
};
|
||||
|
||||
return (
|
||||
<EuiFormRow>
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
<EuiFormRow
|
||||
label="Min size"
|
||||
compressed
|
||||
>
|
||||
<EuiRange
|
||||
min={DEFAULT_MIN_SIZE}
|
||||
max={DEFAULT_MAX_SIZE}
|
||||
value={this.props.minSize.toString()}
|
||||
onChange={onMinSizeChange}
|
||||
showInput
|
||||
showRange
|
||||
/>
|
||||
</EuiFormRow>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiFormRow
|
||||
label="Max size"
|
||||
compressed
|
||||
>
|
||||
<EuiRange
|
||||
min={DEFAULT_MIN_SIZE}
|
||||
max={DEFAULT_MAX_SIZE}
|
||||
value={this.props.maxSize.toString()}
|
||||
onChange={onMaxSizeChange}
|
||||
showInput
|
||||
showRange
|
||||
/>
|
||||
</EuiFormRow>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFormRow>
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
<EuiFormRow
|
||||
label="Min size"
|
||||
compressed
|
||||
>
|
||||
<EuiRange
|
||||
min={DEFAULT_MIN_SIZE}
|
||||
max={DEFAULT_MAX_SIZE}
|
||||
value={this.props.minSize.toString()}
|
||||
onChange={onMinSizeChange}
|
||||
showInput
|
||||
showRange
|
||||
/>
|
||||
</EuiFormRow>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiFormRow
|
||||
label="Max size"
|
||||
compressed
|
||||
>
|
||||
<EuiRange
|
||||
min={DEFAULT_MIN_SIZE}
|
||||
max={DEFAULT_MAX_SIZE}
|
||||
value={this.props.maxSize.toString()}
|
||||
onChange={onMaxSizeChange}
|
||||
showInput
|
||||
showRange
|
||||
/>
|
||||
</EuiFormRow>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,23 +13,16 @@ import { StaticDynamicStyleSelector } from '../../static_dynamic_styling_option'
|
|||
import { DynamicSizeSelection } from './dynamic_size_selection';
|
||||
import { StaticSizeSelection } from './static_size_selection';
|
||||
|
||||
export class VectorStyleSizeEditor extends React.Component {
|
||||
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {};
|
||||
}
|
||||
|
||||
render() {
|
||||
return (<StaticDynamicStyleSelector
|
||||
layer={this.props.layer}
|
||||
property={this.props.styleProperty}
|
||||
name={this.props.stylePropertyName}
|
||||
styleDescriptor={this.props.styleDescriptor}
|
||||
handlePropertyChange={this.props.handlePropertyChange}
|
||||
export function VectorStyleSizeEditor(props) {
|
||||
return (
|
||||
<StaticDynamicStyleSelector
|
||||
ordinalFields={props.ordinalFields}
|
||||
property={props.styleProperty}
|
||||
name={props.stylePropertyName}
|
||||
styleDescriptor={props.styleDescriptor}
|
||||
handlePropertyChange={props.handlePropertyChange}
|
||||
DynamicSelector={DynamicSizeSelection}
|
||||
StaticSelector={StaticSizeSelection}
|
||||
/>);
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* 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 _ from 'lodash';
|
||||
import React, { Component, Fragment } from 'react';
|
||||
|
||||
import { VectorStyleColorEditor } from './color/vector_style_color_editor';
|
||||
import { VectorStyleSizeEditor } from './size/vector_style_size_editor';
|
||||
|
||||
import { EuiSpacer } from '@elastic/eui';
|
||||
|
||||
export class VectorStyleEditor extends Component {
|
||||
state = {
|
||||
ordinalFields: []
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this._isMounted = false;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this._isMounted = true;
|
||||
this._loadOrdinalFields();
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
this._loadOrdinalFields();
|
||||
}
|
||||
|
||||
async _loadOrdinalFields() {
|
||||
const ordinalFields = await this.props.layer.getOrdinalFields();
|
||||
if (!this._isMounted) {
|
||||
return;
|
||||
}
|
||||
if (!_.isEqual(ordinalFields, this.state.ordinalFields)) {
|
||||
this.setState({ ordinalFields });
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Fragment>
|
||||
|
||||
<VectorStyleColorEditor
|
||||
styleProperty="fillColor"
|
||||
stylePropertyName="Fill color"
|
||||
handlePropertyChange={this.props.handlePropertyChange}
|
||||
styleDescriptor={this.props.styleProperties.fillColor}
|
||||
ordinalFields={this.state.ordinalFields}
|
||||
/>
|
||||
|
||||
<EuiSpacer size="m" />
|
||||
|
||||
<VectorStyleColorEditor
|
||||
styleProperty="lineColor"
|
||||
stylePropertyName="Border color"
|
||||
handlePropertyChange={this.props.handlePropertyChange}
|
||||
styleDescriptor={this.props.styleProperties.lineColor}
|
||||
ordinalFields={this.state.ordinalFields}
|
||||
/>
|
||||
|
||||
<EuiSpacer size="m" />
|
||||
|
||||
<VectorStyleSizeEditor
|
||||
styleProperty="lineWidth"
|
||||
stylePropertyName="Border width"
|
||||
handlePropertyChange={this.props.handlePropertyChange}
|
||||
styleDescriptor={this.props.styleProperties.lineWidth}
|
||||
ordinalFields={this.state.ordinalFields}
|
||||
/>
|
||||
|
||||
<EuiSpacer size="m" />
|
||||
|
||||
<VectorStyleSizeEditor
|
||||
styleProperty="iconSize"
|
||||
stylePropertyName="Symbol size"
|
||||
handlePropertyChange={this.props.handlePropertyChange}
|
||||
styleDescriptor={this.props.styleProperties.iconSize}
|
||||
ordinalFields={this.state.ordinalFields}
|
||||
/>
|
||||
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -4,18 +4,13 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React, { Fragment } from 'react';
|
||||
import { VectorStyleColorEditor } from './components/vector/color/vector_style_color_editor';
|
||||
import { VectorStyleSizeEditor } from './components/vector/size/vector_style_size_editor';
|
||||
import _ from 'lodash';
|
||||
import React from 'react';
|
||||
|
||||
import {
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem
|
||||
} from '@elastic/eui';
|
||||
import { FillableCircle, FillableVector } from '../../icons/additional_layer_icons';
|
||||
import { ColorGradient } from '../../icons/color_gradient';
|
||||
import { getHexColorRangeStrings } from '../../utils/color_utils';
|
||||
import _ from 'lodash';
|
||||
import { VectorStyleEditor } from './components/vector/vector_style_editor';
|
||||
|
||||
export class VectorStyle {
|
||||
|
||||
|
@ -45,56 +40,23 @@ export class VectorStyle {
|
|||
return 'Vector style';
|
||||
}
|
||||
|
||||
static description = 'Link styles to property values for data driven styling.';
|
||||
|
||||
static renderEditor({ handleStyleChange, style, layer }) {
|
||||
|
||||
const properties = { ...style.getProperties() };
|
||||
const styleProperties = { ...style.getProperties() };
|
||||
const handlePropertyChange = (propertyName, settings) => {
|
||||
properties[propertyName] = settings;//override single property, but preserve the rest
|
||||
const vectorStyleDescriptor = VectorStyle.createDescriptor(properties);
|
||||
styleProperties[propertyName] = settings;//override single property, but preserve the rest
|
||||
const vectorStyleDescriptor = VectorStyle.createDescriptor(styleProperties);
|
||||
handleStyleChange(vectorStyleDescriptor);
|
||||
};
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<EuiFlexGroup direction="column">
|
||||
<EuiFlexItem>
|
||||
<VectorStyleColorEditor
|
||||
styleProperty={'fillColor'}
|
||||
stylePropertyName={"Fill color"}
|
||||
handlePropertyChange={handlePropertyChange}
|
||||
styleDescriptor={properties.fillColor}
|
||||
layer={layer}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<VectorStyleColorEditor
|
||||
styleProperty={'lineColor'}
|
||||
stylePropertyName={"Line color"}
|
||||
handlePropertyChange={handlePropertyChange}
|
||||
styleDescriptor={properties.lineColor}
|
||||
layer={layer}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<VectorStyleSizeEditor
|
||||
styleProperty={'lineWidth'}
|
||||
stylePropertyName={"Line width"}
|
||||
handlePropertyChange={handlePropertyChange}
|
||||
styleDescriptor={properties.lineWidth}
|
||||
layer={layer}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<VectorStyleSizeEditor
|
||||
styleProperty={'iconSize'}
|
||||
stylePropertyName={"Icon size"}
|
||||
handlePropertyChange={handlePropertyChange}
|
||||
styleDescriptor={properties.iconSize}
|
||||
layer={layer}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</Fragment>
|
||||
<VectorStyleEditor
|
||||
handlePropertyChange={handlePropertyChange}
|
||||
styleProperties={styleProperties}
|
||||
layer={layer}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue