UI: Widgets. Improve image map.

This commit is contained in:
Igor Kulikov 2017-09-26 17:59:53 +03:00
parent c5d47bbe02
commit ec2bbbc25b
6 changed files with 180 additions and 220 deletions

View File

@ -78,7 +78,7 @@
"sizeY": 6.5, "sizeY": 6.5,
"resources": [], "resources": [],
"templateHtml": "", "templateHtml": "",
"templateCss": ".error {\n color: red;\n}\n.tb-labels {\n color: #222;\n font: 12px/1.5 \"Helvetica Neue\", Arial, Helvetica, sans-serif;\n text-align: center;\n width: 200px;\n white-space: nowrap;\n}", "templateCss": ".leaflet-zoom-box {\n\tz-index: 9;\n}\n\n.leaflet-pane { z-index: 4; }\n\n.leaflet-tile-pane { z-index: 2; }\n.leaflet-overlay-pane { z-index: 4; }\n.leaflet-shadow-pane { z-index: 5; }\n.leaflet-marker-pane { z-index: 6; }\n.leaflet-tooltip-pane { z-index: 7; }\n.leaflet-popup-pane { z-index: 8; }\n\n.leaflet-map-pane canvas { z-index: 1; }\n.leaflet-map-pane svg { z-index: 2; }\n\n.leaflet-control {\n\tz-index: 9;\n}\n.leaflet-top,\n.leaflet-bottom {\n\tz-index: 11;\n}\n\n.tb-marker-label {\n border: none;\n background: none;\n box-shadow: none;\n}\n\n.tb-marker-label:before {\n border: none;\n background: none;\n}\n",
"controllerScript": "self.onInit = function() {\n self.ctx.map = new TbMapWidgetV2('image-map', false, self.ctx);\n}\n\nself.onDataUpdated = function() {\n self.ctx.map.update();\n}\n\nself.onResize = function() {\n self.ctx.map.resize();\n}\n\nself.getSettingsSchema = function() {\n return TbMapWidgetV2.settingsSchema('image-map');\n}\n\nself.getDataKeySettingsSchema = function() {\n return TbMapWidgetV2.dataKeySettingsSchema('image-map');\n}\n\nself.actionSources = function() {\n return TbMapWidgetV2.actionSources();\n}\n\nself.onDestroy = function() {\n}\n", "controllerScript": "self.onInit = function() {\n self.ctx.map = new TbMapWidgetV2('image-map', false, self.ctx);\n}\n\nself.onDataUpdated = function() {\n self.ctx.map.update();\n}\n\nself.onResize = function() {\n self.ctx.map.resize();\n}\n\nself.getSettingsSchema = function() {\n return TbMapWidgetV2.settingsSchema('image-map');\n}\n\nself.getDataKeySettingsSchema = function() {\n return TbMapWidgetV2.dataKeySettingsSchema('image-map');\n}\n\nself.actionSources = function() {\n return TbMapWidgetV2.actionSources();\n}\n\nself.onDestroy = function() {\n}\n",
"settingsSchema": "{}", "settingsSchema": "{}",
"dataKeySettingsSchema": "{}\n", "dataKeySettingsSchema": "{}\n",

View File

@ -224,7 +224,7 @@ export default class TbGoogleMap {
} }
if (settings.displayTooltip) { if (settings.displayTooltip) {
this.createTooltip(marker, settings.tooltipPattern, settings.tooltipReplaceInfo, markerArgs); this.createTooltip(marker, settings.tooltipPattern, settings.tooltipReplaceInfo, settings.autocloseTooltip, markerArgs);
} }
if (onClickListener) { if (onClickListener) {
@ -241,11 +241,17 @@ export default class TbGoogleMap {
/* eslint-enable no-undef */ /* eslint-enable no-undef */
/* eslint-disable no-undef */ /* eslint-disable no-undef */
createTooltip(marker, pattern, replaceInfo, markerArgs) { createTooltip(marker, pattern, replaceInfo, autoClose, markerArgs) {
var popup = new google.maps.InfoWindow({ var popup = new google.maps.InfoWindow({
content: '' content: ''
}); });
var map = this;
marker.addListener('click', function() { marker.addListener('click', function() {
if (autoClose) {
map.tooltips.forEach((tooltip) => {
tooltip.popup.close();
});
}
popup.open(this.map, marker); popup.open(this.map, marker);
}); });
this.tooltips.push( { this.tooltips.push( {

View File

@ -14,15 +14,10 @@
* limitations under the License. * limitations under the License.
*/ */
import 'tooltipster/dist/css/tooltipster.bundle.min.css'; import 'leaflet/dist/leaflet.css';
import 'tooltipster/dist/js/tooltipster.bundle.min.js'; import L from 'leaflet/dist/leaflet';
import 'tooltipster/dist/css/plugins/tooltipster/sideTip/themes/tooltipster-sideTip-shadow.min.css';
import './image-map.scss'; const maxZoom = 4;
const pinShape = '<path id="pin" d="m 12.033721,23.509909 c 0.165665,-3.220958 1.940547,-8.45243 4.512974,-11.745035 1.401507,-1.7940561 2.046337,-3.5425327 2.046337,-4.6032909 0,-3.6844827 -2.951858,-6.67149197 -6.592948,-6.67149197 l -1.68e-4,0 c -3.6412584,0 -6.5929483,2.98700927 -6.5929483,6.67149197 0,1.0607582 0.6448307,2.8092348 2.0463367,4.6032909 2.5724276,3.292605 4.3471416,8.524077 4.5129736,11.745035 l 0.06745,0 z" style="fill:#f2756a;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-opacity:1"/>';
const circleShape = '<circle id="circle" fill-rule="evenodd" cy="6.9234" cx="12" clip-rule="evenodd" r="1.5"/>';
const pinSvg = `<svg class="image-map-pin-image" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">${pinShape}${circleShape}</svg>`;
export default class TbImageMap { export default class TbImageMap {
@ -31,10 +26,9 @@ export default class TbImageMap {
this.ctx = ctx; this.ctx = ctx;
this.tooltips = []; this.tooltips = [];
$containerElement.append('<div id="image-map-container"><div id="image-map"></div></div>'); this.$containerElement = $containerElement;
this.$containerElement.css('background', '#fff');
this.imageMapContainer = angular.element('#image-map-container', $containerElement);
this.imageMap = angular.element('#image-map', $containerElement);
this.aspect = 0; this.aspect = 0;
this.width = 0; this.width = 0;
this.height = 0; this.height = 0;
@ -108,7 +102,7 @@ export default class TbImageMap {
if (keyData && keyData.data && keyData.data[0]) { if (keyData && keyData.data && keyData.data[0]) {
var attrValue = keyData.data[0][1]; var attrValue = keyData.data[0][1];
if (attrValue && attrValue.length) { if (attrValue && attrValue.length) {
this.loadImage(attrValue, this.aspect > 0 ? null : this.initCallback); this.loadImage(attrValue, this.aspect > 0 ? null : this.initCallback, true);
} }
} }
} }
@ -117,72 +111,145 @@ export default class TbImageMap {
} }
} }
loadImage(imageUrl, initCallback) { loadImage(imageUrl, initCallback, updateImage) {
if (!imageUrl) { if (!imageUrl) {
imageUrl = 'data:image/svg+xml;base64,PHN2ZyBpZD0ic3ZnMiIgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMTAwIiB3aWR0aD0iMTAwIiB2ZXJzaW9uPSIxLjEiIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgdmlld0JveD0iMCAwIDEwMCAxMDAiPgogPGcgaWQ9ImxheWVyMSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAtOTUyLjM2KSI+CiAgPHJlY3QgaWQ9InJlY3Q0Njg0IiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBoZWlnaHQ9Ijk5LjAxIiB3aWR0aD0iOTkuMDEiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiB5PSI5NTIuODYiIHg9Ii40OTUwNSIgc3Ryb2tlLXdpZHRoPSIuOTkwMTAiIGZpbGw9IiNlZWUiLz4KICA8dGV4dCBpZD0idGV4dDQ2ODYiIHN0eWxlPSJ3b3JkLXNwYWNpbmc6MHB4O2xldHRlci1zcGFjaW5nOjBweDt0ZXh0LWFuY2hvcjptaWRkbGU7dGV4dC1hbGlnbjpjZW50ZXIiIGZvbnQtd2VpZ2h0PSJib2xkIiB4bWw6c3BhY2U9InByZXNlcnZlIiBmb250LXNpemU9IjEwcHgiIGxpbmUtaGVpZ2h0PSIxMjUlIiB5PSI5NzAuNzI4MDkiIHg9IjQ5LjM5NjQ3NyIgZm9udC1mYW1pbHk9IlJvYm90byIgZmlsbD0iIzY2NjY2NiI+PHRzcGFuIGlkPSJ0c3BhbjQ2OTAiIHg9IjUwLjY0NjQ3NyIgeT0iOTcwLjcyODA5Ij5JbWFnZSBiYWNrZ3JvdW5kIDwvdHNwYW4+PHRzcGFuIGlkPSJ0c3BhbjQ2OTIiIHg9IjQ5LjM5NjQ3NyIgeT0iOTgzLjIyODA5Ij5pcyBub3QgY29uZmlndXJlZDwvdHNwYW4+PC90ZXh0PgogIDxyZWN0IGlkPSJyZWN0NDY5NCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgaGVpZ2h0PSIxOS4zNiIgd2lkdGg9IjY5LjM2IiBzdHJva2U9IiMwMDAiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgeT0iOTkyLjY4IiB4PSIxNS4zMiIgc3Ryb2tlLXdpZHRoPSIuNjM5ODYiIGZpbGw9Im5vbmUiLz4KIDwvZz4KPC9zdmc+Cg=='; imageUrl = 'data:image/svg+xml;base64,PHN2ZyBpZD0ic3ZnMiIgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMTAwIiB3aWR0aD0iMTAwIiB2ZXJzaW9uPSIxLjEiIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgdmlld0JveD0iMCAwIDEwMCAxMDAiPgogPGcgaWQ9ImxheWVyMSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAtOTUyLjM2KSI+CiAgPHJlY3QgaWQ9InJlY3Q0Njg0IiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBoZWlnaHQ9Ijk5LjAxIiB3aWR0aD0iOTkuMDEiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiB5PSI5NTIuODYiIHg9Ii40OTUwNSIgc3Ryb2tlLXdpZHRoPSIuOTkwMTAiIGZpbGw9IiNlZWUiLz4KICA8dGV4dCBpZD0idGV4dDQ2ODYiIHN0eWxlPSJ3b3JkLXNwYWNpbmc6MHB4O2xldHRlci1zcGFjaW5nOjBweDt0ZXh0LWFuY2hvcjptaWRkbGU7dGV4dC1hbGlnbjpjZW50ZXIiIGZvbnQtd2VpZ2h0PSJib2xkIiB4bWw6c3BhY2U9InByZXNlcnZlIiBmb250LXNpemU9IjEwcHgiIGxpbmUtaGVpZ2h0PSIxMjUlIiB5PSI5NzAuNzI4MDkiIHg9IjQ5LjM5NjQ3NyIgZm9udC1mYW1pbHk9IlJvYm90byIgZmlsbD0iIzY2NjY2NiI+PHRzcGFuIGlkPSJ0c3BhbjQ2OTAiIHg9IjUwLjY0NjQ3NyIgeT0iOTcwLjcyODA5Ij5JbWFnZSBiYWNrZ3JvdW5kIDwvdHNwYW4+PHRzcGFuIGlkPSJ0c3BhbjQ2OTIiIHg9IjQ5LjM5NjQ3NyIgeT0iOTgzLjIyODA5Ij5pcyBub3QgY29uZmlndXJlZDwvdHNwYW4+PC90ZXh0PgogIDxyZWN0IGlkPSJyZWN0NDY5NCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgaGVpZ2h0PSIxOS4zNiIgd2lkdGg9IjY5LjM2IiBzdHJva2U9IiMwMDAiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgeT0iOTkyLjY4IiB4PSIxNS4zMiIgc3Ryb2tlLXdpZHRoPSIuNjM5ODYiIGZpbGw9Im5vbmUiLz4KIDwvZz4KPC9zdmc+Cg==';
} }
this.imageMap.css({backgroundImage: 'url('+imageUrl+')'}); this.imageUrl = imageUrl;
var imageMap = this; var imageMap = this;
var testImage = document.createElement('img'); // eslint-disable-line var testImage = document.createElement('img'); // eslint-disable-line
testImage.style.visibility = 'hidden'; testImage.style.visibility = 'hidden';
testImage.onload = function() { testImage.onload = function() {
imageMap.aspect = testImage.width / testImage.height; imageMap.aspect = testImage.width / testImage.height;
document.body.removeChild(testImage); //eslint-disable-line document.body.removeChild(testImage); //eslint-disable-line
imageMap.onresize(); imageMap.onresize(updateImage);
if (initCallback) { if (initCallback) {
setTimeout(initCallback, 0); //eslint-disable-line setTimeout(initCallback, 0); //eslint-disable-line
} else {
imageMap.onresize();
} }
} }
document.body.appendChild(testImage); //eslint-disable-line document.body.appendChild(testImage); //eslint-disable-line
testImage.src = imageUrl; testImage.src = imageUrl;
} }
onresize() { onresize(updateImage) {
if (this.aspect > 0) { if (this.aspect > 0) {
var width = this.imageMapContainer.width(); var width = this.$containerElement.width();
if (width > 0) { if (width > 0) {
var height = width / this.aspect; var height = width / this.aspect;
var imageMapHeight = this.imageMapContainer.height(); var imageMapHeight = this.$containerElement.height();
if (imageMapHeight > 0 && height > imageMapHeight) { if (imageMapHeight > 0 && height > imageMapHeight) {
height = imageMapHeight; height = imageMapHeight;
width = height * this.aspect; width = height * this.aspect;
} }
width *= maxZoom;
var prevWidth = this.width;
var prevHeight = this.height;
if (this.width !== width) { if (this.width !== width) {
this.width = width; this.width = width;
this.height = width / this.aspect; this.height = width / this.aspect;
this.imageMap.css({width: this.width, height: this.height}); if (!this.map) {
this.markers.forEach((marker) => { this.initMap(updateImage);
this.updateMarkerDimensions(marker); } else {
}); var lastCenterPos = this.latLngToPoint(this.map.getCenter());
lastCenterPos.x /= prevWidth;
lastCenterPos.y /= prevHeight;
this.updateBounds(updateImage, lastCenterPos);
this.map.invalidateSize(true);
this.updateMarkers();
}
} }
} }
} }
} }
inited() { initMap(updateImage) {
return this.aspect > 0 ? true : false; if (!this.map && this.aspect > 0) {
} var center = this.pointToLatLng(this.width/2, this.height/2);
this.map = L.map(this.$containerElement[0], {
updateMarkerLabel(marker, settings) { minZoom: 1,
if (settings.showLabel) { maxZoom: maxZoom,
marker.labelElement.css({color: settings.labelColor}); center: center,
marker.labelElement.html(`<b>${settings.labelText}</b>`); zoom: 1,
crs: L.CRS.Simple,
attributionControl: false
});
this.updateBounds(updateImage);
this.updateMarkers();
} }
} }
pointToLatLng(x, y) {
return L.CRS.Simple.pointToLatLng({x:x, y:y}, maxZoom-1);
}
latLngToPoint(latLng) {
return L.CRS.Simple.latLngToPoint(latLng, maxZoom-1);
}
inited() {
return angular.isDefined(this.map);
}
updateBounds(updateImage, lastCenterPos) {
var w = this.width;
var h = this.height;
var southWest = this.pointToLatLng(0, h);
var northEast = this.pointToLatLng(w, 0);
var bounds = new L.LatLngBounds(southWest, northEast);
if (updateImage && this.imageOverlay) {
this.imageOverlay.remove();
this.imageOverlay = null;
}
if (this.imageOverlay) {
this.imageOverlay.setBounds(bounds);
} else {
this.imageOverlay = L.imageOverlay(this.imageUrl, bounds).addTo(this.map);
}
var padding = 200 * maxZoom;
southWest = this.pointToLatLng(-padding, h + padding);
northEast = this.pointToLatLng(w+padding, -padding);
var maxBounds = new L.LatLngBounds(southWest, northEast);
this.map.setMaxBounds(maxBounds);
if (lastCenterPos) {
lastCenterPos.x *= w;
lastCenterPos.y *= h;
var center = this.pointToLatLng(lastCenterPos.x, lastCenterPos.y);
this.ctx.$scope.$injector.get('$mdUtil').nextTick(() => {
this.map.panTo(center, {animate: false});
});
}
}
updateMarkerLabel(marker, settings) {
marker.unbindTooltip();
marker.bindTooltip('<div style="color: '+ settings.labelColor +';"><b>'+settings.labelText+'</b></div>',
{ className: 'tb-marker-label', permanent: true, direction: 'top', offset: marker.tooltipOffset });
}
updateMarkerColor(marker, color) { updateMarkerColor(marker, color) {
marker.pinSvgElement.css({fill: color}); var pinColor = color.substr(1);
var icon = L.icon({
iconUrl: 'https://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|' + pinColor,
iconSize: [21, 34],
iconAnchor: [10, 34],
popupAnchor: [0, -34],
shadowUrl: 'https://chart.apis.google.com/chart?chst=d_map_pin_shadow',
shadowSize: [40, 37],
shadowAnchor: [12, 35]
});
marker.setIcon(icon);
} }
updateMarkerImage(marker, settings, image, maxSize) { updateMarkerImage(marker, settings, image, maxSize) {
var testImage = new Image(); // eslint-disable-line no-undef var testImage = document.createElement('img'); // eslint-disable-line
var imageMap = this; testImage.style.visibility = 'hidden';
testImage.onload = function() { testImage.onload = function() {
var width; var width;
var height; var height;
var aspect = testImage.width / testImage.height; var aspect = testImage.width / testImage.height;
document.body.removeChild(testImage); //eslint-disable-line
if (aspect > 1) { if (aspect > 1) {
width = maxSize; width = maxSize;
height = maxSize / aspect; height = maxSize / aspect;
@ -190,74 +257,79 @@ export default class TbImageMap {
width = maxSize * aspect; width = maxSize * aspect;
height = maxSize; height = maxSize;
} }
var size = Math.max(width, height); var icon = L.icon({
marker.size = size; iconUrl: image,
if (marker.imgElement) { iconSize: [width, height],
marker.imgElement.remove(); iconAnchor: [marker.offsetX * width, marker.offsetY * height],
popupAnchor: [0, -height]
});
marker.setIcon(icon);
if (settings.showLabel) {
marker.unbindTooltip();
marker.tooltipOffset = [0, -height * marker.offsetY + 10];
marker.bindTooltip('<div style="color: '+ settings.labelColor +';"><b>'+settings.labelText+'</b></div>',
{ className: 'tb-marker-label', permanent: true, direction: 'top', offset: marker.tooltipOffset });
} }
marker.imgElement = angular.element(`<img src="${image}" aria-label="pin" class="image-map-pin-image"/>`);
var left = (size - width)/2;
var top = (size - height)/2;
marker.imgElement.css({width: width, height: height, left: left, top: top});
marker.pinElement.append(marker.imgElement);
imageMap.updateMarkerDimensions(marker);
} }
document.body.appendChild(testImage); //eslint-disable-line
testImage.src = image; testImage.src = image;
} }
updateMarkerDimensions(marker) {
var pinElement = marker.pinElement;
pinElement.css({width: marker.size, height: marker.size});
var left = marker.x * this.width - marker.size * marker.offsetX;
var top = marker.y * this.height - marker.size * marker.offsetY;
pinElement.css({left: left, top: top});
}
createMarker(position, settings, onClickListener, markerArgs) { createMarker(position, settings, onClickListener, markerArgs) {
var marker = { var height = 34;
size: 34, var pinColor = settings.color.substr(1);
position: position var icon = L.icon({
}; iconUrl: 'https://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|' + pinColor,
iconSize: [21, 34],
iconAnchor: [21 * settings.markerOffsetX, 34 * settings.markerOffsetY],
popupAnchor: [0, -34],
shadowUrl: 'https://chart.apis.google.com/chart?chst=d_map_pin_shadow',
shadowSize: [40, 37],
shadowAnchor: [12, 35]
});
var pos = this.posFunction(position.x, position.y); var pos = this.posFunction(position.x, position.y);
marker.x = pos.x; var x = pos.x * this.width;
marker.y = pos.y; var y = pos.y * this.height;
var location = this.pointToLatLng(x, y);
var marker = L.marker(location, {icon: icon}).addTo(this.map);
marker.position = position;
marker.offsetX = settings.markerOffsetX; marker.offsetX = settings.markerOffsetX;
marker.offsetY = settings.markerOffsetY; marker.offsetY = settings.markerOffsetY;
marker.pinElement = angular.element('<div class="image-map-pin"></div>');
if (settings.showLabel) { if (settings.showLabel) {
marker.labelElement = angular.element(`<div class="image-map-pin-title"><b>${settings.labelText}</b></div>`); marker.tooltipOffset = [0, -height * marker.offsetY + 10];
marker.labelElement.css({color: settings.labelColor}); marker.bindTooltip('<div style="color: '+ settings.labelColor +';"><b>'+settings.labelText+'</b></div>',
marker.pinElement.append(marker.labelElement); { className: 'tb-marker-label', permanent: true, direction: 'top', offset: marker.tooltipOffset });
} }
marker.imgElement = angular.element(pinSvg);
marker.pinSvgElement = marker.imgElement.find('#pin');
marker.pinElement.append(marker.imgElement);
marker.pinSvgElement.css({fill: settings.color});
this.updateMarkerDimensions(marker);
this.imageMap.append(marker.pinElement);
if (settings.useMarkerImage) { if (settings.useMarkerImage) {
this.updateMarkerImage(marker, settings, settings.markerImage, settings.markerImageSize || 34); this.updateMarkerImage(marker, settings, settings.markerImage, settings.markerImageSize || 34);
} }
if (settings.displayTooltip) { if (settings.displayTooltip) {
this.createTooltip(marker, settings.tooltipPattern, settings.tooltipReplaceInfo, markerArgs); this.createTooltip(marker, settings.tooltipPattern, settings.tooltipReplaceInfo, settings.autocloseTooltip, markerArgs);
} }
if (onClickListener) { if (onClickListener) {
marker.pinElement.on('click', onClickListener); marker.on('click', onClickListener);
} }
this.markers.push(marker); this.markers.push(marker);
return marker; return marker;
} }
updateMarkers() {
this.markers.forEach((marker) => {
this.updateMarkerLocation(marker);
});
}
updateMarkerLocation(marker) {
this.setMarkerPosition(marker, marker.position);
}
removeMarker(marker) { removeMarker(marker) {
this.map.removeLayer(marker);
var index = this.markers.indexOf(marker); var index = this.markers.indexOf(marker);
if (index > -1) { if (index > -1) {
marker.pinElement.remove(); marker.pinElement.remove();
@ -265,9 +337,10 @@ export default class TbImageMap {
} }
} }
createTooltip(marker, pattern, replaceInfo, markerArgs) { createTooltip(marker, pattern, replaceInfo, autoClose, markerArgs) {
var popup = new Popup(this.ctx, marker.pinElement); var popup = L.popup();
popup.setContent(''); popup.setContent('');
marker.bindPopup(popup, {autoClose: autoClose, closeOnClick: false});
this.tooltips.push( { this.tooltips.push( {
markerArgs: markerArgs, markerArgs: markerArgs,
popup: popup, popup: popup,
@ -302,9 +375,10 @@ export default class TbImageMap {
setMarkerPosition(marker, position) { setMarkerPosition(marker, position) {
marker.position = position; marker.position = position;
var pos = this.posFunction(position.x, position.y); var pos = this.posFunction(position.x, position.y);
marker.x = pos.x; var x = pos.x * this.width;
marker.y = pos.y; var y = pos.y * this.height;
this.updateMarkerDimensions(marker); var location = this.pointToLatLng(x, y);
marker.setLatLng(location);
} }
getPolylineLatLngs(/*polyline*/) { getPolylineLatLngs(/*polyline*/) {
@ -340,38 +414,3 @@ class Position {
return loc && loc.x == this.x && loc.y == this.y; return loc && loc.x == this.x && loc.y == this.y;
} }
} }
class Popup {
constructor(ctx, anchor) {
anchor.tooltipster(
{
theme: 'tooltipster-shadow',
delay: 100,
trigger: 'custom',
triggerOpen: {
click: true,
tap: true
},
trackOrigin: true
}
);
this.tooltip = anchor.tooltipster('instance');
var contentElement = angular.element('<div class="image-map-pin-tooltip">' +
'<a class="image-map-pin-tooltip-close-button" id="close" style="outline: none;">×</a>' +
'<div id="tooltip-content">' +
'</div>' +
'</div>');
var $compile = ctx.$scope.$injector.get('$compile');
$compile(contentElement)(ctx.$scope);
var popup = this;
contentElement.find('#close').on('click', function() {
popup.tooltip.close();
});
this.content = contentElement.find('#tooltip-content');
this.tooltip.content(contentElement);
}
setContent(content) {
this.content.html(content);
}
}

View File

@ -1,98 +0,0 @@
/**
* Copyright © 2016-2017 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
.image-map-pin-tooltip {
pointer-events: all;
padding: 5px;
.image-map-pin-tooltip-close-button {
cursor: pointer;
position: absolute;
top: 0;
right: 0;
padding: 6px 6px 0 0;
border: none;
text-align: center;
width: 20px;
height: 16px;
font: 18px/16px Tahoma, Verdana, sans-serif;
color: #b0b0b0;
text-decoration: none;
font-weight: bold;
background: transparent;
&:hover {
color: #919191;
}
}
#tooltip-content {
line-height: normal;
font-size: 13px;
font-weight: 300;
color: #333;
}
}
#image-map-container {
width: 100%;
height: 100%;
#image-map {
color: rgba(0, 0, 0, 0.870588);
position: relative;
margin: auto;
background: transparent no-repeat scroll 0 0;
background-size: 100% 100%;
&.is-pointer {
cursor: pointer !important;
}
.movable {
cursor: move;
}
.image-map-pin {
outline: none;
position: absolute;
background: none;
.image-map-pin-title {
position: relative;
white-space: nowrap;
text-align: center;
line-height: 1.5;
font-size: 12px;
font-weight: 400;
top: -20px;
&:before {
content: "";
margin-left: -100%;
}
&:after {
content: "";
margin-right: -100%;
}
}
.image-map-pin-image {
position: absolute;
pointer-events: none;
top: 0;
bottom: 0;
right: 0;
left: 0;
width: 100%;
height: 100%;
}
}
}
}

View File

@ -131,6 +131,7 @@ export default class TbMapWidgetV2 {
this.locationSettings.showLabel = this.ctx.settings.showLabel !== false; this.locationSettings.showLabel = this.ctx.settings.showLabel !== false;
this.locationSettings.displayTooltip = this.ctx.settings.showTooltip !== false; this.locationSettings.displayTooltip = this.ctx.settings.showTooltip !== false;
this.locationSettings.autocloseTooltip = this.ctx.settings.autocloseTooltip !== false;
this.locationSettings.labelColor = this.ctx.widgetConfig.color || '#000000', this.locationSettings.labelColor = this.ctx.widgetConfig.color || '#000000',
this.locationSettings.label = this.ctx.settings.label || "${entityName}"; this.locationSettings.label = this.ctx.settings.label || "${entityName}";
this.locationSettings.color = this.ctx.settings.color ? tinycolor(this.ctx.settings.color).toHexString() : "#FE7569"; this.locationSettings.color = this.ctx.settings.color ? tinycolor(this.ctx.settings.color).toHexString() : "#FE7569";
@ -586,6 +587,11 @@ const commonMapSettingsSchema =
"type":"boolean", "type":"boolean",
"default":true "default":true
}, },
"autocloseTooltip": {
"title": "Auto-close tooltips",
"type":"boolean",
"default":true
},
"tooltipPattern":{ "tooltipPattern":{
"title":"Tooltip (for ex. 'Text ${keyName} units.' or <link-act name='my-action'>Link text</link-act>')", "title":"Tooltip (for ex. 'Text ${keyName} units.' or <link-act name='my-action'>Link text</link-act>')",
"type":"string", "type":"string",
@ -641,6 +647,7 @@ const commonMapSettingsSchema =
"showLabel", "showLabel",
"label", "label",
"showTooltip", "showTooltip",
"autocloseTooltip",
{ {
"key": "tooltipPattern", "key": "tooltipPattern",
"type": "textarea" "type": "textarea"
@ -748,6 +755,11 @@ const imageMapSettingsSchema =
"type":"boolean", "type":"boolean",
"default":true "default":true
}, },
"autocloseTooltip": {
"title": "Auto-close tooltips",
"type":"boolean",
"default":true
},
"tooltipPattern":{ "tooltipPattern":{
"title":"Tooltip (for ex. 'Text ${keyName} units.' or <link-act name='my-action'>Link text</link-act>')", "title":"Tooltip (for ex. 'Text ${keyName} units.' or <link-act name='my-action'>Link text</link-act>')",
"type":"string", "type":"string",
@ -822,6 +834,7 @@ const imageMapSettingsSchema =
"showLabel", "showLabel",
"label", "label",
"showTooltip", "showTooltip",
"autocloseTooltip",
{ {
"key": "tooltipPattern", "key": "tooltipPattern",
"type": "textarea" "type": "textarea"

View File

@ -118,7 +118,7 @@ export default class TbOpenStreetMap {
} }
if (settings.displayTooltip) { if (settings.displayTooltip) {
this.createTooltip(marker, settings.tooltipPattern, settings.tooltipReplaceInfo, markerArgs); this.createTooltip(marker, settings.tooltipPattern, settings.tooltipReplaceInfo, settings.autocloseTooltip, markerArgs);
} }
if (onClickListener) { if (onClickListener) {
@ -132,10 +132,10 @@ export default class TbOpenStreetMap {
this.map.removeLayer(marker); this.map.removeLayer(marker);
} }
createTooltip(marker, pattern, replaceInfo, markerArgs) { createTooltip(marker, pattern, replaceInfo, autoClose, markerArgs) {
var popup = L.popup(); var popup = L.popup();
popup.setContent(''); popup.setContent('');
marker.bindPopup(popup, {autoClose: false, closeOnClick: false}); marker.bindPopup(popup, {autoClose: autoClose, closeOnClick: false});
this.tooltips.push( { this.tooltips.push( {
markerArgs: markerArgs, markerArgs: markerArgs,
popup: popup, popup: popup,