diff --git a/scss/_stylepicker.scss b/scss/_stylepicker.scss
new file mode 100644
index 000000000..343d5efa4
--- /dev/null
+++ b/scss/_stylepicker.scss
@@ -0,0 +1,22 @@
+.o-stylepicker {
+ height: 1.25rem;
+ margin-right: 5px;
+ margin-bottom: 1.25rem;
+ min-width: 110px;
+}
+
+.o-stylepicker-header {
+ margin-right: 5px;
+ margin-top: 1.25rem;
+}
+
+.o-stylepicker button {
+ border-radius: 10px;
+ font-family: Arial, 'Helvetica Neue', sans-serif;
+ font-size: .625rem;
+ line-height: 1.25rem;
+}
+
+.o-stylepicker .dropdown li:hover {
+ color: $grey-darker;
+}
\ No newline at end of file
diff --git a/scss/origo.scss b/scss/origo.scss
index 96653a69f..b0c48fee8 100644
--- a/scss/origo.scss
+++ b/scss/origo.scss
@@ -25,6 +25,7 @@
@import 'popover';
@import 'dropdown';
@import 'sidebar';
+ @import 'stylepicker';
@import 'close';
@import 'icon';
@import 'tooltip';
diff --git a/src/controls/legend/overlay.js b/src/controls/legend/overlay.js
index f14ad5666..a7cc57d47 100644
--- a/src/controls/legend/overlay.js
+++ b/src/controls/legend/overlay.js
@@ -3,10 +3,8 @@ import { HeaderIcon } from '../../utils/legendmaker';
import PopupMenu from '../../ui/popupmenu';
const OverlayLayer = function OverlayLayer(options) {
- let {
- headerIconCls = ''
- } = options;
const {
+ headerIconCls = '',
cls: clsSettings = '',
icon = '#o_list_24px',
iconCls = 'grey-lightest',
@@ -17,9 +15,13 @@ const OverlayLayer = function OverlayLayer(options) {
} = options;
const buttons = [];
+ let headerIconClass = headerIconCls;
+
const popupMenuItems = [];
let layerList;
+ const hasStylePicker = viewer.getLayerStylePicker(layer).length > 0;
+ const layerIconCls = `round compact icon-small relative no-shrink light ${hasStylePicker ? 'style-picker' : ''}`;
const cls = `${clsSettings} flex row align-center padding-left padding-right-smaller item`.trim();
const title = layer.get('title') || 'Titel saknas';
const name = layer.get('name');
@@ -39,7 +41,7 @@ const OverlayLayer = function OverlayLayer(options) {
let headerIcon = HeaderIcon(style, opacity);
if (!headerIcon) {
headerIcon = icon;
- headerIconCls = iconCls;
+ headerIconClass = iconCls;
}
const eventOverlayProps = new CustomEvent('overlayproperties', {
@@ -68,15 +70,15 @@ const OverlayLayer = function OverlayLayer(options) {
};
const layerIcon = Button({
- cls: `${headerIconCls} round compact icon-small light relative no-shrink`,
+ cls: `${headerIconClass} ${layerIconCls}`,
click() {
if (!secure) {
toggleVisible(layer.getVisible());
}
},
style: {
- height: '1.5rem',
- width: '1.5rem'
+ height: 'calc(1.5rem + 2px)',
+ width: 'calc(1.5rem + 2px)'
},
ariaLabel: 'Lager ikon',
icon: headerIcon,
@@ -239,6 +241,16 @@ const OverlayLayer = function OverlayLayer(options) {
el.remove();
};
+ const onLayerStyleChange = function onLayerStyleChange() {
+ const newStyle = viewer.getStyle(layer.get('styleName'));
+ const layerIconCmp = document.getElementById(layerIcon.getId());
+ let newIcon = HeaderIcon(newStyle, opacity);
+ headerIconClass = !newIcon ? iconCls : headerIconCls;
+ newIcon = !newIcon ? icon : newIcon;
+ layerIconCmp.className = `${headerIconClass} ${layerIconCls}`;
+ layerIcon.dispatch('change', { icon: newIcon });
+ };
+
return Component({
name,
getLayer,
@@ -277,6 +289,9 @@ const OverlayLayer = function OverlayLayer(options) {
});
document.getElementById(this.getId()).dispatchEvent(visibleEvent);
});
+ layer.on('change:style', () => {
+ onLayerStyleChange();
+ });
},
render() {
return `
${ButtonsHtml}`;
diff --git a/src/controls/legend/overlayproperties.js b/src/controls/legend/overlayproperties.js
index 0ab68e33e..5c9ae276f 100644
--- a/src/controls/legend/overlayproperties.js
+++ b/src/controls/legend/overlayproperties.js
@@ -1,5 +1,6 @@
-import { Component, InputRange } from '../../ui';
+import { Component, InputRange, Dropdown } from '../../ui';
import { Legend } from '../../utils/legendmaker';
+import Style from '../../style';
const OverlayProperties = function OverlayProperties(options = {}) {
const {
@@ -15,6 +16,15 @@ const OverlayProperties = function OverlayProperties(options = {}) {
const opacityControl = layer.get('opacityControl') !== false;
const style = viewer.getStyle(layer.get('styleName'));
const legend = Legend(style, opacity);
+ const stylePicker = viewer.getLayerStylePicker(layer);
+
+ const legendComponent = Component({
+ render() {
+ return `${legend}
`;
+ }
+ });
+
+ let styleSelection;
let overlayEl;
let sliderEl;
let label = '';
@@ -31,6 +41,10 @@ const OverlayProperties = function OverlayProperties(options = {}) {
label
});
+ function hasStylePicker() {
+ return stylePicker.length > 0;
+ }
+
function extendedLegendZoom(e) {
const parentOverlay = document.getElementById(options.parent.getId());
@@ -43,14 +57,53 @@ const OverlayProperties = function OverlayProperties(options = {}) {
}
}
+ function renderStyleSelection() {
+ const html = `${styleSelection.render()}`;
+ return hasStylePicker() ? html : '';
+ }
+
+ function getStyleDisplayName(styleName) {
+ const altStyle = stylePicker.find(s => s.style === styleName);
+ return (altStyle && altStyle.title) || styleName;
+ }
+
+ const onSelectStyle = (styleTitle) => {
+ const altStyleIndex = stylePicker.findIndex(s => s.title === styleTitle);
+ const altStyle = stylePicker[altStyleIndex];
+ styleSelection.setButtonText(styleTitle);
+ const newStyle = Style.createStyle({ style: altStyle.style, clusterStyleName: altStyle.clusterStyle, viewer });
+ const legendCmp = document.getElementById(legendComponent.getId());
+ legendCmp.innerHTML = Legend(viewer.getStyle(altStyle.style), opacity);
+ if (!layer.get('defaultStyle')) layer.setProperties({ defaultStyle: layer.get('styleName') });
+ layer.setProperties({ altStyleIndex });
+ layer.setProperties({ styleName: altStyle.style });
+ layer.setStyle(newStyle);
+ layer.dispatchEvent('change:style');
+ };
+
return Component({
onInit() {
- this.addComponents([transparencySlider]);
+ styleSelection = Dropdown({
+ direction: 'up',
+ cls: 'o-stylepicker text-black flex',
+ contentCls: 'bg-grey-lighter text-smaller rounded',
+ buttonCls: 'bg-white border text-black box-shadow',
+ buttonTextCls: 'text-smaller',
+ text: getStyleDisplayName(layer.get('styleName')),
+ buttonIconCls: 'black',
+ ariaLabel: 'Välj stil'
+ });
+ const components = [transparencySlider];
+ if (hasStylePicker()) {
+ components.push(styleSelection);
+ }
+ this.addComponents(components);
this.on('click', (e) => {
extendedLegendZoom(e);
});
},
onRender() {
+ this.dispatch('render');
sliderEl = document.getElementById(transparencySlider.getId());
overlayEl = document.getElementById(this.getId());
overlayEl.addEventListener('click', (e) => {
@@ -66,10 +119,21 @@ const OverlayProperties = function OverlayProperties(options = {}) {
layer.setOpacity(sliderEl.valueAsNumber);
});
}
+ if (hasStylePicker()) {
+ styleSelection.setItems(stylePicker.map(altStyle => altStyle.title));
+ const styleSelectionEl = document.getElementById(styleSelection.getId());
+ styleSelectionEl.addEventListener('dropdown:select', (evt) => {
+ onSelectStyle(evt.target.textContent);
+ });
+ }
},
render() {
return `
-
${legend}${transparencySlider.render()}
+
+ ${legendComponent.render()}
+ ${renderStyleSelection()}
+ ${transparencySlider.render()}
+
${abstract ? `
${abstract}
` : ''}
`;
},
diff --git a/src/permalink/permalinkparser.js b/src/permalink/permalinkparser.js
index a3b82da4b..f991daff6 100644
--- a/src/permalink/permalinkparser.js
+++ b/src/permalink/permalinkparser.js
@@ -13,6 +13,10 @@ const layerModel = {
o: {
name: 'opacity',
dataType: 'number'
+ },
+ sn: {
+ name: 'altStyleIndex',
+ dataType: 'number'
}
};
@@ -31,12 +35,15 @@ const layers = function layers(layersStr) {
});
Object.getOwnPropertyNames(layerObject).forEach((prop) => {
const val = layerObject[prop];
- if (Object.prototype.hasOwnProperty.call(layerModel, prop) && prop !== 'o') {
+ if (Object.prototype.hasOwnProperty.call(layerModel, prop) && prop !== 'o' && prop !== 'sn') {
const attribute = layerModel[prop];
obj[attribute.name] = urlparser.strBoolean(val);
} else if (prop === 'o') {
const attribute = layerModel[prop];
obj[attribute.name] = Number(val) / 100;
+ } else if (prop === 'sn') {
+ const attribute = layerModel[prop];
+ obj[attribute.name] = Number(val);
} else {
obj[prop] = val;
}
diff --git a/src/permalink/permalinkstore.js b/src/permalink/permalinkstore.js
index e6ff7f480..c64cc6cb2 100644
--- a/src/permalink/permalinkstore.js
+++ b/src/permalink/permalinkstore.js
@@ -11,6 +11,8 @@ function getSaveLayers(layers) {
saveLayer.v = layer.getVisible() === true ? 1 : 0;
saveLayer.s = layer.get('legend') === true ? 1 : 0;
saveLayer.o = Number(layer.get('opacity')) * 100;
+ // Only get style for layer styles that have changed
+ if (layer.get('defaultStyle') && layer.get('defaultStyle') !== layer.get('styleName')) saveLayer.sn = layer.get('altStyleIndex');
if (saveLayer.s || saveLayer.v) {
saveLayer.name = layer.get('name');
if (saveLayer.name !== 'measure') {
diff --git a/src/ui/dropdown.js b/src/ui/dropdown.js
index c88c5c090..21fad6ee7 100644
--- a/src/ui/dropdown.js
+++ b/src/ui/dropdown.js
@@ -15,7 +15,8 @@ export default function Dropdown(options = {}) {
style: styleSettings,
direction = 'down',
text = ' ',
- ariaLabel = ''
+ ariaLabel = '',
+ buttonTextCls = 'flex'
} = options;
let containerElement;
@@ -78,7 +79,7 @@ export default function Dropdown(options = {}) {
icon: `#ic_arrow_drop_${direction}_24px`,
iconCls: `${buttonIconCls} icon-smaller flex`,
ariaLabel,
- textCls: 'flex'
+ textCls: buttonTextCls
});
if (direction === 'down') {
diff --git a/src/viewer.js b/src/viewer.js
index 025e07a38..6277a2a5c 100644
--- a/src/viewer.js
+++ b/src/viewer.js
@@ -61,6 +61,7 @@ const Viewer = function Viewer(targetOption, options = {}) {
const center = urlParams.center || centerOption;
const zoom = urlParams.zoom || zoomOption;
const groups = flattenGroups(groupOptions);
+ const layerStylePicker = {};
const getCapabilitiesLayers = () => {
const capabilitiesPromises = [];
@@ -327,6 +328,13 @@ const Viewer = function Viewer(targetOption, options = {}) {
visible: false,
legend: false
};
+ // Apply changed style
+ if (savedLayerProps[layerName] && savedLayerProps[layerName].altStyleIndex > -1) {
+ const altStyle = initialProps.stylePicker[savedLayerProps[layerName].altStyleIndex];
+ savedProps.clusterStyle = altStyle.clusterStyle;
+ savedProps.style = altStyle.style;
+ savedProps.defaultStyle = initialProps.style;
+ }
savedProps.name = initialProps.name;
const mergedProps = Object.assign({}, initialProps, savedProps);
acc.push(mergedProps);
@@ -372,8 +380,19 @@ const Viewer = function Viewer(targetOption, options = {}) {
return false;
};
+ const getLayerStylePicker = function getLayerStylePicker(layer) {
+ return layerStylePicker[layer.get('name')] || [];
+ };
+
+ const addLayerStylePicker = function addLayerStylePicker(layerProps) {
+ if (!layerStylePicker[layerProps.name]) {
+ layerStylePicker[layerProps.name] = layerProps.stylePicker;
+ }
+ };
+
const addLayer = function addLayer(layerProps) {
const layer = Layer(layerProps, this);
+ addLayerStylePicker(layerProps);
map.addLayer(layer);
this.dispatch('addlayer', {
layerName: layerProps.name
@@ -598,6 +617,7 @@ const Viewer = function Viewer(targetOption, options = {}) {
getSearchableLayers,
getSize,
getLayer,
+ getLayerStylePicker,
getLayers,
getLayersByProperty,
getMap,