TB-70: Map widget actions.
This commit is contained in:
parent
f7f9b8948c
commit
ecac20dc50
File diff suppressed because one or more lines are too long
@ -1220,7 +1220,9 @@ export default angular.module('thingsboard.locale', [])
|
|||||||
"custom": {
|
"custom": {
|
||||||
"widget-action": {
|
"widget-action": {
|
||||||
"action-cell-button": "Action cell button",
|
"action-cell-button": "Action cell button",
|
||||||
"row-click": "On row click"
|
"row-click": "On row click",
|
||||||
|
"marker-click": "On marker click",
|
||||||
|
"tooltip-tag-action": "Tooltip tag action"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -188,7 +188,7 @@ export default class TbGoogleMap {
|
|||||||
/* eslint-enable no-undef */
|
/* eslint-enable no-undef */
|
||||||
|
|
||||||
/* eslint-disable no-undef */
|
/* eslint-disable no-undef */
|
||||||
createMarker(location, settings, onClickListener) {
|
createMarker(location, settings, onClickListener, markerArgs) {
|
||||||
var height = 34;
|
var height = 34;
|
||||||
var pinColor = settings.color.substr(1);
|
var pinColor = settings.color.substr(1);
|
||||||
var pinImage = new google.maps.MarkerImage("http://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|" + pinColor,
|
var pinImage = new google.maps.MarkerImage("http://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|" + pinColor,
|
||||||
@ -224,7 +224,7 @@ export default class TbGoogleMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (settings.displayTooltip) {
|
if (settings.displayTooltip) {
|
||||||
this.createTooltip(marker, settings.tooltipPattern, settings.tooltipReplaceInfo);
|
this.createTooltip(marker, settings.tooltipPattern, settings.tooltipReplaceInfo, markerArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (onClickListener) {
|
if (onClickListener) {
|
||||||
@ -241,7 +241,7 @@ export default class TbGoogleMap {
|
|||||||
/* eslint-enable no-undef */
|
/* eslint-enable no-undef */
|
||||||
|
|
||||||
/* eslint-disable no-undef */
|
/* eslint-disable no-undef */
|
||||||
createTooltip(marker, pattern, replaceInfo) {
|
createTooltip(marker, pattern, replaceInfo, markerArgs) {
|
||||||
var popup = new google.maps.InfoWindow({
|
var popup = new google.maps.InfoWindow({
|
||||||
content: ''
|
content: ''
|
||||||
});
|
});
|
||||||
@ -249,6 +249,7 @@ export default class TbGoogleMap {
|
|||||||
popup.open(this.map, marker);
|
popup.open(this.map, marker);
|
||||||
});
|
});
|
||||||
this.tooltips.push( {
|
this.tooltips.push( {
|
||||||
|
markerArgs: markerArgs,
|
||||||
popup: popup,
|
popup: popup,
|
||||||
pattern: pattern,
|
pattern: pattern,
|
||||||
replaceInfo: replaceInfo
|
replaceInfo: replaceInfo
|
||||||
|
|||||||
@ -19,7 +19,7 @@ import tinycolor from 'tinycolor2';
|
|||||||
import TbGoogleMap from './google-map';
|
import TbGoogleMap from './google-map';
|
||||||
import TbOpenStreetMap from './openstreet-map';
|
import TbOpenStreetMap from './openstreet-map';
|
||||||
|
|
||||||
import {processPattern, arraysEqual, toLabelValueMap, fillPattern} from './widget-utils';
|
import {processPattern, arraysEqual, toLabelValueMap, fillPattern, fillPatternWithActions} from './widget-utils';
|
||||||
|
|
||||||
export default class TbMapWidgetV2 {
|
export default class TbMapWidgetV2 {
|
||||||
constructor(mapProvider, drawRoutes, ctx, useDynamicLocations, $element) {
|
constructor(mapProvider, drawRoutes, ctx, useDynamicLocations, $element) {
|
||||||
@ -63,6 +63,15 @@ export default class TbMapWidgetV2 {
|
|||||||
tbMap.resize();
|
tbMap.resize();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.ctx.$scope.onTooltipAction = function(event, actionName, dsIndex) {
|
||||||
|
tbMap.onTooltipAction(event, actionName, dsIndex);
|
||||||
|
};
|
||||||
|
this.tooltipActionsMap = {};
|
||||||
|
var descriptors = this.ctx.actionsApi.getActionDescriptors('tooltipAction');
|
||||||
|
descriptors.forEach(function (descriptor) {
|
||||||
|
tbMap.tooltipActionsMap[descriptor.name] = descriptor;
|
||||||
|
});
|
||||||
|
|
||||||
if (mapProvider === 'google-map') {
|
if (mapProvider === 'google-map') {
|
||||||
this.map = new TbGoogleMap($element, initCallback, this.defaultZoomLevel, this.dontFitMapBounds, minZoomLevel, settings.gmApiKey, settings.gmDefaultMapType);
|
this.map = new TbGoogleMap($element, initCallback, this.defaultZoomLevel, this.dontFitMapBounds, minZoomLevel, settings.gmApiKey, settings.gmDefaultMapType);
|
||||||
} else if (mapProvider === 'openstreet-map') {
|
} else if (mapProvider === 'openstreet-map') {
|
||||||
@ -145,6 +154,18 @@ export default class TbMapWidgetV2 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onTooltipAction(event, actionName, dsIndex) {
|
||||||
|
var descriptor = this.tooltipActionsMap[actionName];
|
||||||
|
if (descriptor) {
|
||||||
|
var datasource = this.subscription.datasources[dsIndex];
|
||||||
|
var entityId = {};
|
||||||
|
entityId.id = datasource.entityId;
|
||||||
|
entityId.entityType = datasource.entityType;
|
||||||
|
var entityName = datasource.entityName;
|
||||||
|
this.ctx.actionsApi.handleWidgetAction(event, descriptor, entityId, entityName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
update() {
|
update() {
|
||||||
|
|
||||||
var tbMap = this;
|
var tbMap = this;
|
||||||
@ -159,10 +180,11 @@ export default class TbMapWidgetV2 {
|
|||||||
|
|
||||||
function calculateLocationColor(location, dataMap) {
|
function calculateLocationColor(location, dataMap) {
|
||||||
if (location.settings.useColorFunction && location.settings.colorFunction) {
|
if (location.settings.useColorFunction && location.settings.colorFunction) {
|
||||||
var color = '#FE7569';
|
var color;
|
||||||
try {
|
try {
|
||||||
color = location.settings.colorFunction(dataMap.dataMap, dataMap.dsDataMap, location.dsIndex);
|
color = location.settings.colorFunction(dataMap.dataMap, dataMap.dsDataMap, location.dsIndex);
|
||||||
} catch (e) {
|
} catch (e) {/**/}
|
||||||
|
if (!color) {
|
||||||
color = '#FE7569';
|
color = '#FE7569';
|
||||||
}
|
}
|
||||||
return tinycolor(color).toHexString();
|
return tinycolor(color).toHexString();
|
||||||
@ -212,6 +234,18 @@ export default class TbMapWidgetV2 {
|
|||||||
updateLocationMarkerImage(location, image);
|
updateLocationMarkerImage(location, image);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function locationRowClick($event, location) {
|
||||||
|
var descriptors = tbMap.ctx.actionsApi.getActionDescriptors('markerClick');
|
||||||
|
if (descriptors.length) {
|
||||||
|
var datasource = tbMap.subscription.datasources[location.dsIndex];
|
||||||
|
var entityId = {};
|
||||||
|
entityId.id = datasource.entityId;
|
||||||
|
entityId.entityType = datasource.entityType;
|
||||||
|
var entityName = datasource.entityName;
|
||||||
|
tbMap.ctx.actionsApi.handleWidgetAction($event, descriptors[0], entityId, entityName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function updateLocation(location, data, dataMap) {
|
function updateLocation(location, data, dataMap) {
|
||||||
var locationChanged = false;
|
var locationChanged = false;
|
||||||
if (location.latIndex > -1 && location.lngIndex > -1) {
|
if (location.latIndex > -1 && location.lngIndex > -1) {
|
||||||
@ -234,9 +268,10 @@ export default class TbMapWidgetV2 {
|
|||||||
var markerLocation = latLngs[latLngs.length - 1];
|
var markerLocation = latLngs[latLngs.length - 1];
|
||||||
if (!location.marker) {
|
if (!location.marker) {
|
||||||
location.marker = tbMap.map.createMarker(markerLocation, location.settings,
|
location.marker = tbMap.map.createMarker(markerLocation, location.settings,
|
||||||
function () {
|
function (event) {
|
||||||
tbMap.callbacks.onLocationClick(location);
|
tbMap.callbacks.onLocationClick(location);
|
||||||
}
|
locationRowClick(event, location);
|
||||||
|
}, [location.dsIndex]
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
tbMap.map.setMarkerPosition(location.marker, markerLocation);
|
tbMap.map.setMarkerPosition(location.marker, markerLocation);
|
||||||
@ -259,9 +294,11 @@ export default class TbMapWidgetV2 {
|
|||||||
lng = lngData[lngData.length - 1][1];
|
lng = lngData[lngData.length - 1][1];
|
||||||
latLng = tbMap.map.createLatLng(lat, lng);
|
latLng = tbMap.map.createLatLng(lat, lng);
|
||||||
if (!location.marker) {
|
if (!location.marker) {
|
||||||
location.marker = tbMap.map.createMarker(latLng, location.settings, function () {
|
location.marker = tbMap.map.createMarker(latLng, location.settings,
|
||||||
|
function (event) {
|
||||||
tbMap.callbacks.onLocationClick(location);
|
tbMap.callbacks.onLocationClick(location);
|
||||||
});
|
locationRowClick(event, location);
|
||||||
|
}, [location.dsIndex]);
|
||||||
tbMap.markers.push(location.marker);
|
tbMap.markers.push(location.marker);
|
||||||
locationChanged = true;
|
locationChanged = true;
|
||||||
} else {
|
} else {
|
||||||
@ -368,6 +405,7 @@ export default class TbMapWidgetV2 {
|
|||||||
for (var t=0; t < tooltips.length; t++) {
|
for (var t=0; t < tooltips.length; t++) {
|
||||||
var tooltip = tooltips[t];
|
var tooltip = tooltips[t];
|
||||||
var text = fillPattern(tooltip.pattern, tooltip.replaceInfo, this.subscription.data);
|
var text = fillPattern(tooltip.pattern, tooltip.replaceInfo, this.subscription.data);
|
||||||
|
text = fillPatternWithActions(text, 'onTooltipAction', tooltip.markerArgs);
|
||||||
tooltip.popup.setContent(text);
|
tooltip.popup.setContent(text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -414,6 +452,19 @@ export default class TbMapWidgetV2 {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static actionSources() {
|
||||||
|
return {
|
||||||
|
'markerClick': {
|
||||||
|
name: 'widget-action.marker-click',
|
||||||
|
multiple: false
|
||||||
|
},
|
||||||
|
'tooltipAction': {
|
||||||
|
name: 'widget-action.tooltip-tag-action',
|
||||||
|
multiple: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const googleMapSettingsSchema =
|
const googleMapSettingsSchema =
|
||||||
@ -509,12 +560,12 @@ const commonMapSettingsSchema =
|
|||||||
"default":true
|
"default":true
|
||||||
},
|
},
|
||||||
"label":{
|
"label":{
|
||||||
"title":"Label",
|
"title":"Label (pattern examples: '${entityName}', '${entityName}: (Text ${keyName} units.)' )",
|
||||||
"type":"string",
|
"type":"string",
|
||||||
"default":"${entityName}"
|
"default":"${entityName}"
|
||||||
},
|
},
|
||||||
"tooltipPattern":{
|
"tooltipPattern":{
|
||||||
"title":"Pattern ( for ex. 'Text ${keyName} units.' or '${#<key index>} units' )",
|
"title":"Tooltip (for ex. 'Text ${keyName} units.' or <link-act name='my-action'>Link text</link-act>')",
|
||||||
"type":"string",
|
"type":"string",
|
||||||
"default":"<b>${entityName}</b><br/><br/><b>Latitude:</b> ${latitude:7}<br/><b>Longitude:</b> ${longitude:7}"
|
"default":"<b>${entityName}</b><br/><br/><b>Latitude:</b> ${latitude:7}<br/><b>Longitude:</b> ${longitude:7}"
|
||||||
},
|
},
|
||||||
@ -567,7 +618,10 @@ const commonMapSettingsSchema =
|
|||||||
"lngKeyName",
|
"lngKeyName",
|
||||||
"showLabel",
|
"showLabel",
|
||||||
"label",
|
"label",
|
||||||
"tooltipPattern",
|
{
|
||||||
|
"key": "tooltipPattern",
|
||||||
|
"type": "textarea"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"key":"color",
|
"key":"color",
|
||||||
"type":"color"
|
"type":"color"
|
||||||
|
|||||||
@ -92,7 +92,7 @@ export default class TbOpenStreetMap {
|
|||||||
testImage.src = image;
|
testImage.src = image;
|
||||||
}
|
}
|
||||||
|
|
||||||
createMarker(location, settings, onClickListener) {
|
createMarker(location, settings, onClickListener, markerArgs) {
|
||||||
var height = 34;
|
var height = 34;
|
||||||
var pinColor = settings.color.substr(1);
|
var pinColor = settings.color.substr(1);
|
||||||
var icon = L.icon({
|
var icon = L.icon({
|
||||||
@ -118,7 +118,7 @@ export default class TbOpenStreetMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (settings.displayTooltip) {
|
if (settings.displayTooltip) {
|
||||||
this.createTooltip(marker, settings.tooltipPattern, settings.tooltipReplaceInfo);
|
this.createTooltip(marker, settings.tooltipPattern, settings.tooltipReplaceInfo, markerArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (onClickListener) {
|
if (onClickListener) {
|
||||||
@ -132,11 +132,12 @@ export default class TbOpenStreetMap {
|
|||||||
this.map.removeLayer(marker);
|
this.map.removeLayer(marker);
|
||||||
}
|
}
|
||||||
|
|
||||||
createTooltip(marker, pattern, replaceInfo) {
|
createTooltip(marker, pattern, replaceInfo, markerArgs) {
|
||||||
var popup = L.popup();
|
var popup = L.popup();
|
||||||
popup.setContent('');
|
popup.setContent('');
|
||||||
marker.bindPopup(popup, {autoClose: false, closeOnClick: false});
|
marker.bindPopup(popup, {autoClose: false, closeOnClick: false});
|
||||||
this.tooltips.push( {
|
this.tooltips.push( {
|
||||||
|
markerArgs: markerArgs,
|
||||||
popup: popup,
|
popup: popup,
|
||||||
pattern: pattern,
|
pattern: pattern,
|
||||||
replaceInfo: replaceInfo
|
replaceInfo: replaceInfo
|
||||||
|
|||||||
@ -16,6 +16,9 @@
|
|||||||
|
|
||||||
const varsRegex = /\$\{([^\}]*)\}/g;
|
const varsRegex = /\$\{([^\}]*)\}/g;
|
||||||
|
|
||||||
|
const linkActionRegex = /\<link-act name=['"]([^['"]*)['"]\>([^\<]*)\<\/link-act\>/g;
|
||||||
|
const buttonActionRegex = /\<button-act name=['"]([^['"]*)['"]\>([^\<]*)\<\/button-act\>/g;
|
||||||
|
|
||||||
export function processPattern(pattern, datasources, dsIndex) {
|
export function processPattern(pattern, datasources, dsIndex) {
|
||||||
var match = varsRegex.exec(pattern);
|
var match = varsRegex.exec(pattern);
|
||||||
var replaceInfo = {};
|
var replaceInfo = {};
|
||||||
@ -90,6 +93,49 @@ export function fillPattern(pattern, replaceInfo, data) {
|
|||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createLink(actionName, actionText, actionCallbackName, additionalArgs) {
|
||||||
|
var args = 'event,\''+actionName+'\'';
|
||||||
|
if (additionalArgs && additionalArgs.length) {
|
||||||
|
args += ','+additionalArgs.join();
|
||||||
|
}
|
||||||
|
return '<a href="#" onclick="angular.element(this).scope().'+actionCallbackName+'('+args+'); return false;">'+actionText+'</a>';
|
||||||
|
}
|
||||||
|
|
||||||
|
function createButton(actionName, actionText, actionCallbackName, additionalArgs) {
|
||||||
|
var args = 'event,\''+actionName+'\'';
|
||||||
|
if (additionalArgs && additionalArgs.length) {
|
||||||
|
args += ','+additionalArgs.join();
|
||||||
|
}
|
||||||
|
return '<button onclick="angular.element(this).scope().'+actionCallbackName+'('+args+'); return false;">'+actionText+'</button>';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fillPatternWithActions(pattern, actionCallbackName, additionalArgs) {
|
||||||
|
var text = angular.copy(pattern);
|
||||||
|
var match = linkActionRegex.exec(pattern);
|
||||||
|
var actionTags;
|
||||||
|
var actionName;
|
||||||
|
var actionText;
|
||||||
|
var actionHtml;
|
||||||
|
while (match !== null) {
|
||||||
|
actionTags = match[0];
|
||||||
|
actionName = match[1];
|
||||||
|
actionText = match[2];
|
||||||
|
actionHtml = createLink(actionName, actionText, actionCallbackName, additionalArgs);
|
||||||
|
text = text.split(actionTags).join(actionHtml);
|
||||||
|
match = linkActionRegex.exec(pattern);
|
||||||
|
}
|
||||||
|
match = buttonActionRegex.exec(pattern);
|
||||||
|
while (match !== null) {
|
||||||
|
actionTags = match[0];
|
||||||
|
actionName = match[1];
|
||||||
|
actionText = match[2];
|
||||||
|
actionHtml = createButton(actionName, actionText, actionCallbackName, additionalArgs);
|
||||||
|
text = text.split(actionTags).join(actionHtml);
|
||||||
|
match = buttonActionRegex.exec(pattern);
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
export function toLabelValueMap(data, datasources) {
|
export function toLabelValueMap(data, datasources) {
|
||||||
var dataMap = {};
|
var dataMap = {};
|
||||||
var dsDataMap = [];
|
var dsDataMap = [];
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user