mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
* rename StaticDynamicStyleSelector to StaticDynamicStyleRow * clean up color styling * refactor size editing * more clean up * remove console statements * ensure default styles exist when loading saved objects * do not call callback when range is invalid because bad input in text field
This commit is contained in:
parent
32be17749e
commit
5f7a27165c
18 changed files with 536 additions and 452 deletions
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* 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, { Fragment } from 'react';
|
||||
|
||||
import { EuiRange, EuiFormErrorText } from '@elastic/eui';
|
||||
|
||||
function isWithinRange(min, max, value) {
|
||||
if (value >= min && value <= max) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO move to EUI
|
||||
// Wrapper around EuiRange that ensures onChange callback is only called when value is number and within min/max
|
||||
export class ValidatedRange extends React.Component {
|
||||
|
||||
state = {};
|
||||
|
||||
static getDerivedStateFromProps(nextProps, prevState) {
|
||||
if (nextProps.value !== prevState.prevValue) {
|
||||
return {
|
||||
value: nextProps.value,
|
||||
prevValue: nextProps.value,
|
||||
isValid: isWithinRange(nextProps.min, nextProps.max, nextProps.value),
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
_onRangeChange = (e) => {
|
||||
const sanitizedValue = parseInt(e.target.value, 10);
|
||||
let newValue = isNaN(sanitizedValue) ? '' : sanitizedValue;
|
||||
// work around for https://github.com/elastic/eui/issues/1458
|
||||
// TODO remove once above EUI issue is resolved
|
||||
newValue = Number(newValue);
|
||||
|
||||
const isValid = isWithinRange(this.props.min, this.props.max, newValue)
|
||||
? true
|
||||
: false;
|
||||
|
||||
this.setState({
|
||||
value: newValue,
|
||||
isValid,
|
||||
});
|
||||
|
||||
if (isValid) {
|
||||
this.props.onChange(newValue);
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
let errorMessage;
|
||||
if (!this.state.isValid) {
|
||||
errorMessage = (
|
||||
<EuiFormErrorText>
|
||||
{`Must be between ${this.props.min} and ${this.props.max}`}
|
||||
</EuiFormErrorText>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<EuiRange
|
||||
min={this.props.min}
|
||||
max={this.props.max}
|
||||
value={this.state.value.toString()}
|
||||
onChange={this._onRangeChange}
|
||||
showInput
|
||||
showRange
|
||||
/>
|
||||
{errorMessage}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,2 +1,2 @@
|
|||
@import './components/static_dynamic_styling_option';
|
||||
@import './components/static_dynamic_style_row';
|
||||
@import './components/vector/color/static_color_selection';
|
||||
|
|
|
@ -1,129 +0,0 @@
|
|||
/*
|
||||
* 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 PropTypes from 'prop-types';
|
||||
import React, { Fragment } from 'react';
|
||||
|
||||
import {
|
||||
EuiComboBox,
|
||||
EuiSpacer
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { ColorRampSelector } from './vector/color/color_ramp_selector';
|
||||
import { SizeRangeSelector } from './vector/size/size_range_selector';
|
||||
|
||||
export const styleTypes = {
|
||||
COLOR_RAMP: 'color_ramp',
|
||||
SIZE_RANGE: 'size_range'
|
||||
};
|
||||
|
||||
export function DynamicOrdinalStyleOption({ fields, selectedOptions, onChange, type }) {
|
||||
|
||||
const onFieldChange = (selectedFields) => {
|
||||
const field = selectedFields.length > 0 ? selectedFields[0].value : null;
|
||||
onChange({ field });
|
||||
};
|
||||
|
||||
const groupFieldsByOrigin = () => {
|
||||
const fieldsByOriginMap = new Map();
|
||||
fields
|
||||
.forEach(field => {
|
||||
if (fieldsByOriginMap.has(field.origin)) {
|
||||
const fieldsList = fieldsByOriginMap.get(field.origin);
|
||||
fieldsList.push(field);
|
||||
fieldsByOriginMap.set(field.origin, fieldsList);
|
||||
} else {
|
||||
fieldsByOriginMap.set(field.origin, [field]);
|
||||
}
|
||||
});
|
||||
|
||||
const optionGroups = [];
|
||||
fieldsByOriginMap.forEach((fieldsList, fieldOrigin) => {
|
||||
optionGroups.push({
|
||||
label: fieldOrigin,
|
||||
options: fieldsList
|
||||
.map(field => {
|
||||
return { value: field, label: field.label };
|
||||
})
|
||||
.sort((a, b) => {
|
||||
return a.label.toLowerCase().localeCompare(b.label.toLowerCase());
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
optionGroups.sort((a, b) => {
|
||||
return a.label.toLowerCase().localeCompare(b.label.toLowerCase());
|
||||
});
|
||||
|
||||
return optionGroups;
|
||||
};
|
||||
|
||||
const renderAdditionalOptions = () => {
|
||||
if (!_.has(selectedOptions, 'field')) {
|
||||
// TODO: Don't hide the component
|
||||
return;
|
||||
}
|
||||
|
||||
const onAdditionalOptionsChange = (additionalOptions) => {
|
||||
onChange({ field: selectedOptions.field, ...additionalOptions });
|
||||
};
|
||||
|
||||
switch (type) {
|
||||
case styleTypes.COLOR_RAMP:
|
||||
return (
|
||||
<Fragment>
|
||||
<ColorRampSelector
|
||||
onChange={onAdditionalOptionsChange}
|
||||
color={_.get(selectedOptions, 'color')}
|
||||
/>
|
||||
<EuiSpacer size="s" />
|
||||
</Fragment>
|
||||
);
|
||||
case styleTypes.SIZE_RANGE:
|
||||
return (
|
||||
<SizeRangeSelector
|
||||
onChange={onAdditionalOptionsChange}
|
||||
minSize={_.get(selectedOptions, 'minSize')}
|
||||
maxSize={_.get(selectedOptions, 'maxSize')}
|
||||
/>
|
||||
);
|
||||
default:
|
||||
throw new Error(`Unhandled type ${type}`);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{renderAdditionalOptions()}
|
||||
|
||||
<EuiComboBox
|
||||
selectedOptions={
|
||||
_.has(selectedOptions, 'field')
|
||||
? [{ label: selectedOptions.field.label, value: selectedOptions.field }]
|
||||
: []
|
||||
}
|
||||
options={groupFieldsByOrigin()}
|
||||
onChange={onFieldChange}
|
||||
singleSelection={{ asPlainText: true }}
|
||||
isClearable={false}
|
||||
fullWidth
|
||||
placeholder="Select a field"
|
||||
/>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
DynamicOrdinalStyleOption.propTypes = {
|
||||
selectedOptions: PropTypes.object,
|
||||
fields: PropTypes.array.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
type: PropTypes.oneOf(
|
||||
Object.keys(styleTypes).map(styleType => {
|
||||
return styleTypes[styleType];
|
||||
})
|
||||
).isRequired,
|
||||
};
|
|
@ -16,14 +16,12 @@ import {
|
|||
EuiButtonToggle
|
||||
} from '@elastic/eui';
|
||||
|
||||
export class StaticDynamicStyleSelector extends React.Component {
|
||||
export class StaticDynamicStyleRow extends React.Component {
|
||||
|
||||
// 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'
|
||||
}
|
||||
prevStaticStyleOptions = this.props.defaultStaticStyleOptions;
|
||||
prevDynamicStyleOptions = this.props.defaultDynamicStyleOptions;
|
||||
|
||||
_canBeDynamic() {
|
||||
return this.props.ordinalFields.length > 0;
|
||||
|
@ -58,14 +56,17 @@ export class StaticDynamicStyleSelector extends React.Component {
|
|||
|
||||
_onTypeToggle = () => {
|
||||
if (this._isDynamic()) {
|
||||
// preserve current dynmaic style
|
||||
this.prevDynamicStyleOptions = this._getStyleOptions();
|
||||
// toggle to static style
|
||||
this._onStaticStyleChange(this.prevOptions);
|
||||
} else {
|
||||
// toggle to dynamic style
|
||||
this._onDynamicStyleChange(this.prevOptions);
|
||||
this._onStaticStyleChange(this.prevStaticStyleOptions);
|
||||
return;
|
||||
}
|
||||
|
||||
this.prevOptions = this._getStyleOptions();
|
||||
// preserve current static style
|
||||
this.prevStaticStyleOptions = this._getStyleOptions();
|
||||
// toggle to dynamic style
|
||||
this._onDynamicStyleChange(this.prevDynamicStyleOptions);
|
||||
}
|
||||
|
||||
_renderStyleSelector() {
|
||||
|
@ -73,9 +74,9 @@ export class StaticDynamicStyleSelector extends React.Component {
|
|||
const DynamicSelector = this.props.DynamicSelector;
|
||||
return (
|
||||
<DynamicSelector
|
||||
fields={this.props.ordinalFields}
|
||||
ordinalFields={this.props.ordinalFields}
|
||||
onChange={this._onDynamicStyleChange}
|
||||
selectedOptions={this._getStyleOptions()}
|
||||
styleOptions={this._getStyleOptions()}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -83,8 +84,8 @@ export class StaticDynamicStyleSelector extends React.Component {
|
|||
const StaticSelector = this.props.StaticSelector;
|
||||
return (
|
||||
<StaticSelector
|
||||
changeOptions={this._onStaticStyleChange}
|
||||
selectedOptions={this._getStyleOptions()}
|
||||
onChange={this._onStaticStyleChange}
|
||||
styleOptions={this._getStyleOptions()}
|
||||
/>
|
||||
);
|
||||
}
|
|
@ -7,43 +7,33 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import {
|
||||
EuiSuperSelect
|
||||
} from '@elastic/eui';
|
||||
import { EuiSuperSelect } from '@elastic/eui';
|
||||
import { vislibColorMaps } from 'ui/vislib/components/color/colormaps';
|
||||
import { ColorGradient } from '../../../../../icons/color_gradient';
|
||||
|
||||
const COLOR_GRADIENTS = Object.keys(vislibColorMaps).map(colorKey => ({
|
||||
export const COLOR_GRADIENTS = Object.keys(vislibColorMaps).map(colorKey => ({
|
||||
value: colorKey,
|
||||
text: colorKey,
|
||||
inputDisplay: <ColorGradient color={colorKey}/>
|
||||
}));
|
||||
|
||||
const onColorRampChange = onChange =>
|
||||
selectedColorRampString => {
|
||||
export function ColorRampSelect({ color, onChange }) {
|
||||
const onColorRampChange = (selectedColorRampString) => {
|
||||
onChange({
|
||||
color: selectedColorRampString
|
||||
});
|
||||
};
|
||||
|
||||
export function ColorRampSelector({ color, onChange }) {
|
||||
if (color) {
|
||||
return (
|
||||
<EuiSuperSelect
|
||||
options={COLOR_GRADIENTS}
|
||||
onChange={onColorRampChange(onChange)}
|
||||
valueOfSelected={color}
|
||||
hasDividers={true}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
// Default to first color gradient
|
||||
onColorRampChange(onChange)(COLOR_GRADIENTS[0].value);
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<EuiSuperSelect
|
||||
options={COLOR_GRADIENTS}
|
||||
onChange={onColorRampChange}
|
||||
valueOfSelected={color}
|
||||
hasDividers={true}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
ColorRampSelector.propTypes = {
|
||||
color: PropTypes.string,
|
||||
ColorRampSelect.propTypes = {
|
||||
color: PropTypes.string.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
};
|
|
@ -4,20 +4,43 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { DynamicOrdinalStyleOption, styleTypes } from '../../dynamic_ordinal_styling_option';
|
||||
import _ from 'lodash';
|
||||
import React, { Fragment } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { FieldSelect, fieldShape } from '../field_select';
|
||||
import { ColorRampSelect } from './color_ramp_select';
|
||||
import { EuiSpacer } from '@elastic/eui';
|
||||
|
||||
export class DynamicColorSelection extends React.Component {
|
||||
export function DynamicColorSelection({ ordinalFields, onChange, styleOptions }) {
|
||||
const onFieldChange = ({ field }) => {
|
||||
onChange({ ...styleOptions, field });
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<DynamicOrdinalStyleOption
|
||||
fields={this.props.fields}
|
||||
selectedOptions={this.props.selectedOptions}
|
||||
type={styleTypes.COLOR_RAMP}
|
||||
onChange={this.props.onChange}
|
||||
const onColorChange = ({ color }) => {
|
||||
onChange({ ...styleOptions, color });
|
||||
};
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<ColorRampSelect
|
||||
onChange={onColorChange}
|
||||
color={styleOptions.color}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
<EuiSpacer size="s" />
|
||||
<FieldSelect
|
||||
fields={ordinalFields}
|
||||
selectedField={_.get(styleOptions, 'field')}
|
||||
onChange={onFieldChange}
|
||||
/>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
DynamicColorSelection.propTypes = {
|
||||
ordinalFields: PropTypes.arrayOf(fieldShape).isRequired,
|
||||
styleOptions: PropTypes.shape({
|
||||
color: PropTypes.string.isRequired,
|
||||
field: fieldShape,
|
||||
}).isRequired,
|
||||
onChange: PropTypes.func.isRequired
|
||||
};
|
||||
|
|
|
@ -5,28 +5,31 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
EuiColorPicker,
|
||||
EuiFormControlLayout
|
||||
} from '@elastic/eui';
|
||||
|
||||
export class StaticColorSelection extends React.Component {
|
||||
render() {
|
||||
export function StaticColorSelection({ onChange, styleOptions }) {
|
||||
const onColorChange = color => {
|
||||
onChange({ color });
|
||||
};
|
||||
|
||||
const onOptionChange = color => {
|
||||
this.props.changeOptions({
|
||||
color
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<EuiFormControlLayout>
|
||||
<EuiColorPicker
|
||||
onChange={onOptionChange}
|
||||
color={this.props.selectedOptions ? this.props.selectedOptions.color : null}
|
||||
className="gisColorPicker euiFieldText"
|
||||
/>
|
||||
</EuiFormControlLayout>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<EuiFormControlLayout>
|
||||
<EuiColorPicker
|
||||
onChange={onColorChange}
|
||||
color={styleOptions.color}
|
||||
className="gisColorPicker euiFieldText"
|
||||
/>
|
||||
</EuiFormControlLayout>
|
||||
);
|
||||
}
|
||||
|
||||
StaticColorSelection.propTypes = {
|
||||
styleOptions: PropTypes.shape({
|
||||
color: PropTypes.string.isRequired,
|
||||
}).isRequired,
|
||||
onChange: PropTypes.func.isRequired
|
||||
};
|
||||
|
|
|
@ -6,13 +6,13 @@
|
|||
|
||||
import React from 'react';
|
||||
|
||||
import { StaticDynamicStyleSelector } from '../../static_dynamic_styling_option';
|
||||
import { DynamicColorSelection } from './dynamic_color_selection';
|
||||
import { StaticColorSelection } from './static_color_selection';
|
||||
import { StaticDynamicStyleRow } from '../../static_dynamic_style_row';
|
||||
import { DynamicColorSelection } from './dynamic_color_selection';
|
||||
import { StaticColorSelection } from './static_color_selection';
|
||||
|
||||
export function VectorStyleColorEditor(props) {
|
||||
return (
|
||||
<StaticDynamicStyleSelector
|
||||
<StaticDynamicStyleRow
|
||||
ordinalFields={props.ordinalFields}
|
||||
property={props.styleProperty}
|
||||
name={props.stylePropertyName}
|
||||
|
@ -20,6 +20,8 @@ export function VectorStyleColorEditor(props) {
|
|||
handlePropertyChange={props.handlePropertyChange}
|
||||
DynamicSelector={DynamicColorSelection}
|
||||
StaticSelector={StaticColorSelection}
|
||||
defaultDynamicStyleOptions={props.defaultDynamicStyleOptions}
|
||||
defaultStaticStyleOptions={props.defaultStaticStyleOptions}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* 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 PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
|
||||
import { EuiComboBox } from '@elastic/eui';
|
||||
|
||||
export function FieldSelect({ fields, selectedField, onChange }) {
|
||||
|
||||
const onFieldChange = (selectedFields) => {
|
||||
onChange({
|
||||
field: selectedFields.length > 0 ? selectedFields[0].value : null
|
||||
});
|
||||
};
|
||||
|
||||
const groupFieldsByOrigin = () => {
|
||||
const fieldsByOriginMap = new Map();
|
||||
fields
|
||||
.forEach(field => {
|
||||
if (fieldsByOriginMap.has(field.origin)) {
|
||||
const fieldsList = fieldsByOriginMap.get(field.origin);
|
||||
fieldsList.push(field);
|
||||
fieldsByOriginMap.set(field.origin, fieldsList);
|
||||
} else {
|
||||
fieldsByOriginMap.set(field.origin, [field]);
|
||||
}
|
||||
});
|
||||
|
||||
const optionGroups = [];
|
||||
fieldsByOriginMap.forEach((fieldsList, fieldOrigin) => {
|
||||
optionGroups.push({
|
||||
label: fieldOrigin,
|
||||
options: fieldsList
|
||||
.map(field => {
|
||||
return { value: field, label: field.label };
|
||||
})
|
||||
.sort((a, b) => {
|
||||
return a.label.toLowerCase().localeCompare(b.label.toLowerCase());
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
optionGroups.sort((a, b) => {
|
||||
return a.label.toLowerCase().localeCompare(b.label.toLowerCase());
|
||||
});
|
||||
|
||||
return optionGroups;
|
||||
};
|
||||
|
||||
const selectedOptions = selectedField
|
||||
? [{ label: selectedField.label, value: selectedField }]
|
||||
: [];
|
||||
|
||||
return (
|
||||
<EuiComboBox
|
||||
selectedOptions={selectedOptions}
|
||||
options={groupFieldsByOrigin()}
|
||||
onChange={onFieldChange}
|
||||
singleSelection={{ asPlainText: true }}
|
||||
isClearable={false}
|
||||
fullWidth
|
||||
placeholder="Select a field"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export const fieldShape = PropTypes.shape({
|
||||
name: PropTypes.string.isRequired,
|
||||
label: PropTypes.string.isRequired,
|
||||
origin: PropTypes.oneOf(['join', 'source']).isRequired
|
||||
});
|
||||
|
||||
FieldSelect.propTypes = {
|
||||
selectedField: fieldShape,
|
||||
fields: PropTypes.arrayOf(fieldShape).isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
};
|
|
@ -4,21 +4,45 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import _ from 'lodash';
|
||||
import React, { Fragment } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { FieldSelect, fieldShape } from '../field_select';
|
||||
import { SizeRangeSelector } from './size_range_selector';
|
||||
import { EuiSpacer } from '@elastic/eui';
|
||||
|
||||
import { DynamicOrdinalStyleOption, styleTypes } from '../../dynamic_ordinal_styling_option';
|
||||
export function DynamicSizeSelection({ ordinalFields, styleOptions, onChange }) {
|
||||
const onFieldChange = ({ field }) => {
|
||||
onChange({ ...styleOptions, field });
|
||||
};
|
||||
|
||||
const onSizeRangeChange = ({ minSize, maxSize }) => {
|
||||
onChange({ ...styleOptions, minSize, maxSize });
|
||||
};
|
||||
|
||||
export class DynamicSizeSelection extends React.Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<DynamicOrdinalStyleOption
|
||||
fields={this.props.fields}
|
||||
selectedOptions={this.props.selectedOptions}
|
||||
type={styleTypes.SIZE_RANGE}
|
||||
onChange={this.props.onChange}
|
||||
return (
|
||||
<Fragment>
|
||||
<SizeRangeSelector
|
||||
onChange={onSizeRangeChange}
|
||||
minSize={styleOptions.minSize}
|
||||
maxSize={styleOptions.maxSize}
|
||||
/>
|
||||
);
|
||||
}
|
||||
<EuiSpacer size="s" />
|
||||
<FieldSelect
|
||||
fields={ordinalFields}
|
||||
selectedField={_.get(styleOptions, 'field')}
|
||||
onChange={onFieldChange}
|
||||
/>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
DynamicSizeSelection.propTypes = {
|
||||
ordinalFields: PropTypes.arrayOf(fieldShape).isRequired,
|
||||
styleOptions: PropTypes.shape({
|
||||
minSize: PropTypes.number.isRequired,
|
||||
maxSize: PropTypes.number.isRequired,
|
||||
field: fieldShape,
|
||||
}).isRequired,
|
||||
onChange: PropTypes.func.isRequired
|
||||
};
|
||||
|
|
|
@ -10,93 +10,61 @@ import {
|
|||
EuiFormRow,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiRange
|
||||
} from '@elastic/eui';
|
||||
import { ValidatedRange } from '../../../../../components/validated_range';
|
||||
import { DEFAULT_MIN_SIZE, DEFAULT_MAX_SIZE } from '../../../vector_style_defaults';
|
||||
|
||||
const DEFAULT_MIN_SIZE = 1;
|
||||
const DEFAULT_MAX_SIZE = 64;
|
||||
export function SizeRangeSelector({ minSize, maxSize, onChange }) {
|
||||
|
||||
export class SizeRangeSelector extends React.Component {
|
||||
|
||||
_onSizeChange = (min, max) => {
|
||||
this.props.onChange({
|
||||
const onSizeChange = (min, max) => {
|
||||
onChange({
|
||||
minSize: min,
|
||||
maxSize: max
|
||||
});
|
||||
};
|
||||
|
||||
_areSizesValid() {
|
||||
return typeof this.props.minSize === 'number' && typeof this.props.maxSize === 'number';
|
||||
}
|
||||
const onMinSizeChange = (updatedMinSize) => {
|
||||
onSizeChange(updatedMinSize, updatedMinSize > maxSize ? updatedMinSize : maxSize);
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
if (!this._areSizesValid()) {
|
||||
this._onSizeChange(DEFAULT_MIN_SIZE, DEFAULT_MAX_SIZE);
|
||||
}
|
||||
}
|
||||
const onMaxSizeChange = (updatedMaxSize) => {
|
||||
onSizeChange(updatedMaxSize < minSize ? updatedMaxSize : minSize, updatedMaxSize);
|
||||
};
|
||||
|
||||
componentDidUpdate() {
|
||||
if (!this._areSizesValid()) {
|
||||
this._onSizeChange(DEFAULT_MIN_SIZE, DEFAULT_MAX_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
if (!this._areSizesValid()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const onMinSizeChange = (e) => {
|
||||
const updatedMinSize = parseInt(e.target.value, 10);
|
||||
this._onSizeChange(updatedMinSize, updatedMinSize > this.props.maxSize ? updatedMinSize : this.props.maxSize);
|
||||
};
|
||||
|
||||
const onMaxSizeChange = (e) => {
|
||||
const updatedMaxSize = parseInt(e.target.value, 10);
|
||||
this._onSizeChange(updatedMaxSize < this.props.minSize ? updatedMaxSize : this.props.minSize, updatedMaxSize);
|
||||
};
|
||||
|
||||
return (
|
||||
<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>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
<EuiFormRow
|
||||
label="Min size"
|
||||
compressed
|
||||
>
|
||||
<ValidatedRange
|
||||
min={DEFAULT_MIN_SIZE}
|
||||
max={DEFAULT_MAX_SIZE}
|
||||
value={minSize}
|
||||
onChange={onMinSizeChange}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiFormRow
|
||||
label="Max size"
|
||||
compressed
|
||||
>
|
||||
<ValidatedRange
|
||||
min={DEFAULT_MIN_SIZE}
|
||||
max={DEFAULT_MAX_SIZE}
|
||||
value={maxSize}
|
||||
onChange={onMaxSizeChange}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
SizeRangeSelector.propTypes = {
|
||||
minSize: PropTypes.number,
|
||||
maxSize: PropTypes.number,
|
||||
minSize: PropTypes.number.isRequired,
|
||||
maxSize: PropTypes.number.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
};
|
||||
|
|
|
@ -5,38 +5,28 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { ValidatedRange } from '../../../../../components/validated_range';
|
||||
|
||||
import {
|
||||
EuiRange
|
||||
} from '@elastic/eui';
|
||||
export function StaticSizeSelection({ onChange, styleOptions }) {
|
||||
|
||||
export class StaticSizeSelection extends React.Component {
|
||||
const onSizeChange = (size) => {
|
||||
onChange({ size });
|
||||
};
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {};
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
const onChange = (event) => {
|
||||
const size = parseInt(event.target.value, 10);
|
||||
this.props.changeOptions({
|
||||
size: size
|
||||
});
|
||||
};
|
||||
|
||||
const selectedValue = (
|
||||
this.props.selectedOptions && typeof this.props.selectedOptions.size === 'number'
|
||||
) ? this.props.selectedOptions.size : 0;
|
||||
return (
|
||||
<EuiRange
|
||||
min={0}
|
||||
max={100}
|
||||
value={selectedValue.toString()}
|
||||
onChange={onChange}
|
||||
showInput
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<ValidatedRange
|
||||
min={0}
|
||||
max={100}
|
||||
value={styleOptions.size}
|
||||
onChange={onSizeChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
StaticSizeSelection.propTypes = {
|
||||
styleOptions: PropTypes.shape({
|
||||
size: PropTypes.number.isRequired,
|
||||
}).isRequired,
|
||||
onChange: PropTypes.func.isRequired
|
||||
};
|
||||
|
|
|
@ -6,16 +6,13 @@
|
|||
|
||||
import React from 'react';
|
||||
|
||||
import {
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { StaticDynamicStyleSelector } from '../../static_dynamic_styling_option';
|
||||
import { StaticDynamicStyleRow } from '../../static_dynamic_style_row';
|
||||
import { DynamicSizeSelection } from './dynamic_size_selection';
|
||||
import { StaticSizeSelection } from './static_size_selection';
|
||||
|
||||
export function VectorStyleSizeEditor(props) {
|
||||
return (
|
||||
<StaticDynamicStyleSelector
|
||||
<StaticDynamicStyleRow
|
||||
ordinalFields={props.ordinalFields}
|
||||
property={props.styleProperty}
|
||||
name={props.stylePropertyName}
|
||||
|
@ -23,6 +20,8 @@ export function VectorStyleSizeEditor(props) {
|
|||
handlePropertyChange={props.handlePropertyChange}
|
||||
DynamicSelector={DynamicSizeSelection}
|
||||
StaticSelector={StaticSizeSelection}
|
||||
defaultDynamicStyleOptions={props.defaultDynamicStyleOptions}
|
||||
defaultStaticStyleOptions={props.defaultStaticStyleOptions}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -9,12 +9,19 @@ import React, { Component, Fragment } from 'react';
|
|||
|
||||
import { VectorStyleColorEditor } from './color/vector_style_color_editor';
|
||||
import { VectorStyleSizeEditor } from './size/vector_style_size_editor';
|
||||
import { getDefaultDynamicProperties, getDefaultStaticProperties } from '../../vector_style_defaults';
|
||||
|
||||
import { EuiSpacer } from '@elastic/eui';
|
||||
|
||||
export class VectorStyleEditor extends Component {
|
||||
state = {
|
||||
ordinalFields: []
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
ordinalFields: [],
|
||||
defaultDynamicProperties: getDefaultDynamicProperties(),
|
||||
defaultStaticProperties: getDefaultStaticProperties()
|
||||
};
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
@ -50,6 +57,8 @@ export class VectorStyleEditor extends Component {
|
|||
handlePropertyChange={this.props.handlePropertyChange}
|
||||
styleDescriptor={this.props.styleProperties.fillColor}
|
||||
ordinalFields={this.state.ordinalFields}
|
||||
defaultStaticStyleOptions={this.state.defaultStaticProperties.fillColor.options}
|
||||
defaultDynamicStyleOptions={this.state.defaultDynamicProperties.fillColor.options}
|
||||
/>
|
||||
|
||||
<EuiSpacer size="m" />
|
||||
|
@ -60,6 +69,8 @@ export class VectorStyleEditor extends Component {
|
|||
handlePropertyChange={this.props.handlePropertyChange}
|
||||
styleDescriptor={this.props.styleProperties.lineColor}
|
||||
ordinalFields={this.state.ordinalFields}
|
||||
defaultStaticStyleOptions={this.state.defaultStaticProperties.lineColor.options}
|
||||
defaultDynamicStyleOptions={this.state.defaultDynamicProperties.lineColor.options}
|
||||
/>
|
||||
|
||||
<EuiSpacer size="m" />
|
||||
|
@ -70,6 +81,8 @@ export class VectorStyleEditor extends Component {
|
|||
handlePropertyChange={this.props.handlePropertyChange}
|
||||
styleDescriptor={this.props.styleProperties.lineWidth}
|
||||
ordinalFields={this.state.ordinalFields}
|
||||
defaultStaticStyleOptions={this.state.defaultStaticProperties.lineWidth.options}
|
||||
defaultDynamicStyleOptions={this.state.defaultDynamicProperties.lineWidth.options}
|
||||
/>
|
||||
|
||||
<EuiSpacer size="m" />
|
||||
|
@ -80,6 +93,8 @@ export class VectorStyleEditor extends Component {
|
|||
handlePropertyChange={this.props.handlePropertyChange}
|
||||
styleDescriptor={this.props.styleProperties.iconSize}
|
||||
ordinalFields={this.state.ordinalFields}
|
||||
defaultStaticStyleOptions={this.state.defaultStaticProperties.iconSize.options}
|
||||
defaultDynamicStyleOptions={this.state.defaultDynamicProperties.iconSize.options}
|
||||
/>
|
||||
|
||||
</Fragment>
|
||||
|
|
|
@ -11,6 +11,7 @@ import { FillableCircle, FillableVector } from '../../icons/additional_layer_ico
|
|||
import { ColorGradient } from '../../icons/color_gradient';
|
||||
import { getHexColorRangeStrings } from '../../utils/color_utils';
|
||||
import { VectorStyleEditor } from './components/vector/vector_style_editor';
|
||||
import { DEFAULT_ALPHA_VALUE, getDefaultStaticProperties } from './vector_style_defaults';
|
||||
|
||||
export class VectorStyle {
|
||||
|
||||
|
@ -22,7 +23,7 @@ export class VectorStyle {
|
|||
}
|
||||
|
||||
constructor(descriptor) {
|
||||
this._descriptor = descriptor;
|
||||
this._descriptor = VectorStyle.createDescriptor(descriptor.properties);
|
||||
}
|
||||
|
||||
static canEdit(styleInstance) {
|
||||
|
@ -30,12 +31,17 @@ export class VectorStyle {
|
|||
}
|
||||
|
||||
static createDescriptor(properties) {
|
||||
const defaultStyleProperties = getDefaultStaticProperties();
|
||||
return {
|
||||
type: VectorStyle.type,
|
||||
properties: properties
|
||||
properties: { ...defaultStyleProperties, ...properties }
|
||||
};
|
||||
}
|
||||
|
||||
static createDefaultStyleProperties(mapColors) {
|
||||
return getDefaultStaticProperties(mapColors);
|
||||
}
|
||||
|
||||
static getDisplayName() {
|
||||
return 'Vector style';
|
||||
}
|
||||
|
@ -81,15 +87,6 @@ export class VectorStyle {
|
|||
return this._descriptor.properties || {};
|
||||
}
|
||||
|
||||
getHexColor(colorProperty) {
|
||||
|
||||
if (!this._descriptor.properties[colorProperty] || !this._descriptor.properties[colorProperty].options) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this._descriptor.properties[colorProperty].options.color;
|
||||
}
|
||||
|
||||
_isPropertyDynamic(property) {
|
||||
if (!this._descriptor.properties[property]) {
|
||||
return false;
|
||||
|
@ -218,90 +215,78 @@ export class VectorStyle {
|
|||
return updateStatuses.some(r => r === true);
|
||||
}
|
||||
|
||||
_getMBDataDrivenColor(property) {
|
||||
|
||||
if (!this._descriptor.properties[property] || !this._descriptor.properties[property].options) {
|
||||
return null;
|
||||
}
|
||||
const { field, color } = this._descriptor.properties[property].options;
|
||||
if (field && color) {
|
||||
const colorRange = getHexColorRangeStrings(color, 8)
|
||||
.reduce((accu, curColor, idx, srcArr) => {
|
||||
accu = [ ...accu, idx / srcArr.length, curColor ];
|
||||
return accu;
|
||||
}, []);
|
||||
const originalFieldName = this._descriptor.properties[property].options.field.name;
|
||||
const targetName = VectorStyle.getComputedFieldName(originalFieldName);
|
||||
return [
|
||||
'interpolate',
|
||||
['linear'],
|
||||
['coalesce', ['get', targetName], -1],
|
||||
-1, 'rgba(0,0,0,0)',
|
||||
...colorRange
|
||||
];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
_getMBDataDrivenColor({ fieldName, color }) {
|
||||
const colorRange = getHexColorRangeStrings(color, 8)
|
||||
.reduce((accu, curColor, idx, srcArr) => {
|
||||
accu = [ ...accu, idx / srcArr.length, curColor ];
|
||||
return accu;
|
||||
}, []);
|
||||
const targetName = VectorStyle.getComputedFieldName(fieldName);
|
||||
return [
|
||||
'interpolate',
|
||||
['linear'],
|
||||
['coalesce', ['get', targetName], -1],
|
||||
-1, 'rgba(0,0,0,0)',
|
||||
...colorRange
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
_getMbDataDrivenSize(property) {
|
||||
|
||||
if (!this._descriptor.properties[property] || !this._descriptor.properties[property].options) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { minSize, maxSize } = this._descriptor.properties[property].options;
|
||||
if (typeof minSize === 'number' && typeof maxSize === 'number') {
|
||||
const originalFieldName = this._descriptor.properties[property].options.field.name;
|
||||
const targetName = VectorStyle.getComputedFieldName(originalFieldName);
|
||||
return ['interpolate',
|
||||
['linear'],
|
||||
['get', targetName],
|
||||
0, minSize,
|
||||
1, maxSize
|
||||
];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
_getMbDataDrivenSize({ fieldName, minSize, maxSize }) {
|
||||
const targetName = VectorStyle.getComputedFieldName(fieldName);
|
||||
return ['interpolate',
|
||||
['linear'],
|
||||
['get', targetName],
|
||||
0, minSize,
|
||||
1, maxSize
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
|
||||
_getMBColor(property) {
|
||||
let color;
|
||||
|
||||
const hasFields = _.get(this._descriptor.properties[property].options, 'field', false)
|
||||
&& _.get(this._descriptor.properties[property].options, 'color', false);
|
||||
const isStatic = this._descriptor.properties[property].type === VectorStyle.STYLE_TYPE.STATIC;
|
||||
|
||||
if (isStatic || !hasFields) {
|
||||
color = this.getHexColor(property);
|
||||
} else {
|
||||
color = this._getMBDataDrivenColor(property);
|
||||
_getMBColor(styleDescriptor) {
|
||||
const isStatic = styleDescriptor.type === VectorStyle.STYLE_TYPE.STATIC;
|
||||
if (isStatic) {
|
||||
return _.get(styleDescriptor, 'options.color', null);
|
||||
}
|
||||
return color;
|
||||
|
||||
const isDynamicConfigComplete = _.has(styleDescriptor, 'options.field')
|
||||
&& _.has(styleDescriptor, 'options.color');
|
||||
if (isDynamicConfigComplete) {
|
||||
return this._getMBDataDrivenColor({
|
||||
fieldName: styleDescriptor.options.field.name,
|
||||
color: styleDescriptor.options.color,
|
||||
});
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
_getMBOpacity() {
|
||||
const DEFAULT_OPACITY = 1;
|
||||
const opacity = typeof this._descriptor.properties.alphaValue === 'number' ? this._descriptor.properties.alphaValue : DEFAULT_OPACITY;
|
||||
return opacity;
|
||||
return _.get(this._descriptor.properties, 'alphaValue', DEFAULT_ALPHA_VALUE);
|
||||
}
|
||||
|
||||
_getMbSize(property) {
|
||||
if (this._descriptor.properties[property].type === VectorStyle.STYLE_TYPE.STATIC) {
|
||||
return this._descriptor.properties[property].options.size;
|
||||
} else {
|
||||
return this._getMbDataDrivenSize(property);
|
||||
_getMbSize(styleDescriptor) {
|
||||
if (styleDescriptor.type === VectorStyle.STYLE_TYPE.STATIC) {
|
||||
return styleDescriptor.options.size;
|
||||
}
|
||||
|
||||
const isDynamicConfigComplete = _.has(styleDescriptor, 'options.field')
|
||||
&& _.has(styleDescriptor, 'options.minSize')
|
||||
&& _.has(styleDescriptor, 'options.maxSize');
|
||||
if (isDynamicConfigComplete) {
|
||||
return this._getMbDataDrivenSize({
|
||||
fieldName: styleDescriptor.options.field.name,
|
||||
minSize: styleDescriptor.options.minSize,
|
||||
maxSize: styleDescriptor.options.maxSize,
|
||||
});
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
setMBPaintProperties(mbMap, sourceId, fillLayerId, lineLayerId) {
|
||||
const opacity = this._getMBOpacity();
|
||||
|
||||
if (this._descriptor.properties.fillColor) {
|
||||
const color = this._getMBColor('fillColor');
|
||||
const color = this._getMBColor(this._descriptor.properties.fillColor);
|
||||
mbMap.setPaintProperty(fillLayerId, 'fill-color', color);
|
||||
mbMap.setPaintProperty(fillLayerId, 'fill-opacity', opacity);
|
||||
} else {
|
||||
|
@ -310,7 +295,7 @@ export class VectorStyle {
|
|||
}
|
||||
|
||||
if (this._descriptor.properties.lineColor) {
|
||||
const color = this._getMBColor('lineColor');
|
||||
const color = this._getMBColor(this._descriptor.properties.lineColor);
|
||||
mbMap.setPaintProperty(lineLayerId, 'line-color', color);
|
||||
mbMap.setPaintProperty(lineLayerId, 'line-opacity', opacity);
|
||||
|
||||
|
@ -319,8 +304,8 @@ export class VectorStyle {
|
|||
mbMap.setPaintProperty(lineLayerId, 'line-opacity', 0);
|
||||
}
|
||||
|
||||
if (this._descriptor.properties.lineWidth && this._descriptor.properties.lineWidth.options) {
|
||||
const lineWidth = this._getMbSize('lineWidth');
|
||||
if (this._descriptor.properties.lineWidth) {
|
||||
const lineWidth = this._getMbSize(this._descriptor.properties.lineWidth);
|
||||
mbMap.setPaintProperty(lineLayerId, 'line-width', lineWidth);
|
||||
} else {
|
||||
mbMap.setPaintProperty(lineLayerId, 'line-width', 0);
|
||||
|
@ -330,7 +315,7 @@ export class VectorStyle {
|
|||
setMBPaintPropertiesForPoints(mbMap, sourceId, pointLayerId) {
|
||||
const opacity = this._getMBOpacity();
|
||||
if (this._descriptor.properties.fillColor) {
|
||||
const color = this._getMBColor('fillColor');
|
||||
const color = this._getMBColor(this._descriptor.properties.fillColor);
|
||||
mbMap.setPaintProperty(pointLayerId, 'circle-color', color);
|
||||
mbMap.setPaintProperty(pointLayerId, 'circle-opacity', opacity);
|
||||
} else {
|
||||
|
@ -338,7 +323,7 @@ export class VectorStyle {
|
|||
mbMap.setPaintProperty(pointLayerId, 'circle-opacity', 0);
|
||||
}
|
||||
if (this._descriptor.properties.lineColor) {
|
||||
const color = this._getMBColor('lineColor');
|
||||
const color = this._getMBColor(this._descriptor.properties.lineColor);
|
||||
mbMap.setPaintProperty(pointLayerId, 'circle-stroke-color', color);
|
||||
mbMap.setPaintProperty(pointLayerId, 'circle-stroke-opacity', opacity);
|
||||
|
||||
|
@ -346,14 +331,14 @@ export class VectorStyle {
|
|||
mbMap.setPaintProperty(pointLayerId, 'circle-stroke-color', null);
|
||||
mbMap.setPaintProperty(pointLayerId, 'circle-stroke-opacity', 0);
|
||||
}
|
||||
if (this._descriptor.properties.lineWidth && this._descriptor.properties.lineWidth.options) {
|
||||
const lineWidth = this._getMbSize('lineWidth');
|
||||
if (this._descriptor.properties.lineWidth) {
|
||||
const lineWidth = this._getMbSize(this._descriptor.properties.lineWidth);
|
||||
mbMap.setPaintProperty(pointLayerId, 'circle-stroke-width', lineWidth);
|
||||
} else {
|
||||
mbMap.setPaintProperty(pointLayerId, 'circle-stroke-width', 0);
|
||||
}
|
||||
if (this._descriptor.properties.iconSize && this._descriptor.properties.iconSize.options) {
|
||||
const iconSize = this._getMbSize('iconSize');
|
||||
if (this._descriptor.properties.iconSize) {
|
||||
const iconSize = this._getMbSize(this._descriptor.properties.iconSize);
|
||||
mbMap.setPaintProperty(pointLayerId, 'circle-radius', iconSize);
|
||||
} else {
|
||||
mbMap.setPaintProperty(pointLayerId, 'circle-radius', 0);
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* 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 { VectorStyle } from './vector_style';
|
||||
import { COLOR_GRADIENTS } from './components/vector/color/color_ramp_select';
|
||||
|
||||
const DEFAULT_COLORS = ['#e6194b', '#3cb44b', '#ffe119', '#f58231', '#911eb4'];
|
||||
export const DEFAULT_ALPHA_VALUE = 1;
|
||||
export const DEFAULT_MIN_SIZE = 1;
|
||||
export const DEFAULT_MAX_SIZE = 64;
|
||||
|
||||
export function getDefaultStaticProperties(mapColors = []) {
|
||||
// Colors must be state-aware to reduce unnecessary incrementation
|
||||
const lastColor = mapColors.pop();
|
||||
const nextColorIndex = (DEFAULT_COLORS.indexOf(lastColor) + 1) % (DEFAULT_COLORS.length - 1);
|
||||
const nextColor = DEFAULT_COLORS[nextColorIndex];
|
||||
|
||||
return {
|
||||
fillColor: {
|
||||
type: VectorStyle.STYLE_TYPE.STATIC,
|
||||
options: {
|
||||
color: nextColor,
|
||||
}
|
||||
},
|
||||
lineColor: {
|
||||
type: VectorStyle.STYLE_TYPE.STATIC,
|
||||
options: {
|
||||
color: '#FFFFFF'
|
||||
}
|
||||
},
|
||||
lineWidth: {
|
||||
type: VectorStyle.STYLE_TYPE.STATIC,
|
||||
options: {
|
||||
size: 1
|
||||
}
|
||||
},
|
||||
iconSize: {
|
||||
type: VectorStyle.STYLE_TYPE.STATIC,
|
||||
options: {
|
||||
size: 10
|
||||
}
|
||||
},
|
||||
alphaValue: DEFAULT_ALPHA_VALUE
|
||||
};
|
||||
}
|
||||
|
||||
export function getDefaultDynamicProperties() {
|
||||
return {
|
||||
fillColor: {
|
||||
type: VectorStyle.STYLE_TYPE.DYNAMIC,
|
||||
options: {
|
||||
color: COLOR_GRADIENTS[0].value,
|
||||
}
|
||||
},
|
||||
lineColor: {
|
||||
type: VectorStyle.STYLE_TYPE.DYNAMIC,
|
||||
options: {
|
||||
color: COLOR_GRADIENTS[0].value,
|
||||
}
|
||||
},
|
||||
lineWidth: {
|
||||
type: VectorStyle.STYLE_TYPE.DYNAMIC,
|
||||
options: {
|
||||
minSize: DEFAULT_MIN_SIZE,
|
||||
maxSize: 64
|
||||
}
|
||||
},
|
||||
iconSize: {
|
||||
type: VectorStyle.STYLE_TYPE.DYNAMIC,
|
||||
options: {
|
||||
minSize: DEFAULT_MIN_SIZE,
|
||||
maxSize: DEFAULT_MAX_SIZE
|
||||
}
|
||||
},
|
||||
alphaValue: DEFAULT_ALPHA_VALUE
|
||||
};
|
||||
}
|
|
@ -17,8 +17,6 @@ import { store } from '../../store/store';
|
|||
import { getMapColors } from '../../selectors/map_selectors';
|
||||
import _ from 'lodash';
|
||||
|
||||
const DEFAULT_COLORS = ['#e6194b', '#3cb44b', '#ffe119', '#f58231', '#911eb4'];
|
||||
|
||||
const EMPTY_FEATURE_COLLECTION = {
|
||||
type: 'FeatureCollection',
|
||||
features: []
|
||||
|
@ -37,44 +35,16 @@ export class VectorLayer extends ALayer {
|
|||
static tooltipContainer = document.createElement('div');
|
||||
|
||||
static createDescriptor(options) {
|
||||
// Colors must be state-aware to reduce unnecessary incrementation
|
||||
const DEFAULT_ALPHA_VALUE = 1;
|
||||
const mapColors = getMapColors(store.getState());
|
||||
const lastColor = mapColors.pop();
|
||||
const nextColor = DEFAULT_COLORS[
|
||||
(DEFAULT_COLORS.indexOf(lastColor) + 1) % (DEFAULT_COLORS.length - 1)
|
||||
];
|
||||
const layerDescriptor = super.createDescriptor(options);
|
||||
layerDescriptor.type = VectorLayer.type;
|
||||
|
||||
if (!options.style) {
|
||||
layerDescriptor.style = VectorStyle.createDescriptor({
|
||||
fillColor: {
|
||||
type: VectorStyle.STYLE_TYPE.STATIC,
|
||||
options: {
|
||||
color: nextColor,
|
||||
}
|
||||
},
|
||||
lineColor: {
|
||||
type: VectorStyle.STYLE_TYPE.STATIC,
|
||||
options: {
|
||||
color: '#FFFFFF'
|
||||
}
|
||||
},
|
||||
lineWidth: {
|
||||
type: VectorStyle.STYLE_TYPE.STATIC,
|
||||
options: {
|
||||
size: 1
|
||||
}
|
||||
},
|
||||
iconSize: {
|
||||
type: VectorStyle.STYLE_TYPE.STATIC,
|
||||
options: {
|
||||
size: 10
|
||||
}
|
||||
},
|
||||
alphaValue: DEFAULT_ALPHA_VALUE
|
||||
});
|
||||
// TODO pass store in as argument. Accessing store this way is unsafe
|
||||
const mapColors = getMapColors(store.getState());
|
||||
const styleProperties = VectorStyle.createDefaultStyleProperties(mapColors);
|
||||
layerDescriptor.style = VectorStyle.createDescriptor(styleProperties);
|
||||
}
|
||||
|
||||
return layerDescriptor;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue