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": { "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"
} }
} }
} }

View File

@ -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

View File

@ -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,
tbMap.callbacks.onLocationClick(location); function (event) {
}); 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"

View File

@ -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

View File

@ -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 = [];