Skip to content

Commit

Permalink
[Maps] Enable borders for icon symbols (#43066)
Browse files Browse the repository at this point in the history
* [Maps] Enable borders on icons

* [Maps] Enable borders on icons

* Review feedback

* Remove unnecessary Fragment
  • Loading branch information
nickpeihl authored Aug 12, 2019
1 parent c29a17c commit 3503aa1
Show file tree
Hide file tree
Showing 9 changed files with 61 additions and 30 deletions.
4 changes: 4 additions & 0 deletions docs/maps/vector-style-properties.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ Use *Icon* to symbolize Points as icons.

*Fill color*:: The fill color of the point features.

*Border color*:: The border color of the point features.

*Border width*:: The border width of the point features.

*Symbol orientation*:: The symbol orientation rotating the icon clockwise.

*Symbol size*:: The radius of the symbol size, in pixels.
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -15,31 +15,35 @@ export class SymbolIcon extends Component {
imgDataUrl: undefined,
prevSymbolId: undefined,
prevFill: undefined,
prevStroke: undefined,
prevStrokeWidth: undefined,
}

componentDidMount() {
this._isMounted = true;
this._loadSymbol(this.props.symbolId, this.props.fill);
this._loadSymbol(this.props.symbolId, this.props.fill, this.props.stroke, this.props.strokeWidth);
}

componentDidUpdate() {
this._loadSymbol(this.props.symbolId, this.props.fill);
this._loadSymbol(this.props.symbolId, this.props.fill, this.props.stroke, this.props.strokeWidth);
}

componentWillUnmount() {
this._isMounted = false;
}

async _loadSymbol(nextSymbolId, nextFill) {
async _loadSymbol(nextSymbolId, nextFill, nextStroke, nextStrokeWidth) {
if (nextSymbolId === this.state.prevSymbolId
&& nextFill === this.state.prevFill) {
&& nextFill === this.state.prevFill
&& nextStroke === this.state.prevStroke
&& nextStrokeWidth === this.state.prevStrokeWidth) {
return;
}

let imgDataUrl;
try {
const svg = getMakiSymbolSvg(nextSymbolId);
const styledSvg = await styleSvg(svg, nextFill);
const styledSvg = await styleSvg(svg, nextFill, nextStroke, nextStrokeWidth);
imgDataUrl = buildSrcUrl(styledSvg);
} catch (error) {
// ignore failures - component will just not display an icon
Expand All @@ -49,7 +53,9 @@ export class SymbolIcon extends Component {
this.setState({
imgDataUrl,
prevSymbolId: nextSymbolId,
prevFill: nextFill
prevFill: nextFill,
prevStroke: nextStroke,
prevStrokeWidth: nextStrokeWidth
});
}
}
Expand All @@ -68,4 +74,6 @@ export class SymbolIcon extends Component {
SymbolIcon.propTypes = {
symbolId: PropTypes.string.isRequired,
fill: PropTypes.string.isRequired,
stroke: PropTypes.string.isRequired,
strokeWidth: PropTypes.string.isRequired
};
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ export class VectorIcon extends Component {
<SymbolIcon
symbolId={this.props.symbolId}
fill={style.fill}
stroke={style.stroke}
strokeWidth={style.strokeWidth}
/>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { VectorStyleSymbolEditor } from './vector_style_symbol_editor';
import { OrientationEditor } from './orientation/orientation_editor';
import { getDefaultDynamicProperties, getDefaultStaticProperties } from '../../vector_style_defaults';
import { VECTOR_SHAPE_TYPES } from '../../../sources/vector_feature_types';
import { SYMBOLIZE_AS_CIRCLE } from '../../vector_constants';
import { SYMBOLIZE_AS_ICON } from '../../vector_constants';
import { i18n } from '@kbn/i18n';
import { SYMBOL_OPTIONS } from '../../symbol_utils';

Expand Down Expand Up @@ -140,23 +140,8 @@ export class VectorStyleEditor extends Component {
}

_renderPointProperties() {
let lineColor;
let lineWidth;
let iconOrientation;
if (this.props.styleProperties.symbol.options.symbolizeAs === SYMBOLIZE_AS_CIRCLE) {
lineColor = (
<Fragment>
{this._renderLineColor()}
<EuiSpacer size="m" />
</Fragment>
);
lineWidth = (
<Fragment>
{this._renderLineWidth()}
<EuiSpacer size="m" />
</Fragment>
);
} else {
if (this.props.styleProperties.symbol.options.symbolizeAs === SYMBOLIZE_AS_ICON) {
iconOrientation = (
<Fragment>
<OrientationEditor
Expand Down Expand Up @@ -185,9 +170,11 @@ export class VectorStyleEditor extends Component {
{this._renderFillColor()}
<EuiSpacer size="m" />

{lineColor}
{this._renderLineColor()}
<EuiSpacer size="m" />

{lineWidth}
{this._renderLineWidth()}
<EuiSpacer size="m" />

{iconOrientation}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ export function VectorStyleSymbolEditor({ styleOptions, handlePropertyChange, sy
<SymbolIcon
symbolId={value}
fill={isDarkMode ? 'rgb(223, 229, 239)' : 'rgb(52, 55, 65)'}
stroke={isDarkMode ? 'rgb(255, 255, 255)' : 'rgb(0, 0, 0)'}
strokeWidth={'1px'}
/>
</EuiFlexItem>
<EuiFlexItem>
Expand Down
12 changes: 10 additions & 2 deletions x-pack/legacy/plugins/maps/public/layers/styles/symbol_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,19 @@ export function buildSrcUrl(svgString) {
return domUrl.createObjectURL(svg);
}

export async function styleSvg(svgString, fill) {
export async function styleSvg(svgString, fill, stroke, strokeWidth) {
const svgXml = await parseXmlString(svgString);
let style = '';
if (fill) {
svgXml.svg.$.style = `fill: ${fill};`;
style += `fill:${fill};`;
}
if (stroke) {
style += `stroke:${stroke};`;
}
if (strokeWidth) {
style += `stroke-width:${strokeWidth};`;
}
if (style) svgXml.svg.$.style = style;
const builder = new xml2js.Builder();
return builder.buildObject(svgXml);
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,30 @@ describe('getMakiSymbolSvg', () => {
});

describe('styleSvg', () => {
it('Should not add style property when fill not provided', async () => {
it('Should not add style property when style not provided', async () => {
const unstyledSvgString = '<svg version="1.1" width="11px" height="11px" viewBox="0 0 11 11"><path/></svg>';
const styledSvg = await styleSvg(unstyledSvgString);
expect(styledSvg.split('\n')[1]).toBe('<svg version=\"1.1\" width=\"11px\" height=\"11px\" viewBox=\"0 0 11 11\">');
});

it('Should add style property to svg element', async () => {
it('Should add fill style property to svg element', async () => {
const unstyledSvgString = '<svg version="1.1" width="11px" height="11px" viewBox="0 0 11 11"><path/></svg>';
const styledSvg = await styleSvg(unstyledSvgString, 'red');
// eslint-disable-next-line max-len
expect(styledSvg.split('\n')[1]).toBe('<svg version=\"1.1\" width=\"11px\" height=\"11px\" viewBox=\"0 0 11 11\" style=\"fill: red;\">');
expect(styledSvg.split('\n')[1]).toBe('<svg version=\"1.1\" width=\"11px\" height=\"11px\" viewBox=\"0 0 11 11\" style=\"fill:red;\">');
});

it('Should add stroke style property to svg element', async () => {
const unstyledSvgString = '<svg version="1.1" width="11px" height="11px" viewBox="0 0 11 11"><path/></svg>';
const styledSvg = await styleSvg(unstyledSvgString, 'red', 'white');
// eslint-disable-next-line max-len
expect(styledSvg.split('\n')[1]).toBe('<svg version=\"1.1\" width=\"11px\" height=\"11px\" viewBox=\"0 0 11 11\" style=\"fill:red;stroke:white;\">');
});

it('Should add stroke-width style property to svg element', async () => {
const unstyledSvgString = '<svg version="1.1" width="11px" height="11px" viewBox="0 0 11 11"><path/></svg>';
const styledSvg = await styleSvg(unstyledSvgString, 'red', 'white', '2px');
// eslint-disable-next-line max-len
expect(styledSvg.split('\n')[1]).toBe('<svg version=\"1.1\" width=\"11px\" height=\"11px\" viewBox=\"0 0 11 11\" style=\"fill:red;stroke:white;stroke-width:2px;\">');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -546,8 +546,12 @@ export class VectorStyle extends AbstractStyle {
const symbolId = this._descriptor.properties.symbol.options.symbolId;
mbMap.setLayoutProperty(symbolLayerId, 'icon-anchor', getMakiSymbolAnchor(symbolId));
const color = this._getMBColor(this._descriptor.properties.fillColor);
const haloColor = this._getMBColor(this._descriptor.properties.lineColor);
const haloWidth = this._getMbSize(this._descriptor.properties.lineWidth);
// icon-color is only supported on SDF icons.
mbMap.setPaintProperty(symbolLayerId, 'icon-color', color);
mbMap.setPaintProperty(symbolLayerId, 'icon-halo-color', haloColor);
mbMap.setPaintProperty(symbolLayerId, 'icon-halo-width', haloWidth);
mbMap.setPaintProperty(symbolLayerId, 'icon-opacity', alpha);

// circle sizing is by radius
Expand Down

0 comments on commit 3503aa1

Please sign in to comment.