Allow to use an unicode char as marker icon symbol

One can also use a property to have a dynamic value (eg.
to display numbers:, 1, 2, 3, 4…).

fix #527
This commit is contained in:
Yohan Boniface 2018-07-07 14:57:56 +02:00
parent 705d0cbb73
commit af6c7fba26
8 changed files with 110 additions and 17 deletions

View file

@ -71,6 +71,7 @@ COMMIT;
- fixed ClusterMarker text color on Chrome (#547) - fixed ClusterMarker text color on Chrome (#547)
- allow to clone also markers - allow to clone also markers
- only list https ready tilerlayers when page is in https (#567) - only list https ready tilerlayers when page is in https (#567)
- allow to use an unicode character as Marker symbol (#527)

View file

@ -553,7 +553,29 @@ i.info {
cursor: pointer; cursor: pointer;
float: left; float: left;
} }
input.blur {
width: calc(100% - 40px);
display: inline-block;
vertical-align: middle;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.blur + .button:before {
content: '✔';
}
.blur + .button {
width: 40px;
height: 18px;
display: inline-block;
vertical-align: middle;
line-height: 18px;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
box-sizing: border-box;
}
input[type=hidden].blur + .button {
display: none;
}
/* *********** */ /* *********** */
/* Panel */ /* Panel */

View file

@ -410,7 +410,7 @@ L.U.Help = L.Class.extend({
}, },
formatURL: L._('Supported variables that will be dynamically replaced') + ': {bbox}, {lat}, {lng}, {zoom}, {east}, {north}..., {left}, {top}...', formatURL: L._('Supported variables that will be dynamically replaced') + ': {bbox}, {lat}, {lng}, {zoom}, {east}, {north}..., {left}, {top}...',
formatIconURL: L._('You can use feature properties as variables: ex.: with "http://myserver.org/images/{name}.png", the {name} variable will be replaced by the "name" value of each markers.'), formatIconSymbol: L._('Symbol can be either a unicode caracter or an URL. You can use feature properties as variables: ex.: with "http://myserver.org/images/{name}.png", the {name} variable will be replaced by the "name" value of each marker.'),
colorValue: L._('Must be a valid CSS value (eg.: DarkBlue or #123456)'), colorValue: L._('Must be a valid CSS value (eg.: DarkBlue or #123456)'),
smoothFactor: L._('How much to simplify the polyline on each zoom level (more = better performance and smoother look, less = more accurate)'), smoothFactor: L._('How much to simplify the polyline on each zoom level (more = better performance and smoother look, less = more accurate)'),
dashArray: L._('A comma separated list of numbers that defines the stroke dash pattern. Ex.: "5, 10, 15".'), dashArray: L._('A comma separated list of numbers that defines the stroke dash pattern. Ex.: "5, 10, 15".'),

View file

@ -52,10 +52,10 @@ L.FormBuilder.Element.include({
this.label = L.DomUtil.create('label', '', this.getLabelParent()); this.label = L.DomUtil.create('label', '', this.getLabelParent());
this.label.innerHTML = this.label.title = this.options.label; this.label.innerHTML = this.label.title = this.options.label;
if (this.options.helpEntries) this.builder.map.help.button(this.label, this.options.helpEntries); if (this.options.helpEntries) this.builder.map.help.button(this.label, this.options.helpEntries);
else if (this.options.helpText) { else if (this.options.helpTooltip) {
var info = L.DomUtil.create('i', 'info', this.label); var info = L.DomUtil.create('i', 'info', this.label);
L.DomEvent.on(info, 'mouseover', function () { L.DomEvent.on(info, 'mouseover', function () {
this.builder.map.ui.tooltip({anchor: info, content: this.options.helpText, position: 'top'}); this.builder.map.ui.tooltip({anchor: info, content: this.options.helpTooltip, position: 'top'});
}, this); }, this);
} }
} }
@ -355,28 +355,51 @@ L.FormBuilder.NullableBoolean = L.FormBuilder.Select.extend({
}); });
L.FormBuilder.IconUrl = L.FormBuilder.Input.extend({
L.FormBuilder.BlurInput.include({
build: function () {
this.options.className = 'blur';
L.FormBuilder.Input.prototype.build.call(this);
var button = L.DomUtil.create('span', 'button blur-button');
L.DomUtil.after(this.input, button);
}
});
L.FormBuilder.IconUrl = L.FormBuilder.BlurInput.extend({
type: function () { type: function () {
return 'hidden'; return 'hidden';
}, },
build: function () { build: function () {
L.FormBuilder.Input.prototype.build.call(this); this.options.helpText = this.builder.map.help.formatIconSymbol;
L.FormBuilder.BlurInput.prototype.build.call(this);
this.parentContainer = L.DomUtil.create('div', 'umap-form-iconfield', this.parentNode); this.parentContainer = L.DomUtil.create('div', 'umap-form-iconfield', this.parentNode);
this.buttonsContainer = L.DomUtil.create('div', '', this.parentContainer); this.buttonsContainer = L.DomUtil.create('div', '', this.parentContainer);
this.pictogramsContainer = L.DomUtil.create('div', 'umap-pictogram-list', this.parentContainer); this.pictogramsContainer = L.DomUtil.create('div', 'umap-pictogram-list', this.parentContainer);
this.input.type = 'hidden'; this.input.type = 'hidden';
this.input.placeholder = L._('Url'); this.input.placeholder = L._('Symbol or url');
this.udpatePreview(); this.udpatePreview();
this.on('define', this.fetchIconList); this.on('define', this.fetchIconList);
}, },
isUrl: function () {
return (this.value().indexOf('/') !== -1);
},
udpatePreview: function () { udpatePreview: function () {
if (this.value() && this.value().indexOf('{') === -1) { // Do not try to render URL with variables if (this.value()&& this.value().indexOf('{') === -1) { // Do not try to render URL with variables
var img = L.DomUtil.create('img', '', L.DomUtil.create('div', 'umap-icon-choice', this.buttonsContainer)); if (this.isUrl()) {
img.src = this.value(); var img = L.DomUtil.create('img', '', L.DomUtil.create('div', 'umap-icon-choice', this.buttonsContainer));
L.DomEvent.on(img, 'click', this.fetchIconList, this); img.src = this.value();
L.DomEvent.on(img, 'click', this.fetchIconList, this);
} else {
var el = L.DomUtil.create('span', '', L.DomUtil.create('div', 'umap-icon-choice', this.buttonsContainer));
el.textContent = this.value();
L.DomEvent.on(el, 'click', this.fetchIconList, this);
}
} }
this.button = L.DomUtil.create('a', '', this.buttonsContainer); this.button = L.DomUtil.create('a', '', this.buttonsContainer);
this.button.innerHTML = this.value() ? L._('Change symbol') : L._('Add symbol'); this.button.innerHTML = this.value() ? L._('Change symbol') : L._('Add symbol');
@ -432,15 +455,15 @@ L.FormBuilder.IconUrl = L.FormBuilder.Input.extend({
this.udpatePreview(); this.udpatePreview();
}, this); }, this);
var customButton = L.DomUtil.create('a', '', this.pictogramsContainer); var customButton = L.DomUtil.create('a', '', this.pictogramsContainer);
customButton.innerHTML = L._('Set URL'); customButton.innerHTML = L._('Set symbol');
customButton.href = '#'; customButton.href = '#';
customButton.style.display = 'block'; customButton.style.display = 'block';
customButton.style.clear = 'both'; customButton.style.clear = 'both';
this.builder.map.help.button(customButton, 'formatIconURL'); this.builder.map.help.button(customButton, 'formatIconSymbol');
L.DomEvent L.DomEvent
.on(customButton, 'click', L.DomEvent.stop) .on(customButton, 'click', L.DomEvent.stop)
.on(customButton, 'click', function (e) { .on(customButton, 'click', function (e) {
this.input.type = 'url'; this.input.type = 'text';
this.pictogramsContainer.innerHTML = ''; this.pictogramsContainer.innerHTML = '';
}, this); }, this);
}, },
@ -699,7 +722,7 @@ L.U.FormBuilder = L.FormBuilder.extend({
smoothFactor: {handler: 'Range', min: 0, max: 10, step: 0.5, label: L._('Simplify'), helpEntries: 'smoothFactor', inheritable: true}, smoothFactor: {handler: 'Range', min: 0, max: 10, step: 0.5, label: L._('Simplify'), helpEntries: 'smoothFactor', inheritable: true},
dashArray: {label: L._('dash array'), helpEntries: 'dashArray', inheritable: true}, dashArray: {label: L._('dash array'), helpEntries: 'dashArray', inheritable: true},
iconClass: {handler: 'IconClassSwitcher', label: L._('Icon shape'), inheritable: true}, iconClass: {handler: 'IconClassSwitcher', label: L._('Icon shape'), inheritable: true},
iconUrl: {handler: 'IconUrl', label: L._('Icon symbol'), inheritable: true}, iconUrl: {handler: 'IconUrl', label: L._('Icon symbol'), inheritable: true, helpText: L.U.Help.formatIconSymbol},
popupTemplate: {handler: 'PopupTemplate', label: L._('Popup style'), inheritable: true}, popupTemplate: {handler: 'PopupTemplate', label: L._('Popup style'), inheritable: true},
popupContentTemplate: {label: L._('Popup content template'), handler: 'Textarea', helpEntries: ['dynamicProperties', 'textFormatting'], placeholder: '# {name}', inheritable: true}, popupContentTemplate: {label: L._('Popup content template'), handler: 'Textarea', helpEntries: ['dynamicProperties', 'textFormatting'], placeholder: '# {name}', inheritable: true},
datalayer: {handler: 'DataLayerSwitcher', label: L._('Choose the layer of the feature')}, datalayer: {handler: 'DataLayerSwitcher', label: L._('Choose the layer of the feature')},

View file

@ -59,9 +59,17 @@ L.U.Icon.Default = L.U.Icon.extend({
this.elements.main = L.DomUtil.create('div'); this.elements.main = L.DomUtil.create('div');
this.elements.container = L.DomUtil.create('div', 'icon_container', this.elements.main); this.elements.container = L.DomUtil.create('div', 'icon_container', this.elements.main);
this.elements.arrow = L.DomUtil.create('div', 'icon_arrow', this.elements.main); this.elements.arrow = L.DomUtil.create('div', 'icon_arrow', this.elements.main);
this.elements.img = L.DomUtil.create('img', null, this.elements.container);
var src = this._getIconUrl('icon'); var src = this._getIconUrl('icon');
if (src) this.elements.img.src = src; if (src) {
// An url.
if (src.indexOf('http') === 0 || src.indexOf('/') === 0) {
this.elements.img = L.DomUtil.create('img', null, this.elements.container);
this.elements.img.src = src;
} else {
this.elements.span = L.DomUtil.create('span', null, this.elements.container)
this.elements.span.textContent = src;
}
}
this._setColor(); this._setColor();
this._setIconStyles(this.elements.main, 'icon'); this._setIconStyles(this.elements.main, 'icon');
return this.elements.main; return this.elements.main;

View file

@ -1030,6 +1030,12 @@ a.add-datalayer:hover,
vertical-align: middle; vertical-align: middle;
max-width: 24px !important; max-width: 24px !important;
} }
.umap-div-icon .icon_container span,
.umap-drop-icon .icon_container span {
vertical-align: middle;
color: white;
font-weight: bold;
}
.umap-circle-icon { .umap-circle-icon {
border: 1px solid white; border: 1px solid white;
border-radius: 10px 10px 10px 10px; border-radius: 10px 10px 10px 10px;

View file

@ -31,6 +31,38 @@ describe('L.U.Marker', function () {
}); });
describe('#iconSymbolChange()', function () {
it('should change icon symbol', function () {
enableEdit();
happen.click(qs('div.umap-drop-icon'));
happen.click(qs('ul.leaflet-inplace-toolbar a.umap-toggle-edit'));
changeInputValue(qs('form#umap-feature-shape-properties .umap-field-iconUrl input[name=iconUrl]'), '1');
assert.equal(qs('div.umap-drop-icon span').textContent, '1');
changeInputValue(qs('form#umap-feature-shape-properties .umap-field-iconUrl input[name=iconUrl]'), '{name}');
assert.equal(qs('div.umap-drop-icon span').textContent, 'test');
clickCancel();
});
});
describe('#iconClassChange()', function () {
it('should change icon class', function () {
enableEdit();
happen.click(qs('div.umap-drop-icon'));
happen.click(qs('ul.leaflet-inplace-toolbar a.umap-toggle-edit'));
changeSelectValue(qs('form#umap-feature-shape-properties .umap-field-iconClass select[name=iconClass]'), 'Circle');
assert.notOk(qs('div.umap-drop-icon'));
assert.ok(qs('div.umap-circle-icon'));
happen.click(qs('form#umap-feature-shape-properties .umap-field-iconClass .undefine'));
assert.notOk(qs('div.umap-circle-icon'));
assert.ok(qs('div.umap-drop-icon'));
clickCancel();
});
});
describe('#clone', function () { describe('#clone', function () {
it('should clone marker', function () { it('should clone marker', function () {

View file

@ -44,6 +44,7 @@ var clickCancel = function () {
var changeInputValue = function (input, value) { var changeInputValue = function (input, value) {
input.value = value; input.value = value;
happen.once(input, {type: 'input'}); happen.once(input, {type: 'input'});
happen.once(input, {type: 'blur'});
}; };
var changeSelectValue = function (path_or_select, value) { var changeSelectValue = function (path_or_select, value) {
if (typeof path_or_select === 'string') path_or_select = qs(path_or_select); if (typeof path_or_select === 'string') path_or_select = qs(path_or_select);