TB-70: Image map widget.
This commit is contained in:
		
							parent
							
								
									c0a8849784
								
							
						
					
					
						commit
						2dcf8d6ca1
					
				
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@ -81,6 +81,7 @@
 | 
			
		||||
    "schema-inspector": "^1.6.6",
 | 
			
		||||
    "split.js": "^1.0.7",
 | 
			
		||||
    "tinycolor2": "^1.4.1",
 | 
			
		||||
    "tooltipster": "^4.2.4",
 | 
			
		||||
    "typeface-roboto": "0.0.22",
 | 
			
		||||
    "v-accordion": "^1.6.0"
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										302
									
								
								ui/src/app/widget/lib/image-map.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										302
									
								
								ui/src/app/widget/lib/image-map.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,302 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
import 'tooltipster/dist/css/tooltipster.bundle.min.css';
 | 
			
		||||
import 'tooltipster/dist/js/tooltipster.bundle.min.js';
 | 
			
		||||
import 'tooltipster/dist/css/plugins/tooltipster/sideTip/themes/tooltipster-sideTip-shadow.min.css';
 | 
			
		||||
 | 
			
		||||
import './image-map.scss';
 | 
			
		||||
 | 
			
		||||
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 {
 | 
			
		||||
 | 
			
		||||
    constructor($containerElement, initCallback, imageUrl, posFunction) {
 | 
			
		||||
 | 
			
		||||
        this.tooltips = [];
 | 
			
		||||
 | 
			
		||||
        $containerElement.append('<div id="image-map-container"><div id="image-map"></div></div>');
 | 
			
		||||
 | 
			
		||||
        this.imageMapContainer = angular.element('#image-map-container', $containerElement);
 | 
			
		||||
        this.imageMap = angular.element('#image-map', $containerElement);
 | 
			
		||||
        this.aspect = 0;
 | 
			
		||||
        this.width = 0;
 | 
			
		||||
        this.height = 0;
 | 
			
		||||
        this.markers = [];
 | 
			
		||||
 | 
			
		||||
        if (!imageUrl) {
 | 
			
		||||
            imageUrl = 'data:image/svg+xml;base64,PHN2ZyBpZD0ic3ZnMiIgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMTAwIiB3aWR0aD0iMTAwIiB2ZXJzaW9uPSIxLjEiIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgdmlld0JveD0iMCAwIDEwMCAxMDAiPgogPGcgaWQ9ImxheWVyMSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAtOTUyLjM2KSI+CiAgPHJlY3QgaWQ9InJlY3Q0Njg0IiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBoZWlnaHQ9Ijk5LjAxIiB3aWR0aD0iOTkuMDEiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiB5PSI5NTIuODYiIHg9Ii40OTUwNSIgc3Ryb2tlLXdpZHRoPSIuOTkwMTAiIGZpbGw9IiNlZWUiLz4KICA8dGV4dCBpZD0idGV4dDQ2ODYiIHN0eWxlPSJ3b3JkLXNwYWNpbmc6MHB4O2xldHRlci1zcGFjaW5nOjBweDt0ZXh0LWFuY2hvcjptaWRkbGU7dGV4dC1hbGlnbjpjZW50ZXIiIGZvbnQtd2VpZ2h0PSJib2xkIiB4bWw6c3BhY2U9InByZXNlcnZlIiBmb250LXNpemU9IjEwcHgiIGxpbmUtaGVpZ2h0PSIxMjUlIiB5PSI5NzAuNzI4MDkiIHg9IjQ5LjM5NjQ3NyIgZm9udC1mYW1pbHk9IlJvYm90byIgZmlsbD0iIzY2NjY2NiI+PHRzcGFuIGlkPSJ0c3BhbjQ2OTAiIHg9IjUwLjY0NjQ3NyIgeT0iOTcwLjcyODA5Ij5JbWFnZSBiYWNrZ3JvdW5kIDwvdHNwYW4+PHRzcGFuIGlkPSJ0c3BhbjQ2OTIiIHg9IjQ5LjM5NjQ3NyIgeT0iOTgzLjIyODA5Ij5pcyBub3QgY29uZmlndXJlZDwvdHNwYW4+PC90ZXh0PgogIDxyZWN0IGlkPSJyZWN0NDY5NCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgaGVpZ2h0PSIxOS4zNiIgd2lkdGg9IjY5LjM2IiBzdHJva2U9IiMwMDAiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgeT0iOTkyLjY4IiB4PSIxNS4zMiIgc3Ryb2tlLXdpZHRoPSIuNjM5ODYiIGZpbGw9Im5vbmUiLz4KIDwvZz4KPC9zdmc+Cg==';
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.imageMap.css({backgroundImage: 'url('+imageUrl+')'});
 | 
			
		||||
 | 
			
		||||
        if (angular.isDefined(posFunction) && posFunction.length > 0) {
 | 
			
		||||
            try {
 | 
			
		||||
                this.posFunction = new Function('origXPos, origYPos', posFunction);
 | 
			
		||||
            } catch (e) {
 | 
			
		||||
                this.posFunction = null;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (!this.posFunction) {
 | 
			
		||||
            this.posFunction = (origXPos, origYPos) => {return {x: origXPos, y: origYPos}};
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var imageMap = this;
 | 
			
		||||
        var testImage = new Image(); // eslint-disable-line no-undef
 | 
			
		||||
        testImage.onload = function() {
 | 
			
		||||
            imageMap.aspect = testImage.width / testImage.height;
 | 
			
		||||
            imageMap.onresize();
 | 
			
		||||
            if (initCallback) {
 | 
			
		||||
                setTimeout(initCallback, 0); //eslint-disable-line
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        testImage.src = imageUrl;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    onresize() {
 | 
			
		||||
        if (this.aspect > 0) {
 | 
			
		||||
            var width = this.imageMapContainer.width();
 | 
			
		||||
            if (width > 0) {
 | 
			
		||||
                var height = width / this.aspect;
 | 
			
		||||
                var imageMapHeight = this.imageMapContainer.height();
 | 
			
		||||
                if (imageMapHeight > 0 && height > imageMapHeight) {
 | 
			
		||||
                    height = imageMapHeight;
 | 
			
		||||
                    width = height * this.aspect;
 | 
			
		||||
                }
 | 
			
		||||
                if (this.width !== width) {
 | 
			
		||||
                    this.width = width;
 | 
			
		||||
                    this.height = width / this.aspect;
 | 
			
		||||
                    this.imageMap.css({width: this.width, height: this.height});
 | 
			
		||||
                    this.markers.forEach((marker) => {
 | 
			
		||||
                        this.updateMarkerDimensions(marker);
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inited() {
 | 
			
		||||
        return this.aspect > 0 ? true : false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    updateMarkerLabel(marker, settings) {
 | 
			
		||||
        if (settings.showLabel) {
 | 
			
		||||
            marker.labelElement.css({color: settings.labelColor});
 | 
			
		||||
            marker.labelElement.html(`<b>${settings.labelText}</b>`);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    updateMarkerColor(marker, color) {
 | 
			
		||||
        marker.pinSvgElement.css({fill: color});
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    updateMarkerImage(marker, settings, image, maxSize) {
 | 
			
		||||
        var testImage = new Image(); // eslint-disable-line no-undef
 | 
			
		||||
        var imageMap = this;
 | 
			
		||||
        testImage.onload = function() {
 | 
			
		||||
            var width;
 | 
			
		||||
            var height;
 | 
			
		||||
            var aspect = testImage.width / testImage.height;
 | 
			
		||||
            if (aspect > 1) {
 | 
			
		||||
                width = maxSize;
 | 
			
		||||
                height = maxSize / aspect;
 | 
			
		||||
            } else {
 | 
			
		||||
                width = maxSize * aspect;
 | 
			
		||||
                height = maxSize;
 | 
			
		||||
            }
 | 
			
		||||
            var size = Math.max(width, height);
 | 
			
		||||
            marker.size = size;
 | 
			
		||||
            if (marker.imgElement) {
 | 
			
		||||
                marker.imgElement.remove();
 | 
			
		||||
            }
 | 
			
		||||
            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);
 | 
			
		||||
        }
 | 
			
		||||
        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/2;
 | 
			
		||||
        var top = marker.y * this.height - marker.size;
 | 
			
		||||
        pinElement.css({left: left, top: top});
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    createMarker(position, settings, onClickListener, markerArgs) {
 | 
			
		||||
        var marker = {
 | 
			
		||||
              size: 34,
 | 
			
		||||
              position: position
 | 
			
		||||
        };
 | 
			
		||||
        var pos = this.posFunction(position.x, position.y);
 | 
			
		||||
        marker.x = pos.x;
 | 
			
		||||
        marker.y = pos.y;
 | 
			
		||||
        marker.pinElement = angular.element('<div class="image-map-pin"></div>');
 | 
			
		||||
 | 
			
		||||
        if (settings.showLabel) {
 | 
			
		||||
            marker.labelElement = angular.element(`<div class="image-map-pin-title"><b>${settings.labelText}</b></div>`);
 | 
			
		||||
            marker.labelElement.css({color: settings.labelColor});
 | 
			
		||||
            marker.pinElement.append(marker.labelElement);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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) {
 | 
			
		||||
            this.updateMarkerImage(marker, settings, settings.markerImage, settings.markerImageSize || 34);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (settings.displayTooltip) {
 | 
			
		||||
            this.createTooltip(marker, settings.tooltipPattern, settings.tooltipReplaceInfo, markerArgs);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (onClickListener) {
 | 
			
		||||
            marker.pinElement.on('click', onClickListener);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.markers.push(marker);
 | 
			
		||||
        return marker;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    removeMarker(marker) {
 | 
			
		||||
        var index = this.markers.indexOf(marker);
 | 
			
		||||
        if (index > -1) {
 | 
			
		||||
            marker.pinElement.remove();
 | 
			
		||||
            this.markers.splice(index, 1);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    createTooltip(marker, pattern, replaceInfo, markerArgs) {
 | 
			
		||||
        var popup = new Popup(marker.pinElement);
 | 
			
		||||
        popup.setContent('');
 | 
			
		||||
        this.tooltips.push( {
 | 
			
		||||
            markerArgs: markerArgs,
 | 
			
		||||
            popup: popup,
 | 
			
		||||
            pattern: pattern,
 | 
			
		||||
            replaceInfo: replaceInfo
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    updatePolylineColor(/*polyline, settings, color*/) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    createPolyline(/*locations, settings*/) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    removePolyline(/*polyline*/) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fitBounds() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    createLatLng(x, y) {
 | 
			
		||||
        return new Position(x, y);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    extendBoundsWithMarker() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    getMarkerPosition(marker) {
 | 
			
		||||
        return marker.position;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setMarkerPosition(marker, position) {
 | 
			
		||||
        marker.position = position;
 | 
			
		||||
        var pos = this.posFunction(position.x, position.y);
 | 
			
		||||
        marker.x = pos.x;
 | 
			
		||||
        marker.y = pos.y;
 | 
			
		||||
        this.updateMarkerDimensions(marker);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    getPolylineLatLngs(/*polyline*/) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setPolylineLatLngs(/*polyline, latLngs*/) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    createBounds() {
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    extendBounds() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    invalidateSize() {
 | 
			
		||||
        this.onresize();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    getTooltips() {
 | 
			
		||||
        return this.tooltips;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class Position {
 | 
			
		||||
    constructor(x, y) {
 | 
			
		||||
        this.x = x;
 | 
			
		||||
        this.y = y;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    equals(loc) {
 | 
			
		||||
        return loc && loc.x == this.x && loc.y == this.y;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class Popup {
 | 
			
		||||
    constructor(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 flex id="tooltip-content" layout="column">' +
 | 
			
		||||
                '</div>' +
 | 
			
		||||
            '</div>');
 | 
			
		||||
        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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										98
									
								
								ui/src/app/widget/lib/image-map.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								ui/src/app/widget/lib/image-map.scss
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,98 @@
 | 
			
		||||
/**
 | 
			
		||||
 * 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: cover;
 | 
			
		||||
 | 
			
		||||
    &.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%;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -18,6 +18,7 @@ import tinycolor from 'tinycolor2';
 | 
			
		||||
 | 
			
		||||
import TbGoogleMap from './google-map';
 | 
			
		||||
import TbOpenStreetMap from './openstreet-map';
 | 
			
		||||
import TbImageMap from './image-map';
 | 
			
		||||
 | 
			
		||||
import {processPattern, arraysEqual, toLabelValueMap, fillPattern, fillPatternWithActions} from './widget-utils';
 | 
			
		||||
 | 
			
		||||
@ -25,6 +26,7 @@ export default class TbMapWidgetV2 {
 | 
			
		||||
    constructor(mapProvider, drawRoutes, ctx, useDynamicLocations, $element) {
 | 
			
		||||
        var tbMap = this;
 | 
			
		||||
        this.ctx = ctx;
 | 
			
		||||
        this.mapProvider = mapProvider;
 | 
			
		||||
        if (!$element) {
 | 
			
		||||
            $element = ctx.$container;
 | 
			
		||||
        }
 | 
			
		||||
@ -76,6 +78,8 @@ export default class TbMapWidgetV2 {
 | 
			
		||||
            this.map = new TbGoogleMap($element, initCallback, this.defaultZoomLevel, this.dontFitMapBounds, minZoomLevel, settings.gmApiKey, settings.gmDefaultMapType);
 | 
			
		||||
        } else if (mapProvider === 'openstreet-map') {
 | 
			
		||||
            this.map = new TbOpenStreetMap($element, initCallback, this.defaultZoomLevel, this.dontFitMapBounds, minZoomLevel);
 | 
			
		||||
        } else if (mapProvider === 'image-map') {
 | 
			
		||||
            this.map = new TbImageMap($element, initCallback, settings.mapImageUrl, settings.posFunction);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -109,8 +113,13 @@ export default class TbMapWidgetV2 {
 | 
			
		||||
 | 
			
		||||
    configureLocationsSettings() {
 | 
			
		||||
 | 
			
		||||
        if (this.mapProvider  == 'image-map') {
 | 
			
		||||
            this.locationSettings.latKeyName = this.ctx.settings.xPosKeyName || 'xPos';
 | 
			
		||||
            this.locationSettings.lngKeyName = this.ctx.settings.yPosKeyName || 'yPos';
 | 
			
		||||
        } else {
 | 
			
		||||
            this.locationSettings.latKeyName = this.ctx.settings.latKeyName || 'latitude';
 | 
			
		||||
            this.locationSettings.lngKeyName = this.ctx.settings.lngKeyName || 'longitude';
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.locationSettings.tooltipPattern = this.ctx.settings.tooltipPattern || "<b>${entityName}</b><br/><br/><b>Latitude:</b> ${"+this.locationSettings.latKeyName+":7}<br/><b>Longitude:</b> ${"+this.locationSettings.lngKeyName+":7}";
 | 
			
		||||
 | 
			
		||||
@ -436,6 +445,8 @@ export default class TbMapWidgetV2 {
 | 
			
		||||
            schema = angular.copy(googleMapSettingsSchema);
 | 
			
		||||
        } else if (mapProvider === 'openstreet-map') {
 | 
			
		||||
            schema = angular.copy(openstreetMapSettingsSchema);
 | 
			
		||||
        } else if (mapProvider === 'image-map') {
 | 
			
		||||
            return imageMapSettingsSchema;
 | 
			
		||||
        }
 | 
			
		||||
        angular.merge(schema.schema.properties, commonMapSettingsSchema.schema.properties);
 | 
			
		||||
        schema.schema.required = schema.schema.required.concat(commonMapSettingsSchema.schema.required);
 | 
			
		||||
@ -678,3 +689,134 @@ const routeMapSettingsSchema =
 | 
			
		||||
            "strokeOpacity"
 | 
			
		||||
        ]
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
const imageMapSettingsSchema =
 | 
			
		||||
{
 | 
			
		||||
    "schema":{
 | 
			
		||||
        "title":"Image Map Configuration",
 | 
			
		||||
        "type":"object",
 | 
			
		||||
        "properties":{
 | 
			
		||||
            "mapImageUrl": {
 | 
			
		||||
                "title": "Image map background",
 | 
			
		||||
                "type": "string",
 | 
			
		||||
                "default": "data:image/svg+xml;base64,PHN2ZyBpZD0ic3ZnMiIgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMTAwIiB3aWR0aD0iMTAwIiB2ZXJzaW9uPSIxLjEiIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgdmlld0JveD0iMCAwIDEwMCAxMDAiPgogPGcgaWQ9ImxheWVyMSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAtOTUyLjM2KSI+CiAgPHJlY3QgaWQ9InJlY3Q0Njg0IiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBoZWlnaHQ9Ijk5LjAxIiB3aWR0aD0iOTkuMDEiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiB5PSI5NTIuODYiIHg9Ii40OTUwNSIgc3Ryb2tlLXdpZHRoPSIuOTkwMTAiIGZpbGw9IiNlZWUiLz4KICA8dGV4dCBpZD0idGV4dDQ2ODYiIHN0eWxlPSJ3b3JkLXNwYWNpbmc6MHB4O2xldHRlci1zcGFjaW5nOjBweDt0ZXh0LWFuY2hvcjptaWRkbGU7dGV4dC1hbGlnbjpjZW50ZXIiIGZvbnQtd2VpZ2h0PSJib2xkIiB4bWw6c3BhY2U9InByZXNlcnZlIiBmb250LXNpemU9IjEwcHgiIGxpbmUtaGVpZ2h0PSIxMjUlIiB5PSI5NzAuNzI4MDkiIHg9IjQ5LjM5NjQ3NyIgZm9udC1mYW1pbHk9IlJvYm90byIgZmlsbD0iIzY2NjY2NiI+PHRzcGFuIGlkPSJ0c3BhbjQ2OTAiIHg9IjUwLjY0NjQ3NyIgeT0iOTcwLjcyODA5Ij5JbWFnZSBiYWNrZ3JvdW5kIDwvdHNwYW4+PHRzcGFuIGlkPSJ0c3BhbjQ2OTIiIHg9IjQ5LjM5NjQ3NyIgeT0iOTgzLjIyODA5Ij5pcyBub3QgY29uZmlndXJlZDwvdHNwYW4+PC90ZXh0PgogIDxyZWN0IGlkPSJyZWN0NDY5NCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgaGVpZ2h0PSIxOS4zNiIgd2lkdGg9IjY5LjM2IiBzdHJva2U9IiMwMDAiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgeT0iOTkyLjY4IiB4PSIxNS4zMiIgc3Ryb2tlLXdpZHRoPSIuNjM5ODYiIGZpbGw9Im5vbmUiLz4KIDwvZz4KPC9zdmc+Cg=="
 | 
			
		||||
            },
 | 
			
		||||
            "xPosKeyName":{
 | 
			
		||||
                "title":"X position key name",
 | 
			
		||||
                "type":"string",
 | 
			
		||||
                "default":"xPos"
 | 
			
		||||
            },
 | 
			
		||||
            "yPosKeyName":{
 | 
			
		||||
                "title":"Y position key name",
 | 
			
		||||
                "type":"string",
 | 
			
		||||
                "default":"yPos"
 | 
			
		||||
            },
 | 
			
		||||
            "showLabel":{
 | 
			
		||||
                "title":"Show label",
 | 
			
		||||
                "type":"boolean",
 | 
			
		||||
                "default":true
 | 
			
		||||
            },
 | 
			
		||||
            "label":{
 | 
			
		||||
                "title":"Label (pattern examples: '${entityName}', '${entityName}: (Text ${keyName} units.)' )",
 | 
			
		||||
                "type":"string",
 | 
			
		||||
                "default":"${entityName}"
 | 
			
		||||
            },
 | 
			
		||||
            "tooltipPattern":{
 | 
			
		||||
                "title":"Tooltip (for ex. 'Text ${keyName} units.' or <link-act name='my-action'>Link text</link-act>')",
 | 
			
		||||
                "type":"string",
 | 
			
		||||
                "default":"<b>${entityName}</b><br/><br/><b>X Pos:</b> ${xPos:2}<br/><b>Y Pos:</b> ${yPos:2}"
 | 
			
		||||
            },
 | 
			
		||||
            "color":{
 | 
			
		||||
                "title":"Color",
 | 
			
		||||
                "type":"string"
 | 
			
		||||
            },
 | 
			
		||||
            "posFunction":{
 | 
			
		||||
                "title":"Position conversion function: f(origXPos, origYPos), should return x,y coordinates as double from 0 to 1 each",
 | 
			
		||||
                "type":"string",
 | 
			
		||||
                "default": "return {x: origXPos, y: origYPos};"
 | 
			
		||||
            },
 | 
			
		||||
            "useColorFunction":{
 | 
			
		||||
                "title":"Use color function",
 | 
			
		||||
                "type":"boolean",
 | 
			
		||||
                "default":false
 | 
			
		||||
            },
 | 
			
		||||
            "colorFunction":{
 | 
			
		||||
                "title":"Color function: f(data, dsData, dsIndex)",
 | 
			
		||||
                "type":"string"
 | 
			
		||||
            },
 | 
			
		||||
            "markerImage":{
 | 
			
		||||
                "title":"Custom marker image",
 | 
			
		||||
                "type":"string"
 | 
			
		||||
            },
 | 
			
		||||
            "markerImageSize":{
 | 
			
		||||
                "title":"Custom marker image size (px)",
 | 
			
		||||
                "type":"number",
 | 
			
		||||
                "default":34
 | 
			
		||||
            },
 | 
			
		||||
            "useMarkerImageFunction":{
 | 
			
		||||
                "title":"Use marker image function",
 | 
			
		||||
                "type":"boolean",
 | 
			
		||||
                "default":false
 | 
			
		||||
            },
 | 
			
		||||
            "markerImageFunction":{
 | 
			
		||||
                "title":"Marker image function: f(data, images, dsData, dsIndex)",
 | 
			
		||||
                "type":"string"
 | 
			
		||||
            },
 | 
			
		||||
            "markerImages":{
 | 
			
		||||
                "title":"Marker images",
 | 
			
		||||
                "type":"array",
 | 
			
		||||
                "items":{
 | 
			
		||||
                    "title":"Marker image",
 | 
			
		||||
                    "type":"string"
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        "required":["mapImageUrl"]
 | 
			
		||||
    },
 | 
			
		||||
    "form":[
 | 
			
		||||
        {
 | 
			
		||||
            "key": "mapImageUrl",
 | 
			
		||||
            "type": "image"
 | 
			
		||||
        },
 | 
			
		||||
        "xPosKeyName",
 | 
			
		||||
        "yPosKeyName",
 | 
			
		||||
        "showLabel",
 | 
			
		||||
        "label",
 | 
			
		||||
        {
 | 
			
		||||
            "key": "tooltipPattern",
 | 
			
		||||
            "type": "textarea"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "key":"color",
 | 
			
		||||
            "type":"color"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "key":"posFunction",
 | 
			
		||||
            "type":"javascript"
 | 
			
		||||
        },
 | 
			
		||||
        "useColorFunction",
 | 
			
		||||
        {
 | 
			
		||||
            "key":"colorFunction",
 | 
			
		||||
            "type":"javascript"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "key":"markerImage",
 | 
			
		||||
            "type":"image"
 | 
			
		||||
        },
 | 
			
		||||
        "markerImageSize",
 | 
			
		||||
        "useMarkerImageFunction",
 | 
			
		||||
        {
 | 
			
		||||
            "key":"markerImageFunction",
 | 
			
		||||
            "type":"javascript"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "key":"markerImages",
 | 
			
		||||
            "items":[
 | 
			
		||||
                {
 | 
			
		||||
                    "key":"markerImages[]",
 | 
			
		||||
                    "type":"image"
 | 
			
		||||
                }
 | 
			
		||||
            ]
 | 
			
		||||
        }
 | 
			
		||||
    ]
 | 
			
		||||
};
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user