TB-70: Map widget actions.

This commit is contained in:
Igor Kulikov 2017-07-08 03:04:17 +03:00
parent f7f9b8948c
commit ecac20dc50
6 changed files with 130 additions and 26 deletions

File diff suppressed because one or more lines are too long

View File

@ -1220,7 +1220,9 @@ export default angular.module('thingsboard.locale', [])
"custom": {
"widget-action": {
"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"
}
}
}

View File

@ -188,7 +188,7 @@ export default class TbGoogleMap {
/* eslint-enable no-undef */
/* eslint-disable no-undef */
createMarker(location, settings, onClickListener) {
createMarker(location, settings, onClickListener, markerArgs) {
var height = 34;
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,
@ -224,7 +224,7 @@ export default class TbGoogleMap {
}
if (settings.displayTooltip) {
this.createTooltip(marker, settings.tooltipPattern, settings.tooltipReplaceInfo);
this.createTooltip(marker, settings.tooltipPattern, settings.tooltipReplaceInfo, markerArgs);
}
if (onClickListener) {
@ -241,7 +241,7 @@ export default class TbGoogleMap {
/* eslint-enable no-undef */
/* eslint-disable no-undef */
createTooltip(marker, pattern, replaceInfo) {
createTooltip(marker, pattern, replaceInfo, markerArgs) {
var popup = new google.maps.InfoWindow({
content: ''
});
@ -249,6 +249,7 @@ export default class TbGoogleMap {
popup.open(this.map, marker);
});
this.tooltips.push( {
markerArgs: markerArgs,
popup: popup,
pattern: pattern,
replaceInfo: replaceInfo

View File

@ -19,7 +19,7 @@ import tinycolor from 'tinycolor2';
import TbGoogleMap from './google-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 {
constructor(mapProvider, drawRoutes, ctx, useDynamicLocations, $element) {
@ -63,6 +63,15 @@ export default class TbMapWidgetV2 {
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') {
this.map = new TbGoogleMap($element, initCallback, this.defaultZoomLevel, this.dontFitMapBounds, minZoomLevel, settings.gmApiKey, settings.gmDefaultMapType);
} 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() {
var tbMap = this;
@ -159,10 +180,11 @@ export default class TbMapWidgetV2 {
function calculateLocationColor(location, dataMap) {
if (location.settings.useColorFunction && location.settings.colorFunction) {
var color = '#FE7569';
var color;
try {
color = location.settings.colorFunction(dataMap.dataMap, dataMap.dsDataMap, location.dsIndex);
} catch (e) {
} catch (e) {/**/}
if (!color) {
color = '#FE7569';
}
return tinycolor(color).toHexString();
@ -212,6 +234,18 @@ export default class TbMapWidgetV2 {
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) {
var locationChanged = false;
if (location.latIndex > -1 && location.lngIndex > -1) {
@ -234,9 +268,10 @@ export default class TbMapWidgetV2 {
var markerLocation = latLngs[latLngs.length - 1];
if (!location.marker) {
location.marker = tbMap.map.createMarker(markerLocation, location.settings,
function () {
function (event) {
tbMap.callbacks.onLocationClick(location);
}
locationRowClick(event, location);
}, [location.dsIndex]
);
} else {
tbMap.map.setMarkerPosition(location.marker, markerLocation);
@ -259,9 +294,11 @@ export default class TbMapWidgetV2 {
lng = lngData[lngData.length - 1][1];
latLng = tbMap.map.createLatLng(lat, lng);
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);
});
locationRowClick(event, location);
}, [location.dsIndex]);
tbMap.markers.push(location.marker);
locationChanged = true;
} else {
@ -368,6 +405,7 @@ export default class TbMapWidgetV2 {
for (var t=0; t < tooltips.length; t++) {
var tooltip = tooltips[t];
var text = fillPattern(tooltip.pattern, tooltip.replaceInfo, this.subscription.data);
text = fillPatternWithActions(text, 'onTooltipAction', tooltip.markerArgs);
tooltip.popup.setContent(text);
}
}
@ -414,6 +452,19 @@ export default class TbMapWidgetV2 {
return {};
}
static actionSources() {
return {
'markerClick': {
name: 'widget-action.marker-click',
multiple: false
},
'tooltipAction': {
name: 'widget-action.tooltip-tag-action',
multiple: true
}
};
}
}
const googleMapSettingsSchema =
@ -509,12 +560,12 @@ const commonMapSettingsSchema =
"default":true
},
"label":{
"title":"Label",
"title":"Label (pattern examples: '${entityName}', '${entityName}: (Text ${keyName} units.)' )",
"type":"string",
"default":"${entityName}"
},
"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",
"default":"<b>${entityName}</b><br/><br/><b>Latitude:</b> ${latitude:7}<br/><b>Longitude:</b> ${longitude:7}"
},
@ -567,7 +618,10 @@ const commonMapSettingsSchema =
"lngKeyName",
"showLabel",
"label",
"tooltipPattern",
{
"key": "tooltipPattern",
"type": "textarea"
},
{
"key":"color",
"type":"color"

View File

@ -92,7 +92,7 @@ export default class TbOpenStreetMap {
testImage.src = image;
}
createMarker(location, settings, onClickListener) {
createMarker(location, settings, onClickListener, markerArgs) {
var height = 34;
var pinColor = settings.color.substr(1);
var icon = L.icon({
@ -118,7 +118,7 @@ export default class TbOpenStreetMap {
}
if (settings.displayTooltip) {
this.createTooltip(marker, settings.tooltipPattern, settings.tooltipReplaceInfo);
this.createTooltip(marker, settings.tooltipPattern, settings.tooltipReplaceInfo, markerArgs);
}
if (onClickListener) {
@ -132,11 +132,12 @@ export default class TbOpenStreetMap {
this.map.removeLayer(marker);
}
createTooltip(marker, pattern, replaceInfo) {
createTooltip(marker, pattern, replaceInfo, markerArgs) {
var popup = L.popup();
popup.setContent('');
marker.bindPopup(popup, {autoClose: false, closeOnClick: false});
this.tooltips.push( {
markerArgs: markerArgs,
popup: popup,
pattern: pattern,
replaceInfo: replaceInfo

View File

@ -16,6 +16,9 @@
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) {
var match = varsRegex.exec(pattern);
var replaceInfo = {};
@ -90,6 +93,49 @@ export function fillPattern(pattern, replaceInfo, data) {
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) {
var dataMap = {};
var dsDataMap = [];