49 changed files with 5548 additions and 1854 deletions
File diff suppressed because one or more lines are too long
@ -0,0 +1,50 @@ |
|||
/* |
|||
* 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. |
|||
*/ |
|||
|
|||
export default angular.module('thingsboard.raf', []) |
|||
.provider('tbRaf', TbRAFProvider) |
|||
.name; |
|||
|
|||
function TbRAFProvider() { |
|||
/*@ngInject*/ |
|||
this.$get = function($window, $timeout) { |
|||
var requestAnimationFrame = $window.requestAnimationFrame || |
|||
$window.webkitRequestAnimationFrame; |
|||
|
|||
var cancelAnimationFrame = $window.cancelAnimationFrame || |
|||
$window.webkitCancelAnimationFrame || |
|||
$window.webkitCancelRequestAnimationFrame; |
|||
|
|||
var rafSupported = !!requestAnimationFrame; |
|||
var raf = rafSupported |
|||
? function(fn) { |
|||
var id = requestAnimationFrame(fn); |
|||
return function() { |
|||
cancelAnimationFrame(id); |
|||
}; |
|||
} |
|||
: function(fn) { |
|||
var timer = $timeout(fn, 16.66, false); |
|||
return function() { |
|||
$timeout.cancel(timer); |
|||
}; |
|||
}; |
|||
|
|||
raf.supported = rafSupported; |
|||
|
|||
return raf; |
|||
}; |
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
/** |
|||
* 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. |
|||
*/ |
|||
.tb-widget { |
|||
.tb-widget-error { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
background: rgba(255,255,255,0.5); |
|||
span { |
|||
color: red; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,701 @@ |
|||
/* |
|||
* 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. |
|||
*/ |
|||
|
|||
export default angular.module('thingsboard.locale', []) |
|||
.constant('locales', |
|||
{ |
|||
'en_US': { |
|||
"access": { |
|||
"unauthorized": "Unauthorized", |
|||
"unauthorized-access": "Unauthorized Access", |
|||
"unauthorized-access-text": "You should sign in to have access to this resource!", |
|||
"access-forbidden": "Access Forbidden", |
|||
"access-forbidden-text": "You haven't access rights to this location!<br/>Try to sign in with different user if you still wish to gain access to this location.", |
|||
"refresh-token-expired": "Session has expired", |
|||
"refresh-token-failed": "Unable to refresh session" |
|||
}, |
|||
"action": { |
|||
"activate": "Activate", |
|||
"suspend": "Suspend", |
|||
"save": "Save", |
|||
"saveAs": "Save as", |
|||
"cancel": "Cancel", |
|||
"ok": "OK", |
|||
"delete": "Delete", |
|||
"add": "Add", |
|||
"yes": "Yes", |
|||
"no": "No", |
|||
"update": "Update", |
|||
"remove": "Remove", |
|||
"search": "Search", |
|||
"assign": "Assign", |
|||
"unassign": "Unassign", |
|||
"apply": "Apply", |
|||
"apply-changes": "Apply changes", |
|||
"edit-mode": "Edit mode", |
|||
"enter-edit-mode": "Enter edit mode", |
|||
"decline-changes": "Decline changes", |
|||
"close": "Close", |
|||
"back": "Back", |
|||
"run": "Run", |
|||
"sign-in": "Sign in!", |
|||
"edit": "Edit", |
|||
"view": "View", |
|||
"create": "Create", |
|||
"drag": "Drag", |
|||
"refresh": "Refresh", |
|||
"undo": "Undo", |
|||
"copy": "Copy", |
|||
"paste": "Paste", |
|||
"import": "Import", |
|||
"export": "Export" |
|||
}, |
|||
"admin": { |
|||
"general": "General", |
|||
"general-settings": "General Settings", |
|||
"outgoing-mail": "Outgoing Mail", |
|||
"outgoing-mail-settings": "Outgoing Mail Settings", |
|||
"system-settings": "System Settings", |
|||
"test-mail-sent": "Test mail was successfully sent!", |
|||
"base-url": "Base URL", |
|||
"base-url-required": "Base URL is required.", |
|||
"mail-from": "Mail From", |
|||
"mail-from-required": "Mail From is required.", |
|||
"smtp-protocol": "SMTP protocol", |
|||
"smtp-host": "SMTP host", |
|||
"smtp-host-required": "SMTP host is required.", |
|||
"smtp-port": "SMTP port", |
|||
"smtp-port-required": "You must supply a smtp port.", |
|||
"smtp-port-invalid": "That doesn't look like a valid smtp port.", |
|||
"timeout-msec": "Timeout (msec)", |
|||
"timeout-required": "Timeout is required.", |
|||
"timeout-invalid": "That doesn't look like a valid timeout.", |
|||
"enable-tls": "Enable TLS", |
|||
"send-test-mail": "Send test mail" |
|||
}, |
|||
"attribute": { |
|||
"attributes": "Attributes", |
|||
"latest-telemetry": "Latest telemetry", |
|||
"attributes-scope": "Device attributes scope", |
|||
"scope-latest-telemetry": "Latest telemetry", |
|||
"scope-client": "Client attributes", |
|||
"scope-server": "Server attributes", |
|||
"scope-shared": "Shared attributes", |
|||
"add": "Add attribute", |
|||
"key": "Key", |
|||
"key-required": "Attribute key is required.", |
|||
"value": "Value", |
|||
"value-required": "Attribute value is required.", |
|||
"delete-attributes-title": "Are you sure you want to delete { count, select, 1 {1 attribute} other {# attributes} }?", |
|||
"delete-attributes-text": "Be careful, after the confirmation all selected attributes will be removed.", |
|||
"delete-attributes": "Delete attributes", |
|||
"enter-attribute-value": "Enter attribute value", |
|||
"show-on-widget": "Show on widget", |
|||
"widget-mode": "Widget mode", |
|||
"next-widget": "Next widget", |
|||
"prev-widget": "Previous widget", |
|||
"add-to-dashboard": "Add to dashboard", |
|||
"add-widget-to-dashboard": "Add widget to dashboard", |
|||
"selected-attributes": "{ count, select, 1 {1 attribute} other {# attributes} } selected", |
|||
"selected-telemetry": "{ count, select, 1 {1 telemetry unit} other {# telemetry units} } selected" |
|||
}, |
|||
"confirm-on-exit": { |
|||
"message": "You have unsaved changes. Are you sure you want to leave this page?", |
|||
"html-message": "You have unsaved changes.<br/>Are you sure you want to leave this page?", |
|||
"title": "Unsaved changes" |
|||
}, |
|||
"contact": { |
|||
"country": "Country", |
|||
"city": "City", |
|||
"state": "State", |
|||
"postal-code": "Postal code", |
|||
"postal-code-invalid": "Only digits are allowed.", |
|||
"address": "Address", |
|||
"address2": "Address 2", |
|||
"phone": "Phone", |
|||
"email": "Email", |
|||
"no-address": "No address" |
|||
}, |
|||
"common": { |
|||
"username": "Username", |
|||
"password": "Password", |
|||
"enter-username": "Enter username", |
|||
"enter-password": "Enter password", |
|||
"enter-search": "Enter search" |
|||
}, |
|||
"customer": { |
|||
"customers": "Customers", |
|||
"management": "Customer management", |
|||
"dashboard": "Customer Dashboard", |
|||
"dashboards": "Customer Dashboards", |
|||
"devices": "Customer Devices", |
|||
"add": "Add Customer", |
|||
"delete": "Delete customer", |
|||
"manage-customer-users": "Manage customer users", |
|||
"manage-customer-devices": "Manage customer devices", |
|||
"manage-customer-dashboards": "Manage customer dashboards", |
|||
"add-customer-text": "Add new customer", |
|||
"no-customers-text": "No customers found", |
|||
"customer-details": "Customer details", |
|||
"delete-customer-title": "Are you sure you want to delete the customer '{{customerTitle}}'?", |
|||
"delete-customer-text": "Be careful, after the confirmation the customer and all related data will become unrecoverable.", |
|||
"delete-customers-title": "Are you sure you want to delete { count, select, 1 {1 customer} other {# customers} }?", |
|||
"delete-customers-action-title": "Delete { count, select, 1 {1 customer} other {# customers} }", |
|||
"delete-customers-text": "Be careful, after the confirmation all selected customers will be removed and all related data will become unrecoverable.", |
|||
"manage-users": "Manage users", |
|||
"manage-devices": "Manage devices", |
|||
"manage-dashboards": "Manage dashboards", |
|||
"title": "Title", |
|||
"title-required": "Title is required.", |
|||
"description": "Description" |
|||
}, |
|||
"datetime": { |
|||
"date-from": "Date from", |
|||
"time-from": "Time from", |
|||
"date-to": "Date to", |
|||
"time-to": "Time to" |
|||
}, |
|||
"dashboard": { |
|||
"dashboard": "Dashboard", |
|||
"dashboards": "Dashboards", |
|||
"management": "Dashboard management", |
|||
"view-dashboards": "View Dashboards", |
|||
"add": "Add Dashboard", |
|||
"assign-dashboard-to-customer": "Assign Dashboard(s) To Customer", |
|||
"assign-dashboard-to-customer-text": "Please select the dashboards to assign to the customer", |
|||
"assign-to-customer-text": "Please select the customer to assign the dashboard(s)", |
|||
"assign-to-customer": "Assign to customer", |
|||
"unassign-from-customer": "Unassign from customer", |
|||
"no-dashboards-text": "No dashboards found", |
|||
"no-widgets": "No widgets configured", |
|||
"add-widget": "Add new widget", |
|||
"title": "Title", |
|||
"select-widget-title": "Select widget", |
|||
"select-widget-subtitle": "List of available widget types", |
|||
"delete": "Delete dashboard", |
|||
"title-required": "Title is required.", |
|||
"description": "Description", |
|||
"details": "Details", |
|||
"dashboard-details": "Dashboard details", |
|||
"add-dashboard-text": "Add new dashboard", |
|||
"assign-dashboards": "Assign dashboards", |
|||
"assign-new-dashboard": "Assign new dashboard", |
|||
"assign-dashboards-text": "Assign { count, select, 1 {1 dashboard} other {# dashboards} } to customer", |
|||
"delete-dashboards": "Delete dashboards", |
|||
"unassign-dashboards": "Unassign dashboards", |
|||
"unassign-dashboards-action-title": "Unassign { count, select, 1 {1 dashboard} other {# dashboards} } from customer", |
|||
"delete-dashboard-title": "Are you sure you want to delete the dashboard '{{dashboardTitle}}'?", |
|||
"delete-dashboard-text": "Be careful, after the confirmation the dashboard and all related data will become unrecoverable.", |
|||
"delete-dashboards-title": "Are you sure you want to delete { count, select, 1 {1 dashboard} other {# dashboards} }?", |
|||
"delete-dashboards-action-title": "Delete { count, select, 1 {1 dashboard} other {# dashboards} }", |
|||
"delete-dashboards-text": "Be careful, after the confirmation all selected dashboards will be removed and all related data will become unrecoverable.", |
|||
"unassign-dashboard-title": "Are you sure you want to unassign the dashboard '{{dashboardTitle}}'?", |
|||
"unassign-dashboard-text": "After the confirmation the dashboard will be unassigned and won't be accessible by the customer.", |
|||
"unassign-dashboard": "Unassign dashboard", |
|||
"unassign-dashboards-title": "Are you sure you want to unassign { count, select, 1 {1 dashboard} other {# dashboards} }?", |
|||
"unassign-dashboards-text": "After the confirmation all selected dashboards will be unassigned and won't be accessible by the customer.", |
|||
"select-dashboard": "Select dashboard", |
|||
"no-dashboards-matching": "No dashboards matching '{{dashboard}}' were found.", |
|||
"dashboard-required": "Dashboard is required.", |
|||
"select-existing": "Select existing dashboard", |
|||
"create-new": "Create new dashboard", |
|||
"new-dashboard-title": "New dashboard title", |
|||
"open-dashboard": "Open dashboard", |
|||
"set-background": "Set background", |
|||
"background-color": "Background color", |
|||
"background-image": "Background image", |
|||
"background-size-mode": "Background size mode", |
|||
"no-image": "No image selected", |
|||
"drop-image": "Drop an image or click to select a file to upload.", |
|||
"settings": "Settings", |
|||
"columns-count": "Columns count", |
|||
"columns-count-required": "Columns count is required.", |
|||
"min-columns-count-message": "Only 10 minimum column count is allowed.", |
|||
"max-columns-count-message": "Only 1000 maximum column count is allowed.", |
|||
"widgets-margins": "Margin between widgets", |
|||
"horizontal-margin": "Horizontal margin", |
|||
"horizontal-margin-required": "Horizontal margin value is required.", |
|||
"min-horizontal-margin-message": "Only 0 is allowed as minimum horizontal margin value.", |
|||
"max-horizontal-margin-message": "Only 50 is allowed as maximum horizontal margin value.", |
|||
"vertical-margin": "Vertical margin", |
|||
"vertical-margin-required": "Vertical margin value is required.", |
|||
"min-vertical-margin-message": "Only 0 is allowed as minimum vertical margin value.", |
|||
"max-vertical-margin-message": "Only 50 is allowed as maximum vertical margin value.", |
|||
"display-title": "Display dashboard title", |
|||
"import": "Import dashboard", |
|||
"export": "Export dashboard", |
|||
"export-failed-error": "Unable to export dashboard: {error}", |
|||
"create-new-dashboard": "Create new dashboard", |
|||
"dashboard-file": "Dashboard file", |
|||
"invalid-dashboard-file-error": "Unable to import dashboard: Invalid dashboard data structure.", |
|||
"dashboard-import-missing-aliases-title": "Select missing devices for dashboard aliases", |
|||
"create-new-widget": "Create new widget", |
|||
"import-widget": "Import widget", |
|||
"widget-file": "Widget file", |
|||
"invalid-widget-file-error": "Unable to import widget: Invalid widget data structure.", |
|||
"widget-import-missing-aliases-title": "Select missing devices used by widget" |
|||
}, |
|||
"datakey": { |
|||
"settings": "Settings", |
|||
"advanced": "Advanced", |
|||
"label": "Label", |
|||
"color": "Color", |
|||
"data-generation-func": "Data generation function", |
|||
"use-data-post-processing-func": "Use data post-processing function", |
|||
"configuration": "Data key configuration", |
|||
"timeseries": "Timeseries", |
|||
"attributes": "Attributes", |
|||
"timeseries-required": "Device timeseries is required.", |
|||
"timeseries-or-attributes-required": "Device timeseries/attributes is required.", |
|||
"function-types": "Function types", |
|||
"function-types-required": "Function types is required." |
|||
}, |
|||
"datasource": { |
|||
"type": "Datasource type", |
|||
"add-datasource-prompt": "Please add datasource" |
|||
}, |
|||
"details": { |
|||
"edit-mode": "Edit mode", |
|||
"toggle-edit-mode": "Toggle edit mode" |
|||
}, |
|||
"device": { |
|||
"device": "Device", |
|||
"device-required": "Device is required.", |
|||
"devices": "Devices", |
|||
"management": "Device management", |
|||
"view-devices": "View Devices", |
|||
"device-alias": "Device alias", |
|||
"aliases": "Device aliases", |
|||
"no-alias-matching": "'{{alias}}' not found.", |
|||
"no-aliases-found": "No aliases found.", |
|||
"no-key-matching": "'{{key}}' not found.", |
|||
"no-keys-found": "No keys found.", |
|||
"create-new-alias": "Create a new one!", |
|||
"create-new-key": "Create a new one!", |
|||
"duplicate-alias-error": "Duplicate alias found '{{alias}}'.<br>Device aliases must be unique whithin the dashboard.", |
|||
"select-device-for-alias": "Select device for '{{alias}}' alias", |
|||
"no-devices-matching": "No devices matching '{{device}}' were found.", |
|||
"alias": "Alias", |
|||
"alias-required": "Device alias is required.", |
|||
"remove-alias": "Remove device alias", |
|||
"add-alias": "Add device alias", |
|||
"add": "Add Device", |
|||
"assign-to-customer": "Assign to customer", |
|||
"assign-device-to-customer": "Assign Device(s) To Customer", |
|||
"assign-device-to-customer-text": "Please select the devices to assign to the customer", |
|||
"no-devices-text": "No devices found", |
|||
"assign-to-customer-text": "Please select the customer to assign the device(s)", |
|||
"device-details": "Device details", |
|||
"add-device-text": "Add new device", |
|||
"credentials": "Credentials", |
|||
"manage-credentials": "Manage credentials", |
|||
"delete": "Delete device", |
|||
"assign-devices": "Assign devices", |
|||
"assign-devices-text": "Assign { count, select, 1 {1 device} other {# devices} } to customer", |
|||
"delete-devices": "Delete devices", |
|||
"unassign-from-customer": "Unassign from customer", |
|||
"unassign-devices": "Unassign devices", |
|||
"unassign-devices-action-title": "Unassign { count, select, 1 {1 device} other {# devices} } from customer", |
|||
"assign-new-device": "Assign new device", |
|||
"view-credentials": "View credentials", |
|||
"delete-device-title": "Are you sure you want to delete the device '{{deviceName}}'?", |
|||
"delete-device-text": "Be careful, after the confirmation the device and all related data will become unrecoverable.", |
|||
"delete-devices-title": "Are you sure you want to delete { count, select, 1 {1 device} other {# devices} }?", |
|||
"delete-devices-action-title": "Delete { count, select, 1 {1 device} other {# devices} }", |
|||
"delete-devices-text": "Be careful, after the confirmation all selected devices will be removed and all related data will become unrecoverable.", |
|||
"unassign-device-title": "Are you sure you want to unassign the device '{{deviceName}}'?", |
|||
"unassign-device-text": "After the confirmation the device will be unassigned and won't be accessible by the customer.", |
|||
"unassign-device": "Unassign device", |
|||
"unassign-devices-title": "Are you sure you want to unassign { count, select, 1 {1 device} other {# devices} }?", |
|||
"unassign-devices-text": "After the confirmation all selected devices will be unassigned and won't be accessible by the customer.", |
|||
"device-credentials": "Device Credentials", |
|||
"credentials-type": "Credentials type", |
|||
"access-token": "Access token", |
|||
"access-token-required": "Access token is required.", |
|||
"access-token-invalid": "Access token length must be from 1 to 20 characters.", |
|||
"rsa-key": "RSA public key", |
|||
"rsa-key-required": "RSA public key is required.", |
|||
"secret": "Secret", |
|||
"secret-required": "Secret is required.", |
|||
"name": "Name", |
|||
"name-required": "Name is required.", |
|||
"description": "Description", |
|||
"events": "Events", |
|||
"details": "Details", |
|||
"copyId": "Copy device Id", |
|||
"copyAccessToken": "Copy access token", |
|||
"idCopiedMessage": "Device Id has been copied to clipboard", |
|||
"accessTokenCopiedMessage": "Device access token has been copied to clipboard", |
|||
"assignedToCustomer": "Assigned to customer", |
|||
"unable-delete-device-alias-title": "Unable to delete device alias", |
|||
"unable-delete-device-alias-text": "Device alias '{{deviceAlias}}' can't be deleted as it used by the following widget(s):<br/>{{widgetsList}}", |
|||
"is-gateway": "Is gateway" |
|||
}, |
|||
"dialog": { |
|||
"close": "Close dialog" |
|||
}, |
|||
"error": { |
|||
"unable-to-connect": "Unable to connect to the server! Please check your internet connection.", |
|||
"unhandled-error-code": "Unhandled error code: {{errorCode}}", |
|||
"unknown-error": "Unknown error" |
|||
}, |
|||
"event": { |
|||
"event-type": "Event type", |
|||
"type-alarm": "Alarm", |
|||
"type-error": "Error", |
|||
"type-lc-event": "Lifecycle event", |
|||
"type-stats": "Statistics", |
|||
"no-events-prompt": "No events found", |
|||
"error": "Error", |
|||
"alarm": "Alarm", |
|||
"event-time": "Event time", |
|||
"server": "Server", |
|||
"body": "Body", |
|||
"method": "Method", |
|||
"event": "Event", |
|||
"status": "Status", |
|||
"success": "Success", |
|||
"failed": "Failed", |
|||
"messages-processed": "Messages processed", |
|||
"errors-occurred": "Errors occurred" |
|||
}, |
|||
"fullscreen": { |
|||
"expand": "Expand to fullscreen", |
|||
"exit": "Exit fullscreen", |
|||
"toggle": "Toggle fullscreen mode", |
|||
"fullscreen": "Fullscreen" |
|||
}, |
|||
"function": { |
|||
"function": "Function" |
|||
}, |
|||
"grid": { |
|||
"delete-item-title": "Are you sure you want to delete this item?", |
|||
"delete-item-text": "Be careful, after the confirmation this item and all related data will become unrecoverable.", |
|||
"delete-items-title": "Are you sure you want to delete { count, select, 1 {1 item} other {# items} }?", |
|||
"delete-items-action-title": "Delete { count, select, 1 {1 item} other {# items} }", |
|||
"delete-items-text": "Be careful, after the confirmation all selected items will be removed and all related data will become unrecoverable.", |
|||
"add-item-text": "Add new item", |
|||
"no-items-text": "No items found", |
|||
"item-details": "Item details", |
|||
"delete-item": "Delete Item", |
|||
"delete-items": "Delete Items", |
|||
"scroll-to-top": "Scroll to top" |
|||
}, |
|||
"help": { |
|||
"goto-help-page": "Go to help page" |
|||
}, |
|||
"home": { |
|||
"home": "Home", |
|||
"profile": "Profile", |
|||
"logout": "Logout", |
|||
"menu": "Menu", |
|||
"avatar": "Avatar", |
|||
"open-user-menu": "Open user menu" |
|||
}, |
|||
"import": { |
|||
"no-file": "No file selected", |
|||
"drop-file": "Drop a JSON file or click to select a file to upload." |
|||
}, |
|||
"item": { |
|||
"selected": "Selected" |
|||
}, |
|||
"js-func": { |
|||
"no-return-error": "Function must return value!", |
|||
"return-type-mismatch": "Function must return value of '{{type}}' type!" |
|||
}, |
|||
"login": { |
|||
"login": "Login", |
|||
"request-password-reset": "Request Password Reset", |
|||
"reset-password": "Reset Password", |
|||
"create-password": "Create Password", |
|||
"passwords-mismatch-error": "Entered passwords must be same!", |
|||
"password-again": "Password again", |
|||
"sign-in": "Please sign in", |
|||
"username": "Username (email)", |
|||
"remember-me": "Remember me", |
|||
"forgot-password": "Forgot Password?", |
|||
"password-reset": "Password reset", |
|||
"new-password": "New password", |
|||
"new-password-again": "New password again", |
|||
"password-link-sent-message": "Password reset link was successfully sent!", |
|||
"email": "Email" |
|||
}, |
|||
"plugin": { |
|||
"plugins": "Plugins", |
|||
"delete": "Delete plugin", |
|||
"activate": "Activate plugin", |
|||
"suspend": "Suspend plugin", |
|||
"active": "Active", |
|||
"suspended": "Suspended", |
|||
"name": "Name", |
|||
"name-required": "Name is required.", |
|||
"description": "Description", |
|||
"add": "Add Plugin", |
|||
"delete-plugin-title": "Are you sure you want to delete the plugin '{{pluginName}}'?", |
|||
"delete-plugin-text": "Be careful, after the confirmation the plugin and all related data will become unrecoverable.", |
|||
"delete-plugins-title": "Are you sure you want to delete { count, select, 1 {1 plugin} other {# plugins} }?", |
|||
"delete-plugins-action-title": "Delete { count, select, 1 {1 plugin} other {# plugins} }", |
|||
"delete-plugins-text": "Be careful, after the confirmation all selected plugins will be removed and all related data will become unrecoverable.", |
|||
"add-plugin-text": "Add new plugin", |
|||
"no-plugins-text": "No plugins found", |
|||
"plugin-details": "Plugin details", |
|||
"api-token": "API token", |
|||
"api-token-required": "API token is required.", |
|||
"type": "Plugin type", |
|||
"type-required": "Plugin type is required.", |
|||
"configuration": "Plugin configuration", |
|||
"system": "System", |
|||
"select-plugin": "Select plugin", |
|||
"plugin": "Plugin", |
|||
"no-plugins-matching": "No plugins matching '{{plugin}}' were found.", |
|||
"plugin-required": "Plugin is required.", |
|||
"plugin-require-match": "Please select an existing plugin.", |
|||
"events": "Events", |
|||
"details": "Details" |
|||
}, |
|||
"profile": { |
|||
"profile": "Profile", |
|||
"change-password": "Change Password", |
|||
"current-password": "Current password" |
|||
}, |
|||
"rule": { |
|||
"rules": "Rules", |
|||
"delete": "Delete rule", |
|||
"activate": "Activate rule", |
|||
"suspend": "Suspend rule", |
|||
"active": "Active", |
|||
"suspended": "Suspended", |
|||
"name": "Name", |
|||
"name-required": "Name is required.", |
|||
"description": "Description", |
|||
"add": "Add Rule", |
|||
"delete-rule-title": "Are you sure you want to delete the rule '{{ruleName}}'?", |
|||
"delete-rule-text": "Be careful, after the confirmation the rule and all related data will become unrecoverable.", |
|||
"delete-rules-title": "Are you sure you want to delete { count, select, 1 {1 rule} other {# rules} }?", |
|||
"delete-rules-action-title": "Delete { count, select, 1 {1 rule} other {# rules} }", |
|||
"delete-rules-text": "Be careful, after the confirmation all selected rules will be removed and all related data will become unrecoverable.", |
|||
"add-rule-text": "Add new rule", |
|||
"no-rules-text": "No rules found", |
|||
"rule-details": "Rule details", |
|||
"filters": "Filters", |
|||
"filter": "Filter", |
|||
"add-filter-prompt": "Please add filter", |
|||
"remove-filter": "Remove filter", |
|||
"add-filter": "Add filter", |
|||
"filter-name": "Filter name", |
|||
"filter-type": "Filter type", |
|||
"edit-filter": "Edit filter", |
|||
"view-filter": "View filter", |
|||
"component-name": "Name", |
|||
"component-name-required": "Name is required.", |
|||
"component-type": "Type", |
|||
"component-type-required": "Type is required.", |
|||
"processor": "Processor", |
|||
"no-processor-configured": "No processor configured", |
|||
"create-processor": "Create processor", |
|||
"processor-name": "Processor name", |
|||
"processor-type": "Processor type", |
|||
"plugin-action": "Plugin action", |
|||
"action-name": "Action name", |
|||
"action-type": "Action type", |
|||
"create-action-prompt": "Please create action", |
|||
"create-action": "Create action", |
|||
"details": "Details", |
|||
"events": "Events", |
|||
"system": "System" |
|||
}, |
|||
"rule-plugin": { |
|||
"management": "Rules and plugins management" |
|||
}, |
|||
"tenant": { |
|||
"tenants": "Tenants", |
|||
"management": "Tenant management", |
|||
"add": "Add Tenant", |
|||
"admins": "Admins", |
|||
"manage-tenant-admins": "Manage tenant admins", |
|||
"delete": "Delete tenant", |
|||
"add-tenant-text": "Add new tenant", |
|||
"no-tenants-text": "No tenants found", |
|||
"tenant-details": "Tenant details", |
|||
"delete-tenant-title": "Are you sure you want to delete the tenant '{{tenantTitle}}'?", |
|||
"delete-tenant-text": "Be careful, after the confirmation the tenant and all related data will become unrecoverable.", |
|||
"delete-tenants-title": "Are you sure you want to delete { count, select, 1 {1 tenant} other {# tenants} }?", |
|||
"delete-tenants-action-title": "Delete { count, select, 1 {1 tenant} other {# tenants} }", |
|||
"delete-tenants-text": "Be careful, after the confirmation all selected tenants will be removed and all related data will become unrecoverable.", |
|||
"title": "Title", |
|||
"title-required": "Title is required.", |
|||
"description": "Description" |
|||
}, |
|||
"timeinterval": { |
|||
"seconds-interval": "{ seconds, select, 1 {1 second} other {# seconds} }", |
|||
"minutes-interval": "{ minutes, select, 1 {1 minute} other {# minutes} }", |
|||
"hours-interval": "{ hours, select, 1 {1 hour} other {# hours} }", |
|||
"days-interval": "{ days, select, 1 {1 day} other {# days} }", |
|||
"days": "Days", |
|||
"hours": "Hours", |
|||
"minutes": "Minutes", |
|||
"seconds": "Seconds" |
|||
}, |
|||
"timewindow": { |
|||
"days": "{ days, select, 1 { day } other {# days } }", |
|||
"hours": "{ hours, select, 0 { hour } 1 {1 hour } other {# hours } }", |
|||
"minutes": "{ minutes, select, 0 { minute } 1 {1 minute } other {# minutes } }", |
|||
"seconds": "{ seconds, select, 0 { second } 1 {1 second } other {# seconds } }", |
|||
"realtime": "Realtime", |
|||
"history": "History", |
|||
"last-prefix": "last", |
|||
"period": "from {{ startTime }} to {{ endTime }}", |
|||
"edit": "Edit timewindow", |
|||
"date-range": "Date range", |
|||
"last": "Last", |
|||
"time-period": "Time period" |
|||
}, |
|||
"user": { |
|||
"users": "Users", |
|||
"customer-users": "Customer Users", |
|||
"tenant-admins": "Tenant Admins", |
|||
"sys-admin": "System administrator", |
|||
"tenant-admin": "Tenant administrator", |
|||
"customer": "Customer", |
|||
"anonymous": "Anonymous", |
|||
"add": "Add User", |
|||
"delete": "Delete user", |
|||
"add-user-text": "Add new user", |
|||
"no-users-text": "No users found", |
|||
"user-details": "User details", |
|||
"delete-user-title": "Are you sure you want to delete the user '{{userEmail}}'?", |
|||
"delete-user-text": "Be careful, after the confirmation the user and all related data will become unrecoverable.", |
|||
"delete-users-title": "Are you sure you want to delete { count, select, 1 {1 user} other {# users} }?", |
|||
"delete-users-action-title": "Delete { count, select, 1 {1 user} other {# users} }", |
|||
"delete-users-text": "Be careful, after the confirmation all selected users will be removed and all related data will become unrecoverable.", |
|||
"activation-email-sent-message": "Activation email was successfully sent!", |
|||
"resend-activation": "Resend activation", |
|||
"email": "Email", |
|||
"email-required": "Email is required.", |
|||
"first-name": "First Name", |
|||
"last-name": "Last Name", |
|||
"description": "Description" |
|||
}, |
|||
"value": { |
|||
"type": "Value type", |
|||
"string": "String", |
|||
"string-value": "String value", |
|||
"integer": "Integer", |
|||
"integer-value": "Integer value", |
|||
"invalid-integer-value": "Invalid integer value", |
|||
"double": "Double", |
|||
"double-value": "Double value", |
|||
"boolean": "Boolean", |
|||
"boolean-value": "Boolean value", |
|||
"false": "False", |
|||
"true": "True" |
|||
}, |
|||
"widget": { |
|||
"widget-library": "Widgets Library", |
|||
"widget-bundle": "Widgets Bundle", |
|||
"select-widgets-bundle": "Select widgets bundle", |
|||
"management": "Widget management", |
|||
"editor": "Widget Editor", |
|||
"widget-type-not-found": "Problem loading widget configuration.<br>Probably associated\n widget type was removed.", |
|||
"widget-type-load-error": "Widget wasn't loaded due to the following errors:", |
|||
"remove": "Remove widget", |
|||
"edit": "Edit widget", |
|||
"remove-widget-title": "Are you sure you want to remove the widget '{{widgetTitle}}'?", |
|||
"remove-widget-text": "After the confirmation the widget and all related data will become unrecoverable.", |
|||
"timeseries": "Time series", |
|||
"latest-values": "Latest values", |
|||
"rpc": "Control widget", |
|||
"static": "Static widget", |
|||
"select-widget-type": "Select widget type", |
|||
"missing-widget-title-error": "Widget title must be specified!", |
|||
"widget-saved": "Widget saved", |
|||
"unable-to-save-widget-error": "Unable to save widget! Widget has errors!", |
|||
"save": "Save widget", |
|||
"saveAs": "Save widget as", |
|||
"save-widget-type-as": "Save widget type as", |
|||
"save-widget-type-as-text": "Please enter new widget title and/or select target widgets bundle", |
|||
"toggle-fullscreen": "Toggle fullscreen", |
|||
"run": "Run widget", |
|||
"title": "Widget title", |
|||
"title-required": "Widget title is required.", |
|||
"type": "Widget type", |
|||
"resources": "Resources", |
|||
"resource-url": "JavaScript/CSS URI", |
|||
"remove-resource": "Remove resource", |
|||
"add-resource": "Add resource", |
|||
"html": "HTML", |
|||
"tidy": "Tidy", |
|||
"css": "CSS", |
|||
"settings-schema": "Settings schema", |
|||
"datakey-settings-schema": "Data key settings schema", |
|||
"javascript": "Javascript", |
|||
"remove-widget-type-title": "Are you sure you want to remove the widget type '{{widgetName}}'?", |
|||
"remove-widget-type-text": "After the confirmation the widget type and all related data will become unrecoverable.", |
|||
"remove-widget-type": "Remove widget type", |
|||
"add-widget-type": "Add new widget type", |
|||
"widget-type-load-failed-error": "Failed to load widget type!", |
|||
"widget-template-load-failed-error": "Failed to load widget template!", |
|||
"add": "Add Widget", |
|||
"undo": "Undo widget changes", |
|||
"export": "Export widget" |
|||
}, |
|||
"widgets-bundle": { |
|||
"current": "Current bundle", |
|||
"widgets-bundles": "Widgets Bundles", |
|||
"add": "Add Widgets Bundle", |
|||
"delete": "Delete widgets bundle", |
|||
"title": "Title", |
|||
"title-required": "Title is required.", |
|||
"add-widgets-bundle-text": "Add new widgets bundle", |
|||
"no-widgets-bundles-text": "No widgets bundles found", |
|||
"empty": "Widgets bundle is empty", |
|||
"details": "Details", |
|||
"widgets-bundle-details": "Widgets bundle details", |
|||
"delete-widgets-bundle-title": "Are you sure you want to delete the widgets bundle '{{widgetsBundleTitle}}'?", |
|||
"delete-widgets-bundle-text": "Be careful, after the confirmation the widgets bundle and all related data will become unrecoverable.", |
|||
"delete-widgets-bundles-title": "Are you sure you want to delete { count, select, 1 {1 widgets bundle} other {# widgets bundles} }?", |
|||
"delete-widgets-bundles-action-title": "Delete { count, select, 1 {1 widgets bundle} other {# widgets bundles} }", |
|||
"delete-widgets-bundles-text": "Be careful, after the confirmation all selected widgets bundles will be removed and all related data will become unrecoverable.", |
|||
"no-widgets-bundles-matching": "No widgets bundles matching '{{widgetsBundle}}' were found.", |
|||
"widgets-bundle-required": "Widgets bundle is required.", |
|||
"system": "System" |
|||
}, |
|||
"widget-config": { |
|||
"settings": "Settings", |
|||
"advanced": "Advanced", |
|||
"title": "Title", |
|||
"general-settings": "General settings", |
|||
"display-title": "Display title", |
|||
"drop-shadow": "Drop shadow", |
|||
"enable-fullscreen": "Enable fullscreen", |
|||
"background-color": "Background color", |
|||
"text-color": "Text color", |
|||
"padding": "Padding", |
|||
"title-style": "Title style", |
|||
"mobile-mode-settings": "Mobile mode settings", |
|||
"order": "Order", |
|||
"height": "Height", |
|||
"timewindow": "Timewindow", |
|||
"datasources": "Datasources", |
|||
"datasource-type": "Type", |
|||
"datasource-parameters": "Parameters", |
|||
"remove-datasource": "Remove datasource", |
|||
"add-datasource": "Add datasource", |
|||
"target-device": "Target device" |
|||
} |
|||
} |
|||
} |
|||
).name; |
|||
@ -0,0 +1,731 @@ |
|||
/* |
|||
* 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 $ from 'jquery'; |
|||
import canvasGauges from 'canvas-gauges'; |
|||
import tinycolor from 'tinycolor2'; |
|||
|
|||
/* eslint-disable angular/angularelement */ |
|||
|
|||
let defaultDigitalGaugeOptions = Object.assign({}, canvasGauges.GenericOptions, { |
|||
gaugeType: 'arc', |
|||
gaugeWithScale: 0.75, |
|||
dashThickness: 0, |
|||
roundedLineCap: false, |
|||
|
|||
gaugeColor: '#777', |
|||
levelColors: ['blue'], |
|||
|
|||
symbol: '', |
|||
label: '', |
|||
hideValue: false, |
|||
hideMinMax: false, |
|||
|
|||
fontTitle: 'Roboto', |
|||
|
|||
fontValue: 'Roboto', |
|||
|
|||
fontMinMaxSize: 10, |
|||
fontMinMaxStyle: 'normal', |
|||
fontMinMaxWeight: '500', |
|||
colorMinMax: '#eee', |
|||
fontMinMax: 'Roboto', |
|||
|
|||
fontLabelSize: 8, |
|||
fontLabelStyle: 'normal', |
|||
fontLabelWeight: '500', |
|||
colorLabel: '#eee', |
|||
fontLabel: 'Roboto', |
|||
|
|||
neonGlowBrightness: 0, |
|||
|
|||
isMobile: false |
|||
|
|||
}); |
|||
|
|||
const round = Math.round; |
|||
|
|||
export default class CanvasDigitalGauge extends canvasGauges.BaseGauge { |
|||
|
|||
constructor(options) { |
|||
canvasGauges.performance = window.performance; // eslint-disable-line no-undef, angular/window-service
|
|||
options = Object.assign({}, defaultDigitalGaugeOptions, options || {}); |
|||
super(CanvasDigitalGauge.configure(options)); |
|||
this.initValueClone(); |
|||
} |
|||
|
|||
initValueClone() { |
|||
let canvas = this.canvas; |
|||
this.elementValueClone = canvas.element.cloneNode(true); |
|||
this.contextValueClone = this.elementValueClone.getContext('2d'); |
|||
this.elementValueClone.initialized = false; |
|||
|
|||
this.contextValueClone.translate(canvas.drawX, canvas.drawY); |
|||
this.contextValueClone.save(); |
|||
|
|||
this.elementProgressClone = canvas.element.cloneNode(true); |
|||
this.contextProgressClone = this.elementProgressClone.getContext('2d'); |
|||
this.elementProgressClone.initialized = false; |
|||
|
|||
this.contextProgressClone.translate(canvas.drawX, canvas.drawY); |
|||
this.contextProgressClone.save(); |
|||
|
|||
} |
|||
|
|||
static configure(options) { |
|||
|
|||
if (options.value > options.maxValue) { |
|||
options.value = options.maxValue; |
|||
} |
|||
|
|||
if (options.value < options.minValue) { |
|||
options.value = options.minValue; |
|||
} |
|||
|
|||
var colorsCount = options.levelColors.length; |
|||
var inc = colorsCount > 1 ? (1 / (colorsCount - 1)) : 1; |
|||
options.colorsRange = []; |
|||
if (options.neonGlowBrightness) { |
|||
options.neonColorsRange = []; |
|||
} |
|||
for (var i = 0; i < options.levelColors.length; i++) { |
|||
var percentage = inc * i; |
|||
var tColor = tinycolor(options.levelColors[i]); |
|||
options.colorsRange[i] = { |
|||
pct: percentage, |
|||
color: tColor.toRgb(), |
|||
rgbString: tColor.toRgbString() |
|||
}; |
|||
if (options.neonGlowBrightness) { |
|||
tColor = tinycolor(options.levelColors[i]).brighten(options.neonGlowBrightness); |
|||
options.neonColorsRange[i] = { |
|||
pct: percentage, |
|||
color: tColor.toRgb(), |
|||
rgbString: tColor.toRgbString() |
|||
}; |
|||
} |
|||
} |
|||
|
|||
if (options.neonGlowBrightness) { |
|||
options.neonColorTitle = tinycolor(options.colorTitle).brighten(options.neonGlowBrightness).toHexString(); |
|||
options.neonColorLabel = tinycolor(options.colorLabel).brighten(options.neonGlowBrightness).toHexString(); |
|||
options.neonColorValue = tinycolor(options.colorValue).brighten(options.neonGlowBrightness).toHexString(); |
|||
options.neonColorMinMax = tinycolor(options.colorMinMax).brighten(options.neonGlowBrightness).toHexString(); |
|||
} |
|||
|
|||
return canvasGauges.BaseGauge.configure(options); |
|||
} |
|||
|
|||
destroy() { |
|||
this.contextValueClone = null; |
|||
this.elementValueClone = null; |
|||
this.contextProgressClone = null; |
|||
this.elementProgressClone = null; |
|||
super.destroy(); |
|||
} |
|||
|
|||
update(options) { |
|||
this.canvas.onRedraw = null; |
|||
var result = super.update(options); |
|||
this.initValueClone(); |
|||
this.canvas.onRedraw = this.draw.bind(this); |
|||
this.draw(); |
|||
return result; |
|||
} |
|||
|
|||
draw() { |
|||
try { |
|||
let canvas = this.canvas; |
|||
let [x, y, w, h] = [ |
|||
-canvas.drawX, |
|||
-canvas.drawY, |
|||
canvas.drawWidth, |
|||
canvas.drawHeight |
|||
]; |
|||
let options = this.options; |
|||
if (!canvas.elementClone.initialized) { |
|||
let context = canvas.contextClone; |
|||
|
|||
// clear the cache
|
|||
context.clearRect(x, y, w, h); |
|||
context.save(); |
|||
|
|||
canvas.context.barDimensions = barDimensions(context, options, x, y, w, h); |
|||
this.contextValueClone.barDimensions = canvas.context.barDimensions; |
|||
this.contextProgressClone.barDimensions = canvas.context.barDimensions; |
|||
|
|||
drawBackground(context, options); |
|||
|
|||
drawDigitalTitle(context, options); |
|||
|
|||
drawDigitalLabel(context, options); |
|||
|
|||
drawDigitalMinMax(context, options); |
|||
|
|||
canvas.elementClone.initialized = true; |
|||
} |
|||
|
|||
if (!this.elementValueClone.initialized || this.elementValueClone.renderedValue !== this.value) { |
|||
let context = this.contextValueClone; |
|||
// clear the cache
|
|||
context.clearRect(x, y, w, h); |
|||
context.save(); |
|||
|
|||
context.drawImage(canvas.elementClone, x, y, w, h); |
|||
context.save(); |
|||
|
|||
drawDigitalValue(context, options, this.value); |
|||
|
|||
this.elementValueClone.initialized = true; |
|||
this.elementValueClone.renderedValue = this.value; |
|||
} |
|||
|
|||
var progress = (canvasGauges.drawings.normalizedValue(options).normal - options.minValue) / |
|||
(options.maxValue - options.minValue); |
|||
|
|||
var fixedProgress = progress.toFixed(3); |
|||
|
|||
if (!this.elementProgressClone.initialized || this.elementProgressClone.renderedProgress !== fixedProgress) { |
|||
let context = this.contextProgressClone; |
|||
// clear the cache
|
|||
context.clearRect(x, y, w, h); |
|||
context.save(); |
|||
|
|||
context.drawImage(this.elementValueClone, x, y, w, h); |
|||
context.save(); |
|||
|
|||
if (Number(fixedProgress) > 0) { |
|||
drawProgress(context, options, progress); |
|||
} |
|||
|
|||
this.elementProgressClone.initialized = true; |
|||
this.elementProgressClone.renderedProgress = fixedProgress; |
|||
} |
|||
|
|||
this.canvas.commit(); |
|||
|
|||
// clear the canvas
|
|||
canvas.context.clearRect(x, y, w, h); |
|||
canvas.context.save(); |
|||
|
|||
canvas.context.drawImage(this.elementProgressClone, x, y, w, h); |
|||
canvas.context.save(); |
|||
|
|||
super.draw(); |
|||
|
|||
} catch (err) { |
|||
canvasGauges.drawings.verifyError(err); |
|||
} |
|||
return this; |
|||
} |
|||
|
|||
} |
|||
|
|||
/* eslint-disable angular/document-service */ |
|||
/* eslint-disable no-undef */ |
|||
function determineFontHeight (options, target, baseSize) { |
|||
var fontStyleStr = 'font-style:' + options['font' + target + 'Style'] + ';font-weight:' + |
|||
options['font' + target + 'Weight'] + ';font-size:' + |
|||
options['font' + target + 'Size'] * baseSize + 'px;font-family:' + |
|||
options['font' + target]; |
|||
var result = CanvasDigitalGauge.heightCache[fontStyleStr]; |
|||
if (!result) |
|||
{ |
|||
var fontStyle = { |
|||
fontFamily: options['font' + target], |
|||
fontSize: options['font' + target + 'Size'] * baseSize + 'px', |
|||
fontWeight: options['font' + target + 'Weight'], |
|||
fontStyle: options['font' + target + 'Style'] |
|||
}; |
|||
|
|||
var text = $('<span>Hg</span>').css(fontStyle); |
|||
var block = $('<div style="display: inline-block; width: 1px; height: 0px;"></div>'); |
|||
|
|||
var div = $('<div></div>'); |
|||
div.append(text, block); |
|||
|
|||
var body = $('body'); |
|||
body.append(div); |
|||
|
|||
try { |
|||
result = {}; |
|||
block.css({ verticalAlign: 'baseline' }); |
|||
result.ascent = block.offset().top - text.offset().top; |
|||
block.css({ verticalAlign: 'bottom' }); |
|||
result.height = block.offset().top - text.offset().top; |
|||
result.descent = result.height - result.ascent; |
|||
} finally { |
|||
div.remove(); |
|||
} |
|||
CanvasDigitalGauge.heightCache[fontStyleStr] = result; |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
/* eslint-enable angular/document-service */ |
|||
/* eslint-enable no-undef */ |
|||
|
|||
function barDimensions(context, options, x, y, w, h) { |
|||
|
|||
context.barDimensions = { |
|||
baseX: x, |
|||
baseY: y, |
|||
width: w, |
|||
height: h |
|||
}; |
|||
|
|||
var bd = context.barDimensions; |
|||
|
|||
var aspect = 1; |
|||
|
|||
if (options.gaugeType === 'horizontalBar') { |
|||
aspect = options.title === '' ? 2.5 : 2; |
|||
} else if (options.gaugeType === 'verticalBar') { |
|||
aspect = options.hideMinMax ? 0.35 : 0.5; |
|||
} else if (options.gaugeType === 'arc') { |
|||
aspect = 1.5; |
|||
} |
|||
|
|||
var currentAspect = w / h; |
|||
if (currentAspect > aspect) { |
|||
bd.width = (h * aspect); |
|||
bd.height = h; |
|||
} else { |
|||
bd.width = w; |
|||
bd.height = w / aspect; |
|||
} |
|||
|
|||
bd.baseX += (w - bd.width) / 2; |
|||
bd.baseY += (h - bd.height) / 2; |
|||
|
|||
if (options.gaugeType === 'donut') { |
|||
bd.fontSizeFactor = Math.max(bd.width, bd.height) / 125; |
|||
} else if (options.gaugeType === 'verticalBar' || (options.gaugeType === 'arc' && options.title === '')) { |
|||
bd.fontSizeFactor = Math.max(bd.width, bd.height) / 150; |
|||
} else { |
|||
bd.fontSizeFactor = Math.max(bd.width, bd.height) / 200; |
|||
} |
|||
|
|||
var gws = options.gaugeWidthScale; |
|||
|
|||
if (options.neonGlowBrightness) { |
|||
options.fontTitleHeight = determineFontHeight(options, 'Title', bd.fontSizeFactor); |
|||
options.fontLabelHeight = determineFontHeight(options, 'Label', bd.fontSizeFactor); |
|||
options.fontValueHeight = determineFontHeight(options, 'Value', bd.fontSizeFactor); |
|||
options.fontMinMaxHeight = determineFontHeight(options, 'MinMax', bd.fontSizeFactor); |
|||
} |
|||
|
|||
if (options.gaugeType === 'donut') { |
|||
bd.Ro = bd.width / 2 - bd.width / 20; |
|||
bd.Cy = bd.baseY + bd.height / 2; |
|||
if (options.title && options.title.length > 0) { |
|||
var titleOffset = determineFontHeight(options, 'Title', bd.fontSizeFactor).height; |
|||
titleOffset += bd.fontSizeFactor * 2; |
|||
bd.titleY = bd.baseY + titleOffset; |
|||
titleOffset += bd.fontSizeFactor * 2; |
|||
bd.Cy += titleOffset/2; |
|||
bd.Ro -= titleOffset/2; |
|||
} |
|||
bd.Ri = bd.Ro - bd.width / 6.666666666666667 * gws * 1.2; |
|||
bd.Cx = bd.baseX + bd.width / 2; |
|||
|
|||
} else if (options.gaugeType === 'arc') { |
|||
if (options.title && options.title.length > 0) { |
|||
bd.Ro = bd.width / 2 - bd.width / 7; |
|||
bd.Ri = bd.Ro - bd.width / 6.666666666666667 * gws; |
|||
} else { |
|||
bd.Ro = bd.width / 2 - bd.fontSizeFactor * 4; |
|||
bd.Ri = bd.Ro - bd.width / 6.666666666666667 * gws * 1.2; |
|||
} |
|||
bd.Cx = bd.baseX + bd.width / 2; |
|||
bd.Cy = bd.baseY + bd.height / 1.25; |
|||
} else if (options.gaugeType === 'verticalBar') { |
|||
bd.Ro = bd.width / 2 - bd.width / 10; |
|||
bd.Ri = bd.Ro - bd.width / 6.666666666666667 * gws * (options.hideMinMax ? 4 : 2.5); |
|||
} else { //horizontalBar
|
|||
bd.Ro = bd.width / 2 - bd.width / 10; |
|||
bd.Ri = bd.Ro - bd.width / 6.666666666666667 * gws; |
|||
} |
|||
|
|||
bd.strokeWidth = bd.Ro - bd.Ri; |
|||
bd.Rm = bd.Ri + bd.strokeWidth * 0.5; |
|||
|
|||
bd.fontValueBaseline = 'alphabetic'; |
|||
bd.fontMinMaxBaseline = 'alphabetic'; |
|||
bd.fontMinMaxAlign = 'center'; |
|||
|
|||
if (options.gaugeType === 'donut') { |
|||
bd.fontValueBaseline = 'middle'; |
|||
if (options.label && options.label.length > 0) { |
|||
var valueHeight = determineFontHeight(options, 'Value', bd.fontSizeFactor).height; |
|||
var labelHeight = determineFontHeight(options, 'Label', bd.fontSizeFactor).height; |
|||
var total = valueHeight + labelHeight; |
|||
bd.labelY = bd.Cy + total/2; |
|||
bd.valueY = bd.Cy - total/2 + valueHeight/2; |
|||
} else { |
|||
bd.valueY = bd.Cy; |
|||
} |
|||
} else if (options.gaugeType === 'arc') { |
|||
bd.titleY = bd.Cy - bd.Ro - 12 * bd.fontSizeFactor; |
|||
bd.valueY = bd.Cy; |
|||
bd.labelY = bd.Cy + (8 + options.fontLabelSize) * bd.fontSizeFactor; |
|||
bd.minY = bd.maxY = bd.labelY; |
|||
if (options.roundedLineCap) { |
|||
bd.minY += bd.strokeWidth/2; |
|||
bd.maxY += bd.strokeWidth/2; |
|||
} |
|||
bd.minX = bd.Cx - bd.Rm; |
|||
bd.maxX = bd.Cx + bd.Rm; |
|||
} else if (options.gaugeType === 'horizontalBar') { |
|||
bd.titleY = bd.baseY + 4 * bd.fontSizeFactor + |
|||
(options.title === '' ? 0 : options.fontTitleSize * bd.fontSizeFactor); |
|||
bd.titleBottom = bd.titleY + (options.title === '' ? 0 : 4) * bd.fontSizeFactor; |
|||
|
|||
bd.valueY = bd.titleBottom + |
|||
(options.hideValue ? 0 : options.fontValueSize * bd.fontSizeFactor); |
|||
|
|||
bd.barTop = bd.valueY + 8 * bd.fontSizeFactor; |
|||
bd.barBottom = bd.barTop + bd.strokeWidth; |
|||
|
|||
if (options.hideMinMax && options.label === '') { |
|||
bd.labelY = bd.barBottom; |
|||
bd.barLeft = options.fontMinMaxSize/3 * bd.fontSizeFactor; |
|||
bd.barRight = bd.width - options.fontMinMaxSize/3 * bd.fontSizeFactor; |
|||
} else { |
|||
context.font = canvasGauges.drawings.font(options, 'MinMax', bd.fontSizeFactor); |
|||
var minTextWidth = context.measureText(options.minValue+'').width; |
|||
var maxTextWidth = context.measureText(options.maxValue+'').width; |
|||
var maxW = Math.max(minTextWidth, maxTextWidth); |
|||
bd.minX = bd.baseX + maxW/2 + options.fontMinMaxSize/3 * bd.fontSizeFactor; |
|||
bd.maxX = bd.baseX + bd.width - maxW/2 - options.fontMinMaxSize/3 * bd.fontSizeFactor; |
|||
bd.barLeft = bd.minX; |
|||
bd.barRight = bd.maxX; |
|||
bd.labelY = bd.barBottom + (8 + options.fontLabelSize) * bd.fontSizeFactor; |
|||
bd.minY = bd.maxY = bd.labelY; |
|||
} |
|||
} else if (options.gaugeType === 'verticalBar') { |
|||
bd.titleY = bd.baseY + ((options.title === '' ? 0 : options.fontTitleSize) + 8) * bd.fontSizeFactor; |
|||
bd.titleBottom = bd.titleY + (options.title === '' ? 0 : 4) * bd.fontSizeFactor; |
|||
|
|||
bd.valueY = bd.titleBottom + (options.hideValue ? 0 : options.fontValueSize * bd.fontSizeFactor); |
|||
bd.barTop = bd.valueY + 8 * bd.fontSizeFactor; |
|||
|
|||
bd.labelY = bd.baseY + bd.height - 16; |
|||
if (options.label === '') { |
|||
bd.barBottom = bd.labelY; |
|||
} else { |
|||
bd.barBottom = bd.labelY - (8 + options.fontLabelSize) * bd.fontSizeFactor; |
|||
} |
|||
bd.minX = bd.maxX = |
|||
bd.baseX + bd.width/2 + bd.strokeWidth/2 + options.fontMinMaxSize/3 * bd.fontSizeFactor; |
|||
bd.minY = bd.barBottom; |
|||
bd.maxY = bd.barTop; |
|||
bd.fontMinMaxBaseline = 'middle'; |
|||
bd.fontMinMaxAlign = 'left'; |
|||
} |
|||
|
|||
if (options.dashThickness) { |
|||
var circumference; |
|||
if (options.gaugeType === 'donut') { |
|||
circumference = Math.PI * bd.Rm * 2; |
|||
} else if (options.gaugeType === 'arc') { |
|||
circumference = Math.PI * bd.Rm; |
|||
} else if (options.gaugeType === 'horizontalBar') { |
|||
circumference = bd.barRight - bd.barLeft; |
|||
} else if (options.gaugeType === 'verticalBar') { |
|||
circumference = bd.barBottom - bd.barTop; |
|||
} |
|||
var dashCount = Math.floor(circumference / (options.dashThickness * bd.fontSizeFactor)); |
|||
if (options.gaugeType === 'donut') { |
|||
dashCount = (dashCount | 1) - 1; |
|||
} else { |
|||
dashCount = (dashCount - 1) | 1; |
|||
} |
|||
bd.dashLength = Math.ceil(circumference/dashCount); |
|||
} |
|||
|
|||
return bd; |
|||
} |
|||
|
|||
function drawBackground(context, options) { |
|||
let {barLeft, barRight, barTop, barBottom, width, baseX, strokeWidth} = |
|||
context.barDimensions; |
|||
if (context.barDimensions.dashLength) { |
|||
context.setLineDash([context.barDimensions.dashLength]); |
|||
} |
|||
context.beginPath(); |
|||
context.strokeStyle = options.gaugeColor; |
|||
context.lineWidth = strokeWidth; |
|||
if (options.roundedLineCap) { |
|||
context.lineCap = 'round'; |
|||
} |
|||
if (options.gaugeType === 'donut') { |
|||
context.arc(context.barDimensions.Cx, context.barDimensions.Cy, context.barDimensions.Rm, 1.5 * Math.PI, 3.5 * Math.PI); |
|||
context.stroke(); |
|||
} else if (options.gaugeType === 'arc') { |
|||
context.arc(context.barDimensions.Cx, context.barDimensions.Cy, context.barDimensions.Rm, Math.PI, 2*Math.PI); |
|||
context.stroke(); |
|||
} else if (options.gaugeType === 'horizontalBar') { |
|||
context.moveTo(barLeft,barTop + strokeWidth/2); |
|||
context.lineTo(barRight,barTop + strokeWidth/2); |
|||
context.stroke(); |
|||
} else if (options.gaugeType === 'verticalBar') { |
|||
context.moveTo(baseX + width/2, barBottom); |
|||
context.lineTo(baseX + width/2, barTop); |
|||
context.stroke(); |
|||
} |
|||
} |
|||
|
|||
function drawText(context, options, target, text, textX, textY) { |
|||
context.fillStyle = options[(options.neonGlowBrightness ? 'neonColor' : 'color') + target]; |
|||
context.fillText(text, textX, textY); |
|||
} |
|||
|
|||
function drawDigitalTitle(context, options) { |
|||
if (!options.title) return; |
|||
|
|||
let {titleY, width, baseX, fontSizeFactor} = |
|||
context.barDimensions; |
|||
|
|||
let textX = round(baseX + width / 2); |
|||
let textY = titleY; |
|||
|
|||
context.save(); |
|||
context.textAlign = 'center'; |
|||
context.font = canvasGauges.drawings.font(options, 'Title', fontSizeFactor); |
|||
context.lineWidth = 0; |
|||
drawText(context, options, 'Title', options.title.toUpperCase(), textX, textY); |
|||
} |
|||
|
|||
function drawDigitalLabel(context, options) { |
|||
if (!options.label || options.label === '') return; |
|||
|
|||
let {labelY, baseX, width, fontSizeFactor} = |
|||
context.barDimensions; |
|||
|
|||
let textX = round(baseX + width / 2); |
|||
let textY = labelY; |
|||
|
|||
context.save(); |
|||
context.textAlign = 'center'; |
|||
context.font = canvasGauges.drawings.font(options, 'Label', fontSizeFactor); |
|||
context.lineWidth = 0; |
|||
drawText(context, options, 'Label', options.label.toUpperCase(), textX, textY); |
|||
|
|||
} |
|||
|
|||
function drawDigitalMinMax(context, options) { |
|||
if (options.hideMinMax || options.gaugeType === 'donut') return; |
|||
|
|||
let {minY, maxY, minX, maxX, fontSizeFactor, fontMinMaxAlign, fontMinMaxBaseline} = |
|||
context.barDimensions; |
|||
|
|||
context.save(); |
|||
context.textAlign = fontMinMaxAlign; |
|||
context.textBaseline = fontMinMaxBaseline; |
|||
context.font = canvasGauges.drawings.font(options, 'MinMax', fontSizeFactor); |
|||
context.lineWidth = 0; |
|||
drawText(context, options, 'MinMax', options.minValue+'', minX, minY); |
|||
drawText(context, options, 'MinMax', options.maxValue+'', maxX, maxY); |
|||
} |
|||
|
|||
function padValue(val, options) { |
|||
let dec = options.valueDec; |
|||
let strVal, n; |
|||
|
|||
val = parseFloat(val); |
|||
n = (val < 0); |
|||
val = Math.abs(val); |
|||
|
|||
if (dec > 0) { |
|||
strVal = val.toFixed(dec).toString() |
|||
} else { |
|||
strVal = round(val).toString(); |
|||
} |
|||
strVal = (n ? '-' : '') + strVal; |
|||
return strVal; |
|||
} |
|||
|
|||
function drawDigitalValue(context, options, value) { |
|||
if (options.hideValue) return; |
|||
|
|||
let {valueY, baseX, width, fontSizeFactor, fontValueBaseline} = |
|||
context.barDimensions; |
|||
|
|||
let textX = round(baseX + width / 2); |
|||
let textY = valueY; |
|||
|
|||
let text = options.valueText || padValue(value, options); |
|||
text += options.symbol; |
|||
|
|||
context.save(); |
|||
context.textAlign = 'center'; |
|||
context.textBaseline = fontValueBaseline; |
|||
context.font = canvasGauges.drawings.font(options, 'Value', fontSizeFactor); |
|||
context.lineWidth = 0; |
|||
drawText(context, options, 'Value', text, textX, textY); |
|||
} |
|||
|
|||
function getProgressColor(progress, colorsRange) { |
|||
|
|||
var lower, upper, range, rangePct, pctLower, pctUpper, color; |
|||
|
|||
if (progress === 0 || colorsRange.length === 1) { |
|||
return colorsRange[0].rgbString; |
|||
} |
|||
|
|||
for (var j = 0; j < colorsRange.length; j++) { |
|||
if (progress <= colorsRange[j].pct) { |
|||
lower = colorsRange[j - 1]; |
|||
upper = colorsRange[j]; |
|||
range = upper.pct - lower.pct; |
|||
rangePct = (progress - lower.pct) / range; |
|||
pctLower = 1 - rangePct; |
|||
pctUpper = rangePct; |
|||
color = tinycolor({ |
|||
r: Math.floor(lower.color.r * pctLower + upper.color.r * pctUpper), |
|||
g: Math.floor(lower.color.g * pctLower + upper.color.g * pctUpper), |
|||
b: Math.floor(lower.color.b * pctLower + upper.color.b * pctUpper) |
|||
}); |
|||
return color.toRgbString(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
function drawArcGlow(context, Cx, Cy, Ri, Rm, Ro, color, progress, isDonut) { |
|||
context.setLineDash([]); |
|||
var strokeWidth = Ro - Ri; |
|||
var blur = 0.55; |
|||
var edge = strokeWidth*blur; |
|||
context.lineWidth = strokeWidth+edge; |
|||
var stop = blur/(2*blur+2); |
|||
var glowGradient = context.createRadialGradient(Cx,Cy,Ri-edge/2,Cx,Cy,Ro+edge/2); |
|||
var color1 = tinycolor(color).setAlpha(0.5).toRgbString(); |
|||
var color2 = tinycolor(color).setAlpha(0).toRgbString(); |
|||
glowGradient.addColorStop(0,color2); |
|||
glowGradient.addColorStop(stop,color1); |
|||
glowGradient.addColorStop(1.0-stop,color1); |
|||
glowGradient.addColorStop(1,color2); |
|||
context.strokeStyle = glowGradient; |
|||
context.beginPath(); |
|||
var e = 0.01 * Math.PI; |
|||
if (isDonut) { |
|||
context.arc(Cx, Cy, Rm, 1.5 * Math.PI - e, 1.5 * Math.PI + 2 * Math.PI * progress + e); |
|||
} else { |
|||
context.arc(Cx, Cy, Rm, Math.PI - e, Math.PI + Math.PI * progress + e); |
|||
} |
|||
context.stroke(); |
|||
} |
|||
|
|||
function drawBarGlow(context, startX, startY, endX, endY, color, strokeWidth, isVertical) { |
|||
context.setLineDash([]); |
|||
var blur = 0.55; |
|||
var edge = strokeWidth*blur; |
|||
context.lineWidth = strokeWidth+edge; |
|||
var stop = blur/(2*blur+2); |
|||
var gradientStartX = isVertical ? startX - context.lineWidth/2 : 0; |
|||
var gradientStartY = isVertical ? 0 : startY - context.lineWidth/2; |
|||
var gradientStopX = isVertical ? startX + context.lineWidth/2 : 0; |
|||
var gradientStopY = isVertical ? 0 : startY + context.lineWidth/2; |
|||
|
|||
var glowGradient = context.createLinearGradient(gradientStartX,gradientStartY,gradientStopX,gradientStopY); |
|||
var color1 = tinycolor(color).setAlpha(0.5).toRgbString(); |
|||
var color2 = tinycolor(color).setAlpha(0).toRgbString(); |
|||
glowGradient.addColorStop(0,color2); |
|||
glowGradient.addColorStop(stop,color1); |
|||
glowGradient.addColorStop(1.0-stop,color1); |
|||
glowGradient.addColorStop(1,color2); |
|||
context.strokeStyle = glowGradient; |
|||
var dx = isVertical ? 0 : 0.05 * context.lineWidth; |
|||
var dy = isVertical ? 0.05 * context.lineWidth : 0; |
|||
context.beginPath(); |
|||
context.moveTo(startX - dx, startY + dy); |
|||
context.lineTo(endX + dx, endY - dy); |
|||
context.stroke(); |
|||
} |
|||
|
|||
function drawProgress(context, options, progress) { |
|||
var neonColor; |
|||
if (options.neonGlowBrightness) { |
|||
neonColor = getProgressColor(progress, options.neonColorsRange); |
|||
} else { |
|||
context.strokeStyle = getProgressColor(progress, options.colorsRange); |
|||
} |
|||
|
|||
let {barLeft, barRight, barTop, baseX, width, barBottom, Cx, Cy, Rm, Ro, Ri, strokeWidth} = |
|||
context.barDimensions; |
|||
|
|||
if (context.barDimensions.dashLength) { |
|||
context.setLineDash([context.barDimensions.dashLength]); |
|||
} |
|||
context.lineWidth = strokeWidth; |
|||
if (options.roundedLineCap) { |
|||
context.lineCap = 'round'; |
|||
} else { |
|||
context.lineCap = 'butt'; |
|||
} |
|||
if (options.gaugeType === 'donut') { |
|||
if (options.neonGlowBrightness) { |
|||
context.strokeStyle = neonColor; |
|||
} |
|||
context.beginPath(); |
|||
context.arc(Cx, Cy, Rm, 1.5 * Math.PI, 1.5 * Math.PI + 2 * Math.PI * progress); |
|||
context.stroke(); |
|||
if (options.neonGlowBrightness && !options.isMobile) { |
|||
drawArcGlow(context, Cx, Cy, Ri, Rm, Ro, neonColor, progress, true); |
|||
} |
|||
} else if (options.gaugeType === 'arc') { |
|||
if (options.neonGlowBrightness) { |
|||
context.strokeStyle = neonColor; |
|||
} |
|||
context.beginPath(); |
|||
context.arc(Cx, Cy, Rm, Math.PI, Math.PI + Math.PI * progress); |
|||
context.stroke(); |
|||
if (options.neonGlowBrightness && !options.isMobile) { |
|||
drawArcGlow(context, Cx, Cy, Ri, Rm, Ro, neonColor, progress, false); |
|||
} |
|||
} else if (options.gaugeType === 'horizontalBar') { |
|||
if (options.neonGlowBrightness) { |
|||
context.strokeStyle = neonColor; |
|||
} |
|||
context.beginPath(); |
|||
context.moveTo(barLeft,barTop + strokeWidth/2); |
|||
context.lineTo(barLeft + (barRight-barLeft)*progress, barTop + strokeWidth/2); |
|||
context.stroke(); |
|||
if (options.neonGlowBrightness && !options.isMobile) { |
|||
drawBarGlow(context, barLeft, barTop + strokeWidth/2, barLeft + (barRight-barLeft)*progress, barTop + strokeWidth/2, |
|||
neonColor, strokeWidth, false); |
|||
} |
|||
} else if (options.gaugeType === 'verticalBar') { |
|||
if (options.neonGlowBrightness) { |
|||
context.strokeStyle = neonColor; |
|||
} |
|||
context.beginPath(); |
|||
context.moveTo(baseX + width/2, barBottom); |
|||
context.lineTo(baseX + width/2, barBottom - (barBottom-barTop)*progress); |
|||
context.stroke(); |
|||
if (options.neonGlowBrightness && !options.isMobile) { |
|||
drawBarGlow(context, baseX + width/2, barBottom, baseX + width/2, barBottom - (barBottom-barTop)*progress, |
|||
neonColor, strokeWidth, true); |
|||
} |
|||
} |
|||
} |
|||
|
|||
CanvasDigitalGauge.heightCache = []; |
|||
|
|||
canvasGauges.BaseGauge.initialize('CanvasDigitalGauge', defaultDigitalGaugeOptions); |
|||
|
|||
/* eslint-enable angular/angularelement */ |
|||
@ -0,0 +1,921 @@ |
|||
/* |
|||
* 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 $ from 'jquery'; |
|||
import tinycolor from 'tinycolor2'; |
|||
import canvasGauges from 'canvas-gauges'; |
|||
import CanvasDigitalGauge from './CanvasDigitalGauge'; |
|||
|
|||
/* eslint-disable angular/angularelement */ |
|||
export default class TbCanvasDigitalGauge { |
|||
|
|||
constructor(ctx, canvasId) { |
|||
this.ctx = ctx; |
|||
|
|||
canvasGauges.performance = window.performance; // eslint-disable-line no-undef, angular/window-service
|
|||
|
|||
var gaugeElement = $('#'+canvasId, ctx.$container); |
|||
var settings = ctx.settings; |
|||
|
|||
this.localSettings = {}; |
|||
this.localSettings.minValue = settings.minValue || 0; |
|||
this.localSettings.maxValue = settings.maxValue || 100; |
|||
this.localSettings.gaugeType = settings.gaugeType || 'arc'; |
|||
this.localSettings.neonGlowBrightness = settings.neonGlowBrightness || 0; |
|||
this.localSettings.dashThickness = settings.dashThickness || 0; |
|||
this.localSettings.roundedLineCap = settings.roundedLineCap === true; |
|||
|
|||
var dataKey = ctx.data[0].dataKey; |
|||
var keyColor = settings.defaultColor || dataKey.color; |
|||
|
|||
this.localSettings.unitTitle = ((settings.showUnitTitle === true) ? |
|||
(settings.unitTitle && settings.unitTitle.length > 0 ? |
|||
settings.unitTitle : dataKey.label) : ''); |
|||
|
|||
this.localSettings.gaugeWidthScale = settings.gaugeWidthScale || 0.75; |
|||
this.localSettings.gaugeColor = settings.gaugeColor || tinycolor(keyColor).setAlpha(0.2).toRgbString(); |
|||
|
|||
if (!settings.levelColors || settings.levelColors.length <= 0) { |
|||
this.localSettings.levelColors = [keyColor]; |
|||
} else { |
|||
this.localSettings.levelColors = settings.levelColors.slice(); |
|||
} |
|||
|
|||
this.localSettings.decimals = (angular.isDefined(settings.decimals) && settings.decimals !== null) |
|||
? settings.decimals : 0; |
|||
this.localSettings.units = settings.units || ''; |
|||
this.localSettings.hideValue = settings.showValue !== true; |
|||
this.localSettings.hideMinMax = settings.showMinMax !== true; |
|||
|
|||
this.localSettings.title = ((settings.showTitle === true) ? |
|||
(settings.title && settings.title.length > 0 ? |
|||
settings.title : dataKey.label) : ''); |
|||
|
|||
this.localSettings.titleFont = {}; |
|||
var settingsTitleFont = settings.titleFont; |
|||
if (!settingsTitleFont) { |
|||
settingsTitleFont = {}; |
|||
} |
|||
|
|||
function getFontFamily(fontSettings) { |
|||
var family = fontSettings && fontSettings.family ? fontSettings.family : 'Roboto'; |
|||
if (family === 'RobotoDraft') { |
|||
family = 'Roboto'; |
|||
} |
|||
return family; |
|||
} |
|||
|
|||
this.localSettings.titleFont.family = getFontFamily(settingsTitleFont); |
|||
this.localSettings.titleFont.size = settingsTitleFont.size ? settingsTitleFont.size : 12; |
|||
this.localSettings.titleFont.style = settingsTitleFont.style ? settingsTitleFont.style : 'normal'; |
|||
this.localSettings.titleFont.weight = settingsTitleFont.weight ? settingsTitleFont.weight : '500'; |
|||
this.localSettings.titleFont.color = settingsTitleFont.color ? settingsTitleFont.color : keyColor; |
|||
|
|||
this.localSettings.valueFont = {}; |
|||
var settingsValueFont = settings.valueFont; |
|||
if (!settingsValueFont) { |
|||
settingsValueFont = {}; |
|||
} |
|||
|
|||
this.localSettings.valueFont.family = getFontFamily(settingsValueFont); |
|||
this.localSettings.valueFont.size = settingsValueFont.size ? settingsValueFont.size : 18; |
|||
this.localSettings.valueFont.style = settingsValueFont.style ? settingsValueFont.style : 'normal'; |
|||
this.localSettings.valueFont.weight = settingsValueFont.weight ? settingsValueFont.weight : '500'; |
|||
this.localSettings.valueFont.color = settingsValueFont.color ? settingsValueFont.color : keyColor; |
|||
|
|||
this.localSettings.minMaxFont = {}; |
|||
var settingsMinMaxFont = settings.minMaxFont; |
|||
if (!settingsMinMaxFont) { |
|||
settingsMinMaxFont = {}; |
|||
} |
|||
|
|||
this.localSettings.minMaxFont.family = getFontFamily(settingsMinMaxFont); |
|||
this.localSettings.minMaxFont.size = settingsMinMaxFont.size ? settingsMinMaxFont.size : 10; |
|||
this.localSettings.minMaxFont.style = settingsMinMaxFont.style ? settingsMinMaxFont.style : 'normal'; |
|||
this.localSettings.minMaxFont.weight = settingsMinMaxFont.weight ? settingsMinMaxFont.weight : '500'; |
|||
this.localSettings.minMaxFont.color = settingsMinMaxFont.color ? settingsMinMaxFont.color : keyColor; |
|||
|
|||
this.localSettings.labelFont = {}; |
|||
var settingsLabelFont = settings.labelFont; |
|||
if (!settingsLabelFont) { |
|||
settingsLabelFont = {}; |
|||
} |
|||
|
|||
this.localSettings.labelFont.family = getFontFamily(settingsLabelFont); |
|||
this.localSettings.labelFont.size = settingsLabelFont.size ? settingsLabelFont.size : 8; |
|||
this.localSettings.labelFont.style = settingsLabelFont.style ? settingsLabelFont.style : 'normal'; |
|||
this.localSettings.labelFont.weight = settingsLabelFont.weight ? settingsLabelFont.weight : '500'; |
|||
this.localSettings.labelFont.color = settingsLabelFont.color ? settingsLabelFont.color : keyColor; |
|||
|
|||
|
|||
var gaugeData = { |
|||
|
|||
renderTo: gaugeElement[0], |
|||
|
|||
gaugeWidthScale: this.localSettings.gaugeWidthScale, |
|||
gaugeColor: this.localSettings.gaugeColor, |
|||
levelColors: this.localSettings.levelColors, |
|||
|
|||
title: this.localSettings.title, |
|||
|
|||
fontTitleSize: this.localSettings.titleFont.size, |
|||
fontTitleStyle: this.localSettings.titleFont.style, |
|||
fontTitleWeight: this.localSettings.titleFont.weight, |
|||
colorTitle: this.localSettings.titleFont.color, |
|||
fontTitle: this.localSettings.titleFont.family, |
|||
|
|||
fontValueSize: this.localSettings.valueFont.size, |
|||
fontValueStyle: this.localSettings.valueFont.style, |
|||
fontValueWeight: this.localSettings.valueFont.weight, |
|||
colorValue: this.localSettings.valueFont.color, |
|||
fontValue: this.localSettings.valueFont.family, |
|||
|
|||
fontMinMaxSize: this.localSettings.minMaxFont.size, |
|||
fontMinMaxStyle: this.localSettings.minMaxFont.style, |
|||
fontMinMaxWeight: this.localSettings.minMaxFont.weight, |
|||
colorMinMax: this.localSettings.minMaxFont.color, |
|||
fontMinMax: this.localSettings.minMaxFont.family, |
|||
|
|||
fontLabelSize: this.localSettings.labelFont.size, |
|||
fontLabelStyle: this.localSettings.labelFont.style, |
|||
fontLabelWeight: this.localSettings.labelFont.weight, |
|||
colorLabel: this.localSettings.labelFont.color, |
|||
fontLabel: this.localSettings.labelFont.family, |
|||
|
|||
minValue: this.localSettings.minValue, |
|||
maxValue: this.localSettings.maxValue, |
|||
gaugeType: this.localSettings.gaugeType, |
|||
dashThickness: this.localSettings.dashThickness, |
|||
roundedLineCap: this.localSettings.roundedLineCap, |
|||
|
|||
symbol: this.localSettings.units, |
|||
label: this.localSettings.unitTitle, |
|||
hideValue: this.localSettings.hideValue, |
|||
hideMinMax: this.localSettings.hideMinMax, |
|||
|
|||
valueDec: this.localSettings.decimals, |
|||
|
|||
neonGlowBrightness: this.localSettings.neonGlowBrightness, |
|||
|
|||
// animations
|
|||
animation: settings.animation !== false && !ctx.isMobile, |
|||
animationDuration: (angular.isDefined(settings.animationDuration) && settings.animationDuration !== null) ? settings.animationDuration : 500, |
|||
animationRule: settings.animationRule || 'linear', |
|||
|
|||
isMobile: ctx.isMobile |
|||
|
|||
}; |
|||
|
|||
this.gauge = new CanvasDigitalGauge(gaugeData).draw(); |
|||
|
|||
} |
|||
|
|||
update() { |
|||
if (this.ctx.data.length > 0) { |
|||
var cellData = this.ctx.data[0]; |
|||
if (cellData.data.length > 0) { |
|||
var tvPair = cellData.data[cellData.data.length - |
|||
1]; |
|||
var value = tvPair[1]; |
|||
this.gauge.value = value; |
|||
} |
|||
} |
|||
} |
|||
|
|||
mobileModeChanged() { |
|||
var animation = this.ctx.settings.animation !== false && !this.ctx.isMobile; |
|||
this.gauge.update({animation: animation, isMobile: this.ctx.isMobile}); |
|||
} |
|||
|
|||
resize() { |
|||
this.gauge.update({width: this.ctx.width, height: this.ctx.height}); |
|||
} |
|||
|
|||
static get settingsSchema() { |
|||
return { |
|||
"schema": { |
|||
"type": "object", |
|||
"title": "Settings", |
|||
"properties": { |
|||
"minValue": { |
|||
"title": "Minimum value", |
|||
"type": "number", |
|||
"default": 0 |
|||
}, |
|||
"maxValue": { |
|||
"title": "Maximum value", |
|||
"type": "number", |
|||
"default": 100 |
|||
}, |
|||
"gaugeType": { |
|||
"title": "Gauge type", |
|||
"type": "string", |
|||
"default": "arc" |
|||
}, |
|||
"donutStartAngle": { |
|||
"title": "Angle to start from when in donut mode", |
|||
"type": "number", |
|||
"default": 90 |
|||
}, |
|||
"neonGlowBrightness": { |
|||
"title": "Neon glow effect brightness, (0-100), 0 - disable effect", |
|||
"type": "number", |
|||
"default": 0 |
|||
}, |
|||
"dashThickness": { |
|||
"title": "Thickness of the stripes, 0 - no stripes", |
|||
"type": "number", |
|||
"default": 0 |
|||
}, |
|||
"roundedLineCap": { |
|||
"title": "Display rounded line cap", |
|||
"type": "boolean", |
|||
"default": false |
|||
}, |
|||
"title": { |
|||
"title": "Gauge title", |
|||
"type": "string", |
|||
"default": null |
|||
}, |
|||
"showTitle": { |
|||
"title": "Show gauge title", |
|||
"type": "boolean", |
|||
"default": false |
|||
}, |
|||
"unitTitle": { |
|||
"title": "Unit title", |
|||
"type": "string", |
|||
"default": null |
|||
}, |
|||
"showUnitTitle": { |
|||
"title": "Show unit title", |
|||
"type": "boolean", |
|||
"default": false |
|||
}, |
|||
"showValue": { |
|||
"title": "Show value text", |
|||
"type": "boolean", |
|||
"default": true |
|||
}, |
|||
"showMinMax": { |
|||
"title": "Show min and max values", |
|||
"type": "boolean", |
|||
"default": true |
|||
}, |
|||
"gaugeWidthScale": { |
|||
"title": "Width of the gauge element", |
|||
"type": "number", |
|||
"default": 0.75 |
|||
}, |
|||
"defaultColor": { |
|||
"title": "Default color", |
|||
"type": "string", |
|||
"default": null |
|||
}, |
|||
"gaugeColor": { |
|||
"title": "Background color of the gauge element", |
|||
"type": "string", |
|||
"default": null |
|||
}, |
|||
"levelColors": { |
|||
"title": "Colors of indicator, from lower to upper", |
|||
"type": "array", |
|||
"items": { |
|||
"title": "Color", |
|||
"type": "string" |
|||
} |
|||
}, |
|||
"animation": { |
|||
"title": "Enable animation", |
|||
"type": "boolean", |
|||
"default": true |
|||
}, |
|||
"animationDuration": { |
|||
"title": "Animation duration", |
|||
"type": "number", |
|||
"default": 500 |
|||
}, |
|||
"animationRule": { |
|||
"title": "Animation rule", |
|||
"type": "string", |
|||
"default": "linear" |
|||
}, |
|||
"decimals": { |
|||
"title": "Number of digits after floating point", |
|||
"type": "number", |
|||
"default": 0 |
|||
}, |
|||
"units": { |
|||
"title": "Special symbol to show next to value", |
|||
"type": "string", |
|||
"default": "" |
|||
}, |
|||
"titleFont": { |
|||
"title": "Gauge title font", |
|||
"type": "object", |
|||
"properties": { |
|||
"family": { |
|||
"title": "Font family", |
|||
"type": "string", |
|||
"default": "Roboto" |
|||
}, |
|||
"size": { |
|||
"title": "Size", |
|||
"type": "number", |
|||
"default": 12 |
|||
}, |
|||
"style": { |
|||
"title": "Style", |
|||
"type": "string", |
|||
"default": "normal" |
|||
}, |
|||
"weight": { |
|||
"title": "Weight", |
|||
"type": "string", |
|||
"default": "500" |
|||
}, |
|||
"color": { |
|||
"title": "color", |
|||
"type": "string", |
|||
"default": null |
|||
} |
|||
} |
|||
}, |
|||
"labelFont": { |
|||
"title": "Font of label showing under value", |
|||
"type": "object", |
|||
"properties": { |
|||
"family": { |
|||
"title": "Font family", |
|||
"type": "string", |
|||
"default": "Roboto" |
|||
}, |
|||
"size": { |
|||
"title": "Size", |
|||
"type": "number", |
|||
"default": 8 |
|||
}, |
|||
"style": { |
|||
"title": "Style", |
|||
"type": "string", |
|||
"default": "normal" |
|||
}, |
|||
"weight": { |
|||
"title": "Weight", |
|||
"type": "string", |
|||
"default": "500" |
|||
}, |
|||
"color": { |
|||
"title": "color", |
|||
"type": "string", |
|||
"default": null |
|||
} |
|||
} |
|||
}, |
|||
"valueFont": { |
|||
"title": "Font of label showing current value", |
|||
"type": "object", |
|||
"properties": { |
|||
"family": { |
|||
"title": "Font family", |
|||
"type": "string", |
|||
"default": "Roboto" |
|||
}, |
|||
"size": { |
|||
"title": "Size", |
|||
"type": "number", |
|||
"default": 18 |
|||
}, |
|||
"style": { |
|||
"title": "Style", |
|||
"type": "string", |
|||
"default": "normal" |
|||
}, |
|||
"weight": { |
|||
"title": "Weight", |
|||
"type": "string", |
|||
"default": "500" |
|||
}, |
|||
"color": { |
|||
"title": "color", |
|||
"type": "string", |
|||
"default": null |
|||
} |
|||
} |
|||
}, |
|||
"minMaxFont": { |
|||
"title": "Font of minimum and maximum labels", |
|||
"type": "object", |
|||
"properties": { |
|||
"family": { |
|||
"title": "Font family", |
|||
"type": "string", |
|||
"default": "Roboto" |
|||
}, |
|||
"size": { |
|||
"title": "Size", |
|||
"type": "number", |
|||
"default": 10 |
|||
}, |
|||
"style": { |
|||
"title": "Style", |
|||
"type": "string", |
|||
"default": "normal" |
|||
}, |
|||
"weight": { |
|||
"title": "Weight", |
|||
"type": "string", |
|||
"default": "500" |
|||
}, |
|||
"color": { |
|||
"title": "color", |
|||
"type": "string", |
|||
"default": null |
|||
} |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
"form": [ |
|||
"minValue", |
|||
"maxValue", |
|||
{ |
|||
"key": "gaugeType", |
|||
"type": "rc-select", |
|||
"multiple": false, |
|||
"items": [ |
|||
{ |
|||
"value": "arc", |
|||
"label": "Arc" |
|||
}, |
|||
{ |
|||
"value": "donut", |
|||
"label": "Donut" |
|||
}, |
|||
{ |
|||
"value": "horizontalBar", |
|||
"label": "Horizontal bar" |
|||
}, |
|||
{ |
|||
"value": "verticalBar", |
|||
"label": "Vertical bar" |
|||
} |
|||
] |
|||
}, |
|||
"donutStartAngle", |
|||
"neonGlowBrightness", |
|||
"dashThickness", |
|||
"roundedLineCap", |
|||
"title", |
|||
"showTitle", |
|||
"unitTitle", |
|||
"showUnitTitle", |
|||
"showValue", |
|||
"showMinMax", |
|||
"gaugeWidthScale", |
|||
{ |
|||
"key": "defaultColor", |
|||
"type": "color" |
|||
}, |
|||
{ |
|||
"key": "gaugeColor", |
|||
"type": "color" |
|||
}, |
|||
{ |
|||
"key": "levelColors", |
|||
"items": [ |
|||
{ |
|||
"key": "levelColors[]", |
|||
"type": "color" |
|||
} |
|||
] |
|||
}, |
|||
"animation", |
|||
"animationDuration", |
|||
{ |
|||
"key": "animationRule", |
|||
"type": "rc-select", |
|||
"multiple": false, |
|||
"items": [ |
|||
{ |
|||
"value": "linear", |
|||
"label": "Linear" |
|||
}, |
|||
{ |
|||
"value": "quad", |
|||
"label": "Quad" |
|||
}, |
|||
{ |
|||
"value": "quint", |
|||
"label": "Quint" |
|||
}, |
|||
{ |
|||
"value": "cycle", |
|||
"label": "Cycle" |
|||
}, |
|||
{ |
|||
"value": "bounce", |
|||
"label": "Bounce" |
|||
}, |
|||
{ |
|||
"value": "elastic", |
|||
"label": "Elastic" |
|||
}, |
|||
{ |
|||
"value": "dequad", |
|||
"label": "Dequad" |
|||
}, |
|||
{ |
|||
"value": "dequint", |
|||
"label": "Dequint" |
|||
}, |
|||
{ |
|||
"value": "decycle", |
|||
"label": "Decycle" |
|||
}, |
|||
{ |
|||
"value": "debounce", |
|||
"label": "Debounce" |
|||
}, |
|||
{ |
|||
"value": "delastic", |
|||
"label": "Delastic" |
|||
} |
|||
] |
|||
}, |
|||
"decimals", |
|||
"units", |
|||
{ |
|||
"key": "titleFont", |
|||
"items": [ |
|||
"titleFont.family", |
|||
"titleFont.size", |
|||
{ |
|||
"key": "titleFont.style", |
|||
"type": "rc-select", |
|||
"multiple": false, |
|||
"items": [ |
|||
{ |
|||
"value": "normal", |
|||
"label": "Normal" |
|||
}, |
|||
{ |
|||
"value": "italic", |
|||
"label": "Italic" |
|||
}, |
|||
{ |
|||
"value": "oblique", |
|||
"label": "Oblique" |
|||
} |
|||
] |
|||
}, |
|||
{ |
|||
"key": "titleFont.weight", |
|||
"type": "rc-select", |
|||
"multiple": false, |
|||
"items": [ |
|||
{ |
|||
"value": "normal", |
|||
"label": "Normal" |
|||
}, |
|||
{ |
|||
"value": "bold", |
|||
"label": "Bold" |
|||
}, |
|||
{ |
|||
"value": "bolder", |
|||
"label": "Bolder" |
|||
}, |
|||
{ |
|||
"value": "lighter", |
|||
"label": "Lighter" |
|||
}, |
|||
{ |
|||
"value": "100", |
|||
"label": "100" |
|||
}, |
|||
{ |
|||
"value": "200", |
|||
"label": "200" |
|||
}, |
|||
{ |
|||
"value": "300", |
|||
"label": "300" |
|||
}, |
|||
{ |
|||
"value": "400", |
|||
"label": "400" |
|||
}, |
|||
{ |
|||
"value": "500", |
|||
"label": "500" |
|||
}, |
|||
{ |
|||
"value": "600", |
|||
"label": "600" |
|||
}, |
|||
{ |
|||
"value": "700", |
|||
"label": "800" |
|||
}, |
|||
{ |
|||
"value": "800", |
|||
"label": "800" |
|||
}, |
|||
{ |
|||
"value": "900", |
|||
"label": "900" |
|||
} |
|||
] |
|||
}, |
|||
{ |
|||
"key": "titleFont.color", |
|||
"type": "color" |
|||
} |
|||
] |
|||
}, |
|||
{ |
|||
"key": "labelFont", |
|||
"items": [ |
|||
"labelFont.family", |
|||
"labelFont.size", |
|||
{ |
|||
"key": "labelFont.style", |
|||
"type": "rc-select", |
|||
"multiple": false, |
|||
"items": [ |
|||
{ |
|||
"value": "normal", |
|||
"label": "Normal" |
|||
}, |
|||
{ |
|||
"value": "italic", |
|||
"label": "Italic" |
|||
}, |
|||
{ |
|||
"value": "oblique", |
|||
"label": "Oblique" |
|||
} |
|||
] |
|||
}, |
|||
{ |
|||
"key": "labelFont.weight", |
|||
"type": "rc-select", |
|||
"multiple": false, |
|||
"items": [ |
|||
{ |
|||
"value": "normal", |
|||
"label": "Normal" |
|||
}, |
|||
{ |
|||
"value": "bold", |
|||
"label": "Bold" |
|||
}, |
|||
{ |
|||
"value": "bolder", |
|||
"label": "Bolder" |
|||
}, |
|||
{ |
|||
"value": "lighter", |
|||
"label": "Lighter" |
|||
}, |
|||
{ |
|||
"value": "100", |
|||
"label": "100" |
|||
}, |
|||
{ |
|||
"value": "200", |
|||
"label": "200" |
|||
}, |
|||
{ |
|||
"value": "300", |
|||
"label": "300" |
|||
}, |
|||
{ |
|||
"value": "400", |
|||
"label": "400" |
|||
}, |
|||
{ |
|||
"value": "500", |
|||
"label": "500" |
|||
}, |
|||
{ |
|||
"value": "600", |
|||
"label": "600" |
|||
}, |
|||
{ |
|||
"value": "700", |
|||
"label": "800" |
|||
}, |
|||
{ |
|||
"value": "800", |
|||
"label": "800" |
|||
}, |
|||
{ |
|||
"value": "900", |
|||
"label": "900" |
|||
} |
|||
] |
|||
}, |
|||
{ |
|||
"key": "labelFont.color", |
|||
"type": "color" |
|||
} |
|||
] |
|||
}, |
|||
{ |
|||
"key": "valueFont", |
|||
"items": [ |
|||
"valueFont.family", |
|||
"valueFont.size", |
|||
{ |
|||
"key": "valueFont.style", |
|||
"type": "rc-select", |
|||
"multiple": false, |
|||
"items": [ |
|||
{ |
|||
"value": "normal", |
|||
"label": "Normal" |
|||
}, |
|||
{ |
|||
"value": "italic", |
|||
"label": "Italic" |
|||
}, |
|||
{ |
|||
"value": "oblique", |
|||
"label": "Oblique" |
|||
} |
|||
] |
|||
}, |
|||
{ |
|||
"key": "valueFont.weight", |
|||
"type": "rc-select", |
|||
"multiple": false, |
|||
"items": [ |
|||
{ |
|||
"value": "normal", |
|||
"label": "Normal" |
|||
}, |
|||
{ |
|||
"value": "bold", |
|||
"label": "Bold" |
|||
}, |
|||
{ |
|||
"value": "bolder", |
|||
"label": "Bolder" |
|||
}, |
|||
{ |
|||
"value": "lighter", |
|||
"label": "Lighter" |
|||
}, |
|||
{ |
|||
"value": "100", |
|||
"label": "100" |
|||
}, |
|||
{ |
|||
"value": "200", |
|||
"label": "200" |
|||
}, |
|||
{ |
|||
"value": "300", |
|||
"label": "300" |
|||
}, |
|||
{ |
|||
"value": "400", |
|||
"label": "400" |
|||
}, |
|||
{ |
|||
"value": "500", |
|||
"label": "500" |
|||
}, |
|||
{ |
|||
"value": "600", |
|||
"label": "600" |
|||
}, |
|||
{ |
|||
"value": "700", |
|||
"label": "800" |
|||
}, |
|||
{ |
|||
"value": "800", |
|||
"label": "800" |
|||
}, |
|||
{ |
|||
"value": "900", |
|||
"label": "900" |
|||
} |
|||
] |
|||
}, |
|||
{ |
|||
"key": "valueFont.color", |
|||
"type": "color" |
|||
} |
|||
] |
|||
}, |
|||
{ |
|||
"key": "minMaxFont", |
|||
"items": [ |
|||
"minMaxFont.family", |
|||
"minMaxFont.size", |
|||
{ |
|||
"key": "minMaxFont.style", |
|||
"type": "rc-select", |
|||
"multiple": false, |
|||
"items": [ |
|||
{ |
|||
"value": "normal", |
|||
"label": "Normal" |
|||
}, |
|||
{ |
|||
"value": "italic", |
|||
"label": "Italic" |
|||
}, |
|||
{ |
|||
"value": "oblique", |
|||
"label": "Oblique" |
|||
} |
|||
] |
|||
}, |
|||
{ |
|||
"key": "minMaxFont.weight", |
|||
"type": "rc-select", |
|||
"multiple": false, |
|||
"items": [ |
|||
{ |
|||
"value": "normal", |
|||
"label": "Normal" |
|||
}, |
|||
{ |
|||
"value": "bold", |
|||
"label": "Bold" |
|||
}, |
|||
{ |
|||
"value": "bolder", |
|||
"label": "Bolder" |
|||
}, |
|||
{ |
|||
"value": "lighter", |
|||
"label": "Lighter" |
|||
}, |
|||
{ |
|||
"value": "100", |
|||
"label": "100" |
|||
}, |
|||
{ |
|||
"value": "200", |
|||
"label": "200" |
|||
}, |
|||
{ |
|||
"value": "300", |
|||
"label": "300" |
|||
}, |
|||
{ |
|||
"value": "400", |
|||
"label": "400" |
|||
}, |
|||
{ |
|||
"value": "500", |
|||
"label": "500" |
|||
}, |
|||
{ |
|||
"value": "600", |
|||
"label": "600" |
|||
}, |
|||
{ |
|||
"value": "700", |
|||
"label": "800" |
|||
}, |
|||
{ |
|||
"value": "800", |
|||
"label": "800" |
|||
}, |
|||
{ |
|||
"value": "900", |
|||
"label": "900" |
|||
} |
|||
] |
|||
}, |
|||
{ |
|||
"key": "minMaxFont.color", |
|||
"type": "color" |
|||
} |
|||
] |
|||
} |
|||
] |
|||
}; |
|||
} |
|||
} |
|||
/* eslint-enable angular/angularelement */ |
|||
@ -1,591 +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. |
|||
*/ |
|||
import $ from 'jquery'; |
|||
import tinycolor from 'tinycolor2'; |
|||
import 'justgage'; |
|||
import Raphael from 'raphael'; |
|||
|
|||
/* eslint-disable angular/angularelement */ |
|||
|
|||
export default class TbDigitalGauge { |
|||
constructor(containerElement, settings, data) { |
|||
|
|||
var tbGauge = this; |
|||
|
|||
window.Raphael = Raphael; // eslint-disable-line no-undef, angular/window-service
|
|||
|
|||
var isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1; // eslint-disable-line no-undef
|
|||
|
|||
var gaugeElement = $(containerElement); |
|||
|
|||
this.localSettings = {}; |
|||
|
|||
this.localSettings.minValue = settings.minValue || 0; |
|||
this.localSettings.maxValue = settings.maxValue || 100; |
|||
this.localSettings.gaugeType = settings.gaugeType || 'arc'; |
|||
this.localSettings.donutStartAngle = (angular.isDefined(settings.donutStartAngle) && settings.donutStartAngle !== null) |
|||
? settings.donutStartAngle : 90; |
|||
this.localSettings.neonGlowBrightness = settings.neonGlowBrightness || 0; |
|||
this.localSettings.dashThickness = settings.dashThickness || 0; |
|||
this.localSettings.roundedLineCap = settings.roundedLineCap === true; |
|||
|
|||
var dataKey = data[0].dataKey; |
|||
var keyColor = settings.defaultColor || dataKey.color; |
|||
|
|||
this.localSettings.title = ((settings.showTitle === true) ? |
|||
(settings.title && settings.title.length > 0 ? |
|||
settings.title : dataKey.label) : ''); |
|||
|
|||
this.localSettings.unitTitle = ((settings.showUnitTitle === true) ? |
|||
(settings.unitTitle && settings.unitTitle.length > 0 ? |
|||
settings.unitTitle : dataKey.label) : ''); |
|||
|
|||
this.localSettings.gaugeWidthScale = settings.gaugeWidthScale || 0.75; |
|||
this.localSettings.gaugeColor = settings.gaugeColor || tinycolor(keyColor).setAlpha(0.2).toRgbString(); |
|||
|
|||
if (!settings.levelColors || settings.levelColors.length <= 0) { |
|||
this.localSettings.levelColors = [keyColor, keyColor]; |
|||
} else { |
|||
this.localSettings.levelColors = settings.levelColors.slice(); |
|||
} |
|||
if (this.localSettings.neonGlowBrightness) { |
|||
this.localSettings.origLevelColors = []; |
|||
for (var i = 0; i < this.localSettings.levelColors.length; i++) { |
|||
this.localSettings.origLevelColors.push(this.localSettings.levelColors[i]); |
|||
this.localSettings.levelColors[i] = tinycolor(this.localSettings.levelColors[i]).brighten(this.localSettings.neonGlowBrightness).toHexString(); |
|||
} |
|||
var colorsCount = this.localSettings.origLevelColors.length; |
|||
var inc = colorsCount > 1 ? (1 / (colorsCount - 1)) : 1; |
|||
this.localSettings.colorsRange = []; |
|||
for (i = 0; i < this.localSettings.origLevelColors.length; i++) { |
|||
var percentage = inc * i; |
|||
var tColor = tinycolor(this.localSettings.origLevelColors[i]); |
|||
this.localSettings.colorsRange[i] = { |
|||
pct: percentage, |
|||
color: tColor.toRgb(), |
|||
rgbString: tColor.toRgbString |
|||
}; |
|||
} |
|||
} |
|||
|
|||
|
|||
this.localSettings.refreshAnimationType = settings.refreshAnimationType || '>'; |
|||
this.localSettings.refreshAnimationTime = settings.refreshAnimationTime || 700; |
|||
this.localSettings.startAnimationType = settings.startAnimationType || '>'; |
|||
this.localSettings.startAnimationTime = settings.startAnimationTime || 700; |
|||
this.localSettings.decimals = (angular.isDefined(settings.decimals) && settings.decimals !== null) |
|||
? settings.decimals : 0; |
|||
this.localSettings.units = settings.units || ''; |
|||
this.localSettings.hideValue = settings.showValue !== true; |
|||
this.localSettings.hideMinMax = settings.showMinMax !== true; |
|||
|
|||
this.localSettings.titleFont = {}; |
|||
var settingsTitleFont = settings.titleFont; |
|||
if (!settingsTitleFont) { |
|||
settingsTitleFont = {}; |
|||
} |
|||
|
|||
this.localSettings.titleFont.family = settingsTitleFont.family || 'RobotoDraft'; |
|||
this.localSettings.titleFont.size = settingsTitleFont.size ? settingsTitleFont.size : 12; |
|||
this.localSettings.titleFont.style = settingsTitleFont.style ? settingsTitleFont.style : 'normal'; |
|||
this.localSettings.titleFont.weight = settingsTitleFont.weight ? settingsTitleFont.weight : '500'; |
|||
this.localSettings.titleFont.color = settingsTitleFont.color ? settingsTitleFont.color : keyColor; |
|||
|
|||
this.localSettings.labelFont = {}; |
|||
var settingsLabelFont = settings.labelFont; |
|||
if (!settingsLabelFont) { |
|||
settingsLabelFont = {}; |
|||
} |
|||
|
|||
this.localSettings.labelFont.family = settingsLabelFont.family || 'RobotoDraft'; |
|||
this.localSettings.labelFont.size = settingsLabelFont.size ? settingsLabelFont.size : 8; |
|||
this.localSettings.labelFont.style = settingsLabelFont.style ? settingsLabelFont.style : 'normal'; |
|||
this.localSettings.labelFont.weight = settingsLabelFont.weight ? settingsLabelFont.weight : '500'; |
|||
this.localSettings.labelFont.color = settingsLabelFont.color ? settingsLabelFont.color : keyColor; |
|||
|
|||
this.localSettings.valueFont = {}; |
|||
var settingsValueFont = settings.valueFont; |
|||
if (!settingsValueFont) { |
|||
settingsValueFont = {}; |
|||
} |
|||
|
|||
this.localSettings.valueFont.family = settingsValueFont.family || 'RobotoDraft'; |
|||
this.localSettings.valueFont.size = settingsValueFont.size ? settingsValueFont.size : 18; |
|||
this.localSettings.valueFont.style = settingsValueFont.style ? settingsValueFont.style : 'normal'; |
|||
this.localSettings.valueFont.weight = settingsValueFont.weight ? settingsValueFont.weight : '500'; |
|||
this.localSettings.valueFont.color = settingsValueFont.color ? settingsValueFont.color : keyColor; |
|||
|
|||
this.localSettings.minMaxFont = {}; |
|||
var settingsMinMaxFont = settings.minMaxFont; |
|||
if (!settingsMinMaxFont) { |
|||
settingsMinMaxFont = {}; |
|||
} |
|||
|
|||
this.localSettings.minMaxFont.family = settingsMinMaxFont.family || 'RobotoDraft'; |
|||
this.localSettings.minMaxFont.size = settingsMinMaxFont.size ? settingsMinMaxFont.size : 10; |
|||
this.localSettings.minMaxFont.style = settingsMinMaxFont.style ? settingsMinMaxFont.style : 'normal'; |
|||
this.localSettings.minMaxFont.weight = settingsMinMaxFont.weight ? settingsMinMaxFont.weight : '500'; |
|||
this.localSettings.minMaxFont.color = settingsMinMaxFont.color ? settingsMinMaxFont.color : keyColor; |
|||
|
|||
if (this.localSettings.neonGlowBrightness) { |
|||
this.localSettings.titleFont.origColor = this.localSettings.titleFont.color; |
|||
this.localSettings.titleFont.color = tinycolor(this.localSettings.titleFont.color).brighten(this.localSettings.neonGlowBrightness).toHexString(); |
|||
this.localSettings.labelFont.origColor = this.localSettings.labelFont.color; |
|||
this.localSettings.labelFont.color = tinycolor(this.localSettings.labelFont.color).brighten(this.localSettings.neonGlowBrightness).toHexString(); |
|||
this.localSettings.valueFont.origColor = this.localSettings.valueFont.color; |
|||
this.localSettings.valueFont.color = tinycolor(this.localSettings.valueFont.color).brighten(this.localSettings.neonGlowBrightness).toHexString(); |
|||
this.localSettings.minMaxFont.origColor = this.localSettings.minMaxFont.color; |
|||
this.localSettings.minMaxFont.color = tinycolor(this.localSettings.minMaxFont.color).brighten(this.localSettings.neonGlowBrightness).toHexString(); |
|||
} |
|||
|
|||
var gaugeOptions = { |
|||
parentNode: gaugeElement[0], |
|||
value: 0, |
|||
min: this.localSettings.minValue, |
|||
max: this.localSettings.maxValue, |
|||
title: this.localSettings.title, |
|||
label: this.localSettings.unitTitle, |
|||
humanFriendlyDecimal: 0, |
|||
gaugeWidthScale: this.localSettings.gaugeWidthScale, |
|||
relativeGaugeSize: true, |
|||
gaugeColor: this.localSettings.gaugeColor, |
|||
levelColors: this.localSettings.levelColors, |
|||
refreshAnimationType: this.localSettings.refreshAnimationType, |
|||
refreshAnimationTime: this.localSettings.refreshAnimationTime, |
|||
startAnimationType: this.localSettings.startAnimationType, |
|||
startAnimationTime: this.localSettings.startAnimationTime, |
|||
humanFriendly: false, |
|||
donut: this.localSettings.gaugeType === 'donut', |
|||
donutStartAngle: this.localSettings.donutStartAngle, |
|||
decimals: this.localSettings.decimals, |
|||
pointer: false, |
|||
symbol: this.localSettings.units, |
|||
hideValue: this.localSettings.hideValue, |
|||
hideMinMax: this.localSettings.hideMinMax, |
|||
titleFontColor: this.localSettings.titleFont.color, |
|||
labelFontColor: this.localSettings.labelFont.color, |
|||
valueFontColor: this.localSettings.valueFont.color, |
|||
valueFontFamily: this.localSettings.valueFont.family |
|||
}; |
|||
|
|||
this.gauge = new JustGage(gaugeOptions); // eslint-disable-line no-undef
|
|||
|
|||
var gParams = this.gauge.params; |
|||
|
|||
var titleTextElement = $(this.gauge.txtTitle.node); |
|||
titleTextElement.css('fontFamily', this.localSettings.titleFont.family); |
|||
titleTextElement.css('fontSize', this.localSettings.titleFont.size + 'px'); |
|||
titleTextElement.css('fontStyle', this.localSettings.titleFont.style); |
|||
titleTextElement.css('fontWeight', this.localSettings.titleFont.weight); |
|||
titleTextElement.css('textTransform', 'uppercase'); |
|||
|
|||
var labelTextElement = $(this.gauge.txtLabel.node); |
|||
labelTextElement.css('fontFamily', this.localSettings.labelFont.family); |
|||
labelTextElement.css('fontSize', this.localSettings.labelFont.size + 'px'); |
|||
labelTextElement.css('fontStyle', this.localSettings.labelFont.style); |
|||
labelTextElement.css('fontWeight', this.localSettings.labelFont.weight); |
|||
labelTextElement.css('textTransform', 'uppercase'); |
|||
|
|||
var valueTextElement = $(this.gauge.txtValue.node); |
|||
valueTextElement.css('fontSize', this.localSettings.valueFont.size + 'px'); |
|||
valueTextElement.css('fontStyle', this.localSettings.valueFont.style); |
|||
valueTextElement.css('fontWeight', this.localSettings.valueFont.weight); |
|||
|
|||
var minValTextElement = $(this.gauge.txtMin.node); |
|||
var maxValTextElement = $(this.gauge.txtMax.node); |
|||
minValTextElement.css('fontFamily', this.localSettings.minMaxFont.family); |
|||
maxValTextElement.css('fontFamily', this.localSettings.minMaxFont.family); |
|||
minValTextElement.css('fontSize', this.localSettings.minMaxFont.size+'px'); |
|||
maxValTextElement.css('fontSize', this.localSettings.minMaxFont.size+'px'); |
|||
minValTextElement.css('fontStyle', this.localSettings.minMaxFont.style); |
|||
maxValTextElement.css('fontStyle', this.localSettings.minMaxFont.style); |
|||
minValTextElement.css('fontWeight', this.localSettings.minMaxFont.weight); |
|||
maxValTextElement.css('fontWeight', this.localSettings.minMaxFont.weight); |
|||
minValTextElement.css('fill', this.localSettings.minMaxFont.color); |
|||
maxValTextElement.css('fill', this.localSettings.minMaxFont.color); |
|||
|
|||
var gaugeLevelElement = $(this.gauge.level.node); |
|||
var gaugeBackElement = $(this.gauge.gauge.node); |
|||
|
|||
var w = gParams.widgetW; |
|||
var gws = this.localSettings.gaugeWidthScale; |
|||
var Ro, Ri; |
|||
if (this.localSettings.gaugeType === 'donut') { |
|||
Ro = w / 2 - w / 7; |
|||
} else { |
|||
Ro = w / 2 - w / 10; |
|||
} |
|||
Ri = Ro - w / 6.666666666666667 * gws; |
|||
gParams.strokeWidth = Ro - Ri; |
|||
|
|||
gParams.viewport = { |
|||
x: 0, |
|||
y: 0, |
|||
width: gParams.canvasW, |
|||
height: gParams.canvasH |
|||
} |
|||
var maxW; |
|||
if (this.localSettings.gaugeType === 'donut') { |
|||
if (gaugeOptions.title && gaugeOptions.title.length > 0) { |
|||
gParams.viewport.height = 140; |
|||
} else { |
|||
gParams.viewport.y = 17; |
|||
gParams.viewport.height = 120; |
|||
} |
|||
gParams.viewport.x = 40; |
|||
gParams.viewport.width = 120; |
|||
$('tspan', labelTextElement).attr('dy', '6'); |
|||
if (!this.localSettings.unitTitle || this.localSettings.unitTitle.length === 0) { |
|||
var Cy = gParams.widgetH / 1.95 + gParams.dy; |
|||
gParams.valueY = Cy + (this.localSettings.valueFont.size-4)/2; |
|||
this.gauge.txtValue.attr({"y": gParams.valueY }); |
|||
} |
|||
} else if (this.localSettings.gaugeType === 'arc') { |
|||
if (gaugeOptions.title && gaugeOptions.title.length > 0) { |
|||
gParams.viewport.y = 5; |
|||
gParams.viewport.height = 140; |
|||
} else { |
|||
gParams.viewport.y = 40; |
|||
gParams.viewport.height = 100; |
|||
} |
|||
if (this.localSettings.roundedLineCap) { |
|||
$('tspan', minValTextElement).attr('dy', ''+(gParams.strokeWidth/2)); |
|||
$('tspan', maxValTextElement).attr('dy', ''+(gParams.strokeWidth/2)); |
|||
} |
|||
} else if (this.localSettings.gaugeType === 'horizontalBar') { |
|||
gParams.titleY = gParams.dy + gParams.widgetH / 3.5 + (this.localSettings.title === '' ? 0 : this.localSettings.titleFont.size); |
|||
this.gauge.txtTitle.attr({"y": gParams.titleY }); |
|||
gParams.titleBottom = gParams.titleY + (this.localSettings.title === '' ? 0 : 8); |
|||
|
|||
gParams.valueY = gParams.titleBottom + (this.localSettings.hideValue ? 0 : this.localSettings.valueFont.size); |
|||
gParams.barTop = gParams.valueY + 8; |
|||
gParams.barBottom = gParams.barTop + gParams.strokeWidth; |
|||
|
|||
this.gauge.txtValue.attr({"y": gParams.valueY }); |
|||
|
|||
if (this.localSettings.hideMinMax && this.localSettings.unitTitle === '') { |
|||
gParams.labelY = gParams.barBottom; |
|||
gParams.barLeft = this.localSettings.minMaxFont.size/3; |
|||
gParams.barRight = gParams.viewport.width - this.localSettings.minMaxFont.size/3; |
|||
} else { |
|||
maxW = Math.max(this.gauge.txtMin.node.getComputedTextLength(), this.gauge.txtMax.node.getComputedTextLength()); |
|||
gParams.minX = maxW/2 + this.localSettings.minMaxFont.size/3; |
|||
gParams.maxX = gParams.viewport.width - maxW/2 - this.localSettings.minMaxFont.size/3; |
|||
gParams.barLeft = gParams.minX; |
|||
gParams.barRight = gParams.maxX; |
|||
gParams.labelY = gParams.barBottom + 4 + this.localSettings.labelFont.size; |
|||
this.gauge.txtLabel.attr({"y": gParams.labelY }); |
|||
this.gauge.txtMin.attr({"x": gParams.minX, "y": gParams.labelY }); |
|||
this.gauge.txtMax.attr({"x": gParams.maxX, "y": gParams.labelY }); |
|||
} |
|||
gParams.viewport.y = 40; |
|||
gParams.viewport.height = gParams.labelY-25; |
|||
} else if (this.localSettings.gaugeType === 'verticalBar') { |
|||
gParams.titleY = (this.localSettings.title === '' ? 0 : this.localSettings.titleFont.size) + 8; |
|||
this.gauge.txtTitle.attr({"y": gParams.titleY }); |
|||
gParams.titleBottom = gParams.titleY + (this.localSettings.title === '' ? 0 : 8); |
|||
|
|||
gParams.valueY = gParams.titleBottom + (this.localSettings.hideValue ? 0 : this.localSettings.valueFont.size); |
|||
gParams.barTop = gParams.valueY + 8; |
|||
this.gauge.txtValue.attr({"y": gParams.valueY }); |
|||
|
|||
gParams.labelY = gParams.widgetH - 16; |
|||
if (this.localSettings.unitTitle === '') { |
|||
gParams.barBottom = gParams.labelY; |
|||
} else { |
|||
gParams.barBottom = gParams.labelY - 4 - this.localSettings.labelFont.size; |
|||
this.gauge.txtLabel.attr({"y": gParams.labelY }); |
|||
} |
|||
gParams.minX = gParams.maxX = (gParams.widgetW/2 + gParams.dx) + gParams.strokeWidth/2 + this.localSettings.minMaxFont.size/3; |
|||
gParams.minY = gParams.barBottom; |
|||
gParams.maxY = gParams.barTop; |
|||
this.gauge.txtMin.attr({"text-anchor": "start", "x": gParams.minX, "y": gParams.minY }); |
|||
this.gauge.txtMax.attr({"text-anchor": "start", "x": gParams.maxX, "y": gParams.maxY }); |
|||
gParams.prefWidth = gParams.strokeWidth; |
|||
if (!this.localSettings.hideMinMax) { |
|||
maxW = Math.max(this.gauge.txtMin.node.getComputedTextLength(), this.gauge.txtMax.node.getComputedTextLength()); |
|||
gParams.prefWidth += (maxW + this.localSettings.minMaxFont.size ) * 2; |
|||
} |
|||
gParams.viewport.x = (gParams.canvasW - gParams.prefWidth)/2; |
|||
gParams.viewport.width = gParams.prefWidth; |
|||
} |
|||
this.gauge.canvas.setViewBox(gParams.viewport.x, gParams.viewport.y, gParams.viewport.width, gParams.viewport.height, true); |
|||
|
|||
if (this.localSettings.dashThickness) { |
|||
var Rm = Ri + gParams.strokeWidth * 0.5; |
|||
var circumference = Math.PI * Rm; |
|||
if (this.localSettings.gaugeType === 'donut') { |
|||
circumference *=2; |
|||
} |
|||
var dashCount = Math.floor(circumference / (this.localSettings.dashThickness)); |
|||
if (this.localSettings.gaugeType === 'donut') { |
|||
dashCount = (dashCount | 1) - 1; |
|||
} else { |
|||
dashCount = (dashCount - 1) | 1; |
|||
} |
|||
var dashLength = circumference/dashCount; |
|||
gaugeLevelElement.attr('stroke-dasharray', '' + dashLength + 'px'); |
|||
gaugeBackElement.attr('stroke-dasharray', '' + dashLength + 'px'); |
|||
} |
|||
|
|||
function getColor(val, pct) { |
|||
|
|||
var lower, upper, range, rangePct, pctLower, pctUpper, color; |
|||
|
|||
if (tbGauge.localSettings.colorsRange.length === 1) { |
|||
return tbGauge.localSettings.colorsRange[0].rgbString; |
|||
} |
|||
if (pct === 0) { |
|||
return tbGauge.localSettings.colorsRange[0].rgbString; |
|||
} |
|||
|
|||
for (var j = 0; j < tbGauge.localSettings.colorsRange.length; j++) { |
|||
if (pct <= tbGauge.localSettings.colorsRange[j].pct) { |
|||
lower = tbGauge.localSettings.colorsRange[j - 1]; |
|||
upper = tbGauge.localSettings.colorsRange[j]; |
|||
range = upper.pct - lower.pct; |
|||
rangePct = (pct - lower.pct) / range; |
|||
pctLower = 1 - rangePct; |
|||
pctUpper = rangePct; |
|||
color = tinycolor({ |
|||
r: Math.floor(lower.color.r * pctLower + upper.color.r * pctUpper), |
|||
g: Math.floor(lower.color.g * pctLower + upper.color.g * pctUpper), |
|||
b: Math.floor(lower.color.b * pctLower + upper.color.b * pctUpper) |
|||
}); |
|||
return color.toRgbString(); |
|||
} |
|||
} |
|||
|
|||
} |
|||
|
|||
this.gauge.canvas.customAttributes.pki = function(value, min, max, w, h, dx, dy, gws, donut, reverse) { // eslint-disable-line no-unused-vars
|
|||
var alpha, Rm, Ro, Ri, Cx, Cy, Xm, Ym, Xo, Yo, path; |
|||
|
|||
if (tbGauge.localSettings.neonGlowBrightness && !isFirefox |
|||
&& tbGauge.floodColorElement1 && tbGauge.floodColorElement2) { |
|||
var progress = (value - min) / (max - min); |
|||
var resultColor = getColor(value, progress); |
|||
var brightenColor1 = tinycolor(resultColor).brighten(tbGauge.localSettings.neonGlowBrightness).toRgbString(); |
|||
var brightenColor2 = resultColor; |
|||
tbGauge.floodColorElement1.setAttribute('flood-color', brightenColor1); |
|||
tbGauge.floodColorElement2.setAttribute('flood-color', brightenColor2); |
|||
} |
|||
|
|||
var gaugeType = tbGauge.localSettings.gaugeType; |
|||
|
|||
if (gaugeType === 'donut') { |
|||
alpha = (1 - 2 * (value - min) / (max - min)) * Math.PI; |
|||
Ro = w / 2 - w / 7; |
|||
Ri = Ro - w / 6.666666666666667 * gws; |
|||
Rm = Ri + (Ro - Ri)/2; |
|||
|
|||
Cx = w / 2 + dx; |
|||
Cy = h / 1.95 + dy; |
|||
|
|||
Xm = w / 2 + dx + Rm * Math.cos(alpha); |
|||
Ym = h - (h - Cy) - Rm * Math.sin(alpha); |
|||
|
|||
path = "M" + (Cx - Rm) + "," + Cy + " "; |
|||
if ((value - min) > ((max - min) / 2)) { |
|||
path += "A" + Rm + "," + Rm + " 0 0 1 " + (Cx + Rm) + "," + Cy + " "; |
|||
path += "A" + Rm + "," + Rm + " 0 0 1 " + Xm + "," + Ym + " "; |
|||
} else { |
|||
path += "A" + Rm + "," + Rm + " 0 0 1 " + Xm + "," + Ym + " "; |
|||
} |
|||
return { |
|||
path: path |
|||
}; |
|||
|
|||
} else if (gaugeType === 'arc') { |
|||
alpha = (1 - (value - min) / (max - min)) * Math.PI; |
|||
Ro = w / 2 - w / 10; |
|||
Ri = Ro - w / 6.666666666666667 * gws; |
|||
Rm = Ri + (Ro - Ri)/2; |
|||
|
|||
Cx = w / 2 + dx; |
|||
Cy = h / 1.25 + dy; |
|||
|
|||
Xm = w / 2 + dx + Rm * Math.cos(alpha); |
|||
Ym = h - (h - Cy) - Rm * Math.sin(alpha); |
|||
|
|||
path = "M" + (Cx - Rm) + "," + Cy + " "; |
|||
path += "A" + Rm + "," + Rm + " 0 0 1 " + Xm + "," + Ym + " "; |
|||
|
|||
return { |
|||
path: path |
|||
}; |
|||
} else if (gaugeType === 'horizontalBar') { |
|||
Cx = tbGauge.gauge.params.barLeft; |
|||
Cy = tbGauge.gauge.params.barTop + tbGauge.gauge.params.strokeWidth/2; |
|||
Ro = (tbGauge.gauge.params.barRight - tbGauge.gauge.params.barLeft)/2; |
|||
alpha = (value - min) / (max - min); |
|||
Xo = Cx + 2 * Ro * alpha; |
|||
path = "M" + Cx + "," + Cy + " "; |
|||
path += "H" + " " + Xo; |
|||
return { |
|||
path: path |
|||
}; |
|||
} else if (gaugeType === 'verticalBar') { |
|||
Cx = w / 2 + dx; |
|||
Cy = tbGauge.gauge.params.barBottom; |
|||
Ro = (tbGauge.gauge.params.barBottom - tbGauge.gauge.params.barTop)/2; |
|||
alpha = (value - min) / (max - min); |
|||
Yo = Cy - 2 * Ro * alpha; |
|||
path = "M" + Cx + "," + Cy + " "; |
|||
path += "V" + " " + Yo; |
|||
return { |
|||
path: path |
|||
}; |
|||
} |
|||
}; |
|||
|
|||
var gaugeAttrs = { |
|||
"stroke": this.gauge.gauge.attrs.fill, |
|||
"fill": 'rgba(0,0,0,0)', |
|||
pki: [ this.gauge.config.max, |
|||
this.gauge.config.min, |
|||
this.gauge.config.max, |
|||
gParams.widgetW, |
|||
gParams.widgetH, |
|||
gParams.dx, |
|||
gParams.dy, |
|||
this.gauge.config.gaugeWidthScale, |
|||
this.gauge.config.donut, |
|||
this.gauge.config.reverse |
|||
] |
|||
}; |
|||
gaugeAttrs['stroke-width'] = gParams.strokeWidth; |
|||
|
|||
|
|||
var gaugeLevelAttrs = { |
|||
"stroke": this.gauge.level.attrs.fill, |
|||
"fill": 'rgba(0,0,0,0)' |
|||
}; |
|||
gaugeLevelAttrs['stroke-width'] = gParams.strokeWidth; |
|||
if (this.localSettings.roundedLineCap) { |
|||
gaugeAttrs['stroke-linecap'] = 'round'; |
|||
gaugeLevelAttrs['stroke-linecap'] = 'round'; |
|||
} |
|||
|
|||
this.gauge.gauge.attr(gaugeAttrs); |
|||
this.gauge.level.attr(gaugeLevelAttrs); |
|||
|
|||
this.gauge.level.animate = function(attrs, refreshAnimationTime, refreshAnimationType) { |
|||
if (attrs.fill) { |
|||
attrs.stroke = attrs.fill; |
|||
attrs.fill = 'rgba(0,0,0,0)'; |
|||
} |
|||
return Raphael.el.animate.call(tbGauge.gauge.level, attrs, refreshAnimationTime, refreshAnimationType); |
|||
} |
|||
|
|||
function neonShadow(color) { |
|||
var brightenColor = tinycolor(color).brighten(tbGauge.localSettings.neonGlowBrightness); |
|||
return '0 0 10px '+brightenColor+','+ |
|||
'0 0 20px '+brightenColor+','+ |
|||
'0 0 30px '+brightenColor+','+ |
|||
'0 0 40px '+ color +','+ |
|||
'0 0 70px '+ color +','+ |
|||
'0 0 80px '+ color +','+ |
|||
'0 0 100px '+ color +','+ |
|||
'0 0 150px '+ color; |
|||
} |
|||
|
|||
if (this.localSettings.neonGlowBrightness) { |
|||
titleTextElement.css('textShadow', neonShadow(this.localSettings.titleFont.origColor)); |
|||
valueTextElement.css('textShadow', neonShadow(this.localSettings.valueFont.origColor)); |
|||
labelTextElement.css('textShadow', neonShadow(this.localSettings.labelFont.origColor)); |
|||
minValTextElement.css('textShadow', neonShadow(this.localSettings.minMaxFont.origColor)); |
|||
maxValTextElement.css('textShadow', neonShadow(this.localSettings.minMaxFont.origColor)); |
|||
} |
|||
|
|||
if (this.localSettings.neonGlowBrightness && !isFirefox) { |
|||
var filterX = (gParams.viewport.x / gParams.viewport.width)*100 + '%'; |
|||
var filterY = (gParams.viewport.y / gParams.viewport.height)*100 + '%'; |
|||
var svgBackFilterId = 'backBlurFilter' + Math.random(); |
|||
var svgBackFilter = document.createElementNS("http://www.w3.org/2000/svg", "filter"); // eslint-disable-line no-undef, angular/document-service
|
|||
svgBackFilter.setAttribute('id', svgBackFilterId); |
|||
svgBackFilter.setAttribute('filterUnits', 'userSpaceOnUse'); |
|||
svgBackFilter.setAttribute('x', filterX); |
|||
svgBackFilter.setAttribute('y', filterY); |
|||
svgBackFilter.setAttribute('width', '100%'); |
|||
svgBackFilter.setAttribute('height', '100%'); |
|||
svgBackFilter.innerHTML = |
|||
'<feComponentTransfer>'+ |
|||
'<feFuncR type="linear" slope="1.5"/>'+ |
|||
'<feFuncG type="linear" slope="1.5"/>'+ |
|||
'<feFuncB type="linear" slope="1.5"/>'+ |
|||
'</feComponentTransfer>'+ |
|||
'<feGaussianBlur stdDeviation="3" result="coloredBlur"></feGaussianBlur>'+ |
|||
'<feMerge>'+ |
|||
'<feMergeNode in="coloredBlur"/>'+ |
|||
'<feMergeNode in="SourceGraphic"/>'+ |
|||
'</feMerge>'; |
|||
gaugeBackElement.attr('filter', 'url(#'+svgBackFilterId+')'); |
|||
|
|||
var svgFillFilterId = 'fillBlurFilter' + Math.random(); |
|||
var svgFillFilter = document.createElementNS("http://www.w3.org/2000/svg", "filter"); // eslint-disable-line no-undef, angular/document-service
|
|||
svgFillFilter.setAttribute('id', svgFillFilterId); |
|||
svgFillFilter.setAttribute('filterUnits', 'userSpaceOnUse'); |
|||
svgFillFilter.setAttribute('x', filterX); |
|||
svgFillFilter.setAttribute('y', filterY); |
|||
svgFillFilter.setAttribute('width', '100%'); |
|||
svgFillFilter.setAttribute('height', '100%'); |
|||
|
|||
var brightenColor1 = tinycolor(this.localSettings.origLevelColors[0]).brighten(this.localSettings.neonGlowBrightness).toRgbString(); |
|||
var brightenColor2 = tinycolor(this.localSettings.origLevelColors[0]).toRgbString(); |
|||
svgFillFilter.innerHTML = |
|||
'<feFlood flood-color="'+brightenColor1+'" result="flood1" />'+ |
|||
'<feComposite in="flood1" in2="SourceGraphic" operator="in" result="floodShape" />'+ |
|||
'<feGaussianBlur in="floodShape" stdDeviation="3" result="blur" />'+ |
|||
'<feFlood flood-color="'+brightenColor2+'" result="flood2" />'+ |
|||
'<feComposite in="flood2" in2="SourceGraphic" operator="in" result="floodShape2" />'+ |
|||
'<feGaussianBlur in="floodShape2" stdDeviation="12" result="blur2" />'+ |
|||
'<feMerge result="blurs">'+ |
|||
' <feMergeNode in="blur2"/>'+ |
|||
' <feMergeNode in="blur2"/>'+ |
|||
' <feMergeNode in="blur"/>'+ |
|||
' <feMergeNode in="blur"/>'+ |
|||
' <feMergeNode in="SourceGraphic"/>'+ |
|||
'</feMerge>'; |
|||
this.floodColorElement1 = $('feFlood:nth-of-type(1)', svgFillFilter)[0]; |
|||
this.floodColorElement2 = $('feFlood:nth-of-type(2)', svgFillFilter)[0]; |
|||
gaugeLevelElement.attr('filter', 'url(#'+svgFillFilterId+')'); |
|||
|
|||
var svgDefsElement = $('svg > defs', containerElement); |
|||
svgDefsElement[0].appendChild(svgBackFilter); |
|||
svgDefsElement[0].appendChild(svgFillFilter); |
|||
} else { |
|||
gaugeBackElement.attr('filter', ''); |
|||
gaugeLevelElement.attr('filter', ''); |
|||
} |
|||
} |
|||
|
|||
redraw(data) { |
|||
if (data.length > 0) { |
|||
var cellData = data[0]; |
|||
if (cellData.data.length > 0) { |
|||
var tvPair = cellData.data[cellData.data.length - |
|||
1]; |
|||
var value = tvPair[1]; |
|||
if (this.gauge.config.value !== value) { |
|||
this.gauge.refresh(value); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
/* eslint-enable angular/angularelement */ |
|||
@ -0,0 +1,472 @@ |
|||
/* |
|||
* 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 $ from 'jquery'; |
|||
import tinycolor from 'tinycolor2'; |
|||
import moment from 'moment'; |
|||
import 'flot/lib/jquery.colorhelpers'; |
|||
import 'flot/src/jquery.flot'; |
|||
import 'flot/src/plugins/jquery.flot.time'; |
|||
import 'flot/src/plugins/jquery.flot.selection'; |
|||
import 'flot/src/plugins/jquery.flot.pie'; |
|||
|
|||
/* eslint-disable angular/angularelement */ |
|||
export default class TbFlot { |
|||
constructor(ctx, chartType) { |
|||
|
|||
this.ctx = ctx; |
|||
this.chartType = chartType || 'line'; |
|||
|
|||
var colors = []; |
|||
for (var i in ctx.data) { |
|||
var series = ctx.data[i]; |
|||
series.label = series.dataKey.label; |
|||
colors.push(series.dataKey.color); |
|||
var keySettings = series.dataKey.settings; |
|||
|
|||
series.lines = { |
|||
fill: keySettings.fillLines || false, |
|||
show: keySettings.showLines || true |
|||
}; |
|||
|
|||
series.points = { |
|||
show: false, |
|||
radius: 8 |
|||
}; |
|||
if (keySettings.showPoints === true) { |
|||
series.points.show = true; |
|||
series.points.lineWidth = 5; |
|||
series.points.radius = 3; |
|||
} |
|||
|
|||
var lineColor = tinycolor(series.dataKey.color); |
|||
lineColor.setAlpha(.75); |
|||
|
|||
series.highlightColor = lineColor.toRgbString(); |
|||
|
|||
} |
|||
|
|||
var tbFlot = this; |
|||
|
|||
ctx.tooltip = $('#flot-series-tooltip'); |
|||
if (ctx.tooltip.length === 0) { |
|||
ctx.tooltip = $("<div id=flot-series-tooltip' class='flot-mouse-value'></div>"); |
|||
ctx.tooltip.css({ |
|||
fontSize: "12px", |
|||
fontFamily: "Roboto", |
|||
lineHeight: "24px", |
|||
opacity: "1", |
|||
backgroundColor: "rgba(0,0,0,0.7)", |
|||
color: "#fff", |
|||
position: "absolute", |
|||
display: "none", |
|||
zIndex: "100", |
|||
padding: "2px 8px", |
|||
borderRadius: "4px" |
|||
}).appendTo("body"); |
|||
} |
|||
|
|||
ctx.tooltipFormatter = function(item) { |
|||
var label = item.series.label; |
|||
var color = item.series.color; |
|||
var content = ''; |
|||
if (tbFlot.chartType === 'line') { |
|||
var timestamp = parseInt(item.datapoint[0]); |
|||
var date = moment(timestamp).format('YYYY-MM-DD HH:mm:ss'); |
|||
content += '<b>' + date + '</b></br>'; |
|||
} |
|||
var lineSpan = $('<span></span>'); |
|||
lineSpan.css({ |
|||
backgroundColor: color, |
|||
width: "20px", |
|||
height: "3px", |
|||
display: "inline-block", |
|||
verticalAlign: "middle", |
|||
marginRight: "5px" |
|||
}); |
|||
content += lineSpan.prop('outerHTML'); |
|||
|
|||
var labelSpan = $('<span>' + label + ':</span>'); |
|||
labelSpan.css({ |
|||
marginRight: "10px" |
|||
}); |
|||
content += labelSpan.prop('outerHTML'); |
|||
var value = tbFlot.chartType === 'line' ? item.datapoint[1] : item.datapoint[1][0][1]; |
|||
content += ' <b>' + value.toFixed(ctx.trackDecimals); |
|||
if (settings.units) { |
|||
content += ' ' + settings.units; |
|||
} |
|||
if (tbFlot.chartType === 'pie') { |
|||
content += ' (' + Math.round(item.series.percent) + ' %)'; |
|||
} |
|||
content += '</b>'; |
|||
return content; |
|||
}; |
|||
|
|||
var settings = ctx.settings; |
|||
ctx.trackDecimals = angular.isDefined(settings.decimals) ? settings.decimals : 1; |
|||
|
|||
var font = { |
|||
color: settings.fontColor || "#545454", |
|||
size: settings.fontSize || 10, |
|||
family: "Roboto" |
|||
}; |
|||
|
|||
var options = { |
|||
colors: colors, |
|||
title: null, |
|||
subtitle: null, |
|||
shadowSize: settings.shadowSize || 4, |
|||
HtmlText: false, |
|||
grid: { |
|||
hoverable: true, |
|||
mouseActiveRadius: 10, |
|||
autoHighlight: true |
|||
}, |
|||
selection : { mode : ctx.isMobile ? null : 'x' }, |
|||
legend : { |
|||
show: true, |
|||
position : 'nw', |
|||
labelBoxBorderColor: '#CCCCCC', |
|||
backgroundColor : '#F0F0F0', |
|||
backgroundOpacity: 0.85, |
|||
font: angular.copy(font) |
|||
} |
|||
}; |
|||
if (settings.legend) { |
|||
options.legend.show = settings.legend.show !== false; |
|||
options.legend.position = settings.legend.position || 'nw'; |
|||
options.legend.labelBoxBorderColor = settings.legend.labelBoxBorderColor || null; |
|||
options.legend.backgroundColor = settings.legend.backgroundColor || null; |
|||
options.legend.backgroundOpacity = angular.isDefined(settings.legend.backgroundOpacity) ? |
|||
settings.legend.backgroundOpacity : 0.85; |
|||
} |
|||
|
|||
if (this.chartType === 'line') { |
|||
options.xaxis = { |
|||
mode: 'time', |
|||
timezone: 'browser', |
|||
font: angular.copy(font), |
|||
labelFont: angular.copy(font) |
|||
}; |
|||
options.yaxis = { |
|||
font: angular.copy(font), |
|||
labelFont: angular.copy(font) |
|||
}; |
|||
if (settings.xaxis) { |
|||
if (settings.xaxis.showLabels === false) { |
|||
options.xaxis.tickFormatter = function() { |
|||
return ''; |
|||
}; |
|||
} |
|||
options.xaxis.font.color = settings.xaxis.color || options.xaxis.font.color; |
|||
options.xaxis.label = settings.xaxis.title || null; |
|||
options.xaxis.labelFont.color = options.xaxis.font.color; |
|||
options.xaxis.labelFont.size = options.xaxis.font.size+2; |
|||
options.xaxis.labelFont.weight = "bold"; |
|||
} |
|||
if (settings.yaxis) { |
|||
if (settings.yaxis.showLabels === false) { |
|||
options.yaxis.tickFormatter = function() { |
|||
return ''; |
|||
}; |
|||
} |
|||
options.yaxis.font.color = settings.yaxis.color || options.yaxis.font.color; |
|||
options.yaxis.label = settings.yaxis.title || null; |
|||
options.yaxis.labelFont.color = options.yaxis.font.color; |
|||
options.yaxis.labelFont.size = options.yaxis.font.size+2; |
|||
options.yaxis.labelFont.weight = "bold"; |
|||
} |
|||
|
|||
options.grid.borderWidth = 1; |
|||
options.grid.color = settings.fontColor || "#545454"; |
|||
|
|||
if (settings.grid) { |
|||
options.grid.color = settings.grid.color || "#545454"; |
|||
options.grid.backgroundColor = settings.grid.backgroundColor || null; |
|||
options.grid.tickColor = settings.grid.tickColor || "#DDDDDD"; |
|||
options.grid.borderWidth = angular.isDefined(settings.grid.outlineWidth) ? |
|||
settings.grid.outlineWidth : 1; |
|||
if (settings.grid.verticalLines === false) { |
|||
options.xaxis.tickLength = 0; |
|||
} |
|||
if (settings.grid.horizontalLines === false) { |
|||
options.yaxis.tickLength = 0; |
|||
} |
|||
} |
|||
|
|||
options.xaxis.min = ctx.timeWindow.minTime; |
|||
options.xaxis.max = ctx.timeWindow.maxTime; |
|||
} else if (this.chartType === 'pie') { |
|||
options.series = { |
|||
pie: { |
|||
show: true, |
|||
label: { |
|||
show: settings.showLabels === true |
|||
}, |
|||
radius: settings.radius || 1, |
|||
innerRadius: settings.innerRadius || 0, |
|||
stroke: { |
|||
color: '#fff', |
|||
width: 0 |
|||
}, |
|||
tilt: settings.tilt || 1, |
|||
shadow: { |
|||
left: 5, |
|||
top: 15, |
|||
alpha: 0.02 |
|||
} |
|||
} |
|||
} |
|||
if (settings.stroke) { |
|||
options.series.pie.stroke.color = settings.stroke.color || '#fff'; |
|||
options.series.pie.stroke.width = settings.stroke.width || 0; |
|||
} |
|||
|
|||
if (options.series.pie.label.show) { |
|||
options.series.pie.label.formatter = function (label, series) { |
|||
return "<div class='pie-label'>" + label + "<br/>" + Math.round(series.percent) + "%</div>"; |
|||
} |
|||
options.series.pie.label.radius = 3/4; |
|||
options.series.pie.label.background = { |
|||
opacity: 0.8 |
|||
}; |
|||
} |
|||
} |
|||
|
|||
//Experimental
|
|||
this.ctx.animatedPie = settings.animatedPie === true; |
|||
|
|||
this.options = options; |
|||
|
|||
if (this.chartType === 'pie' && this.ctx.animatedPie) { |
|||
this.ctx.pieDataAnimationDuration = 250; |
|||
this.ctx.pieData = angular.copy(this.ctx.data); |
|||
this.ctx.pieRenderedData = []; |
|||
this.ctx.pieTargetData = []; |
|||
for (i in this.ctx.data) { |
|||
this.ctx.pieTargetData[i] = (this.ctx.data[i].data && this.ctx.data[i].data[0]) |
|||
? this.ctx.data[i].data[0][1] : 0; |
|||
} |
|||
this.pieDataRendered(); |
|||
this.ctx.plot = $.plot(this.ctx.$container, this.ctx.pieData, this.options); |
|||
} else { |
|||
this.ctx.plot = $.plot(this.ctx.$container, this.ctx.data, this.options); |
|||
} |
|||
this.checkMouseEvents(); |
|||
} |
|||
|
|||
update() { |
|||
if (!this.isMouseInteraction) { |
|||
if (this.chartType === 'line') { |
|||
this.ctx.plot.getOptions().xaxes[0].min = this.ctx.timeWindow.minTime; |
|||
this.ctx.plot.getOptions().xaxes[0].max = this.ctx.timeWindow.maxTime; |
|||
} |
|||
if (this.chartType === 'line') { |
|||
this.ctx.plot.setData(this.ctx.data); |
|||
this.ctx.plot.setupGrid(); |
|||
this.ctx.plot.draw(); |
|||
} else if (this.chartType === 'pie') { |
|||
if (this.ctx.animatedPie) { |
|||
this.nextPieDataAnimation(true); |
|||
} else { |
|||
this.ctx.plot.setData(this.ctx.data); |
|||
this.ctx.plot.draw(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
pieDataRendered() { |
|||
for (var i in this.ctx.pieTargetData) { |
|||
var value = this.ctx.pieTargetData[i] ? this.ctx.pieTargetData[i] : 0; |
|||
this.ctx.pieRenderedData[i] = value; |
|||
if (!this.ctx.pieData[i].data[0]) { |
|||
this.ctx.pieData[i].data[0] = [0,0]; |
|||
} |
|||
this.ctx.pieData[i].data[0][1] = value; |
|||
} |
|||
} |
|||
|
|||
nextPieDataAnimation(start) { |
|||
if (start) { |
|||
this.finishPieDataAnimation(); |
|||
this.ctx.pieAnimationStartTime = this.ctx.pieAnimationLastTime = Date.now(); |
|||
for (var i in this.ctx.data) { |
|||
this.ctx.pieTargetData[i] = (this.ctx.data[i].data && this.ctx.data[i].data[0]) |
|||
? this.ctx.data[i].data[0][1] : 0; |
|||
} |
|||
} |
|||
if (this.ctx.pieAnimationCaf) { |
|||
this.ctx.pieAnimationCaf(); |
|||
this.ctx.pieAnimationCaf = null; |
|||
} |
|||
var self = this; |
|||
this.ctx.pieAnimationCaf = this.ctx.$scope.tbRaf( |
|||
function () { |
|||
self.onPieDataAnimation(); |
|||
} |
|||
); |
|||
} |
|||
|
|||
onPieDataAnimation() { |
|||
var time = Date.now(); |
|||
var elapsed = time - this.ctx.pieAnimationLastTime;//this.ctx.pieAnimationStartTime;
|
|||
var progress = (time - this.ctx.pieAnimationStartTime) / this.ctx.pieDataAnimationDuration; |
|||
if (progress >= 1) { |
|||
this.finishPieDataAnimation(); |
|||
} else { |
|||
if (elapsed >= 40) { |
|||
for (var i in this.ctx.pieTargetData) { |
|||
var prevValue = this.ctx.pieRenderedData[i]; |
|||
var targetValue = this.ctx.pieTargetData[i]; |
|||
var value = prevValue + (targetValue - prevValue) * progress; |
|||
if (!this.ctx.pieData[i].data[0]) { |
|||
this.ctx.pieData[i].data[0] = [0,0]; |
|||
} |
|||
this.ctx.pieData[i].data[0][1] = value; |
|||
} |
|||
this.ctx.plot.setData(this.ctx.pieData); |
|||
this.ctx.plot.draw(); |
|||
this.ctx.pieAnimationLastTime = time; |
|||
} |
|||
this.nextPieDataAnimation(false); |
|||
} |
|||
} |
|||
|
|||
finishPieDataAnimation() { |
|||
this.pieDataRendered(); |
|||
this.ctx.plot.setData(this.ctx.pieData); |
|||
this.ctx.plot.draw(); |
|||
} |
|||
|
|||
resize() { |
|||
this.ctx.plot.resize(); |
|||
if (this.chartType === 'line') { |
|||
this.ctx.plot.setupGrid(); |
|||
} |
|||
this.ctx.plot.draw(); |
|||
} |
|||
|
|||
checkMouseEvents() { |
|||
if (this.ctx.isMobile || this.ctx.isEdit) { |
|||
this.disableMouseEvents(); |
|||
} else if (!this.ctx.isEdit) { |
|||
this.enableMouseEvents(); |
|||
} |
|||
} |
|||
|
|||
enableMouseEvents() { |
|||
this.ctx.$container.css('pointer-events',''); |
|||
this.ctx.$container.addClass('mouse-events'); |
|||
this.options.selection = { mode : 'x' }; |
|||
|
|||
var tbFlot = this; |
|||
|
|||
if (!this.flotHoverHandler) { |
|||
this.flotHoverHandler = function (event, pos, item) { |
|||
if (item) { |
|||
var pageX = item.pageX || pos.pageX; |
|||
var pageY = item.pageY || pos.pageY; |
|||
tbFlot.ctx.tooltip.html(tbFlot.ctx.tooltipFormatter(item)) |
|||
.css({top: pageY+5, left: 0}) |
|||
.fadeIn(200); |
|||
var windowWidth = $( window ).width(); //eslint-disable-line
|
|||
var tooltipWidth = tbFlot.ctx.tooltip.width(); |
|||
var left = pageX+5; |
|||
if (windowWidth - pageX < tooltipWidth + 50) { |
|||
left = pageX - tooltipWidth - 10; |
|||
} |
|||
tbFlot.ctx.tooltip.css({ |
|||
left: left |
|||
}); |
|||
} else { |
|||
tbFlot.ctx.tooltip.stop(true); |
|||
tbFlot.ctx.tooltip.hide(); |
|||
} |
|||
}; |
|||
this.ctx.$container.bind('plothover', this.flotHoverHandler); |
|||
} |
|||
|
|||
if (!this.flotSelectHandler) { |
|||
this.flotSelectHandler = function (event, ranges) { |
|||
tbFlot.ctx.plot.clearSelection(); |
|||
tbFlot.ctx.timewindowFunctions.onUpdateTimewindow(ranges.xaxis.from, ranges.xaxis.to); |
|||
}; |
|||
this.ctx.$container.bind('plotselected', this.flotSelectHandler); |
|||
} |
|||
if (!this.dblclickHandler) { |
|||
this.dblclickHandler = function () { |
|||
tbFlot.ctx.timewindowFunctions.onResetTimewindow(); |
|||
}; |
|||
this.ctx.$container.bind('dblclick', this.dblclickHandler); |
|||
} |
|||
if (!this.mousedownHandler) { |
|||
this.mousedownHandler = function () { |
|||
tbFlot.isMouseInteraction = true; |
|||
}; |
|||
this.ctx.$container.bind('mousedown', this.mousedownHandler); |
|||
} |
|||
if (!this.mouseupHandler) { |
|||
this.mouseupHandler = function () { |
|||
tbFlot.isMouseInteraction = false; |
|||
}; |
|||
this.ctx.$container.bind('mouseup', this.mouseupHandler); |
|||
} |
|||
if (!this.mouseleaveHandler) { |
|||
this.mouseleaveHandler = function () { |
|||
tbFlot.ctx.tooltip.stop(true); |
|||
tbFlot.ctx.tooltip.hide(); |
|||
tbFlot.isMouseInteraction = false; |
|||
}; |
|||
this.ctx.$container.bind('mouseleave', this.mouseleaveHandler); |
|||
} |
|||
} |
|||
|
|||
disableMouseEvents() { |
|||
this.ctx.$container.css('pointer-events','none'); |
|||
this.ctx.$container.removeClass('mouse-events'); |
|||
this.options.selection = { mode : null }; |
|||
|
|||
if (this.flotHoverHandler) { |
|||
this.ctx.$container.unbind('plothover', this.flotHoverHandler); |
|||
this.flotHoverHandler = null; |
|||
} |
|||
|
|||
if (this.flotSelectHandler) { |
|||
this.ctx.$container.unbind('plotselected', this.flotSelectHandler); |
|||
this.flotSelectHandler = null; |
|||
} |
|||
if (this.dblclickHandler) { |
|||
this.ctx.$container.unbind('dblclick', this.dblclickHandler); |
|||
this.dblclickHandler = null; |
|||
} |
|||
if (this.mousedownHandler) { |
|||
this.ctx.$container.unbind('mousedown', this.mousedownHandler); |
|||
this.mousedownHandler = null; |
|||
} |
|||
if (this.mouseupHandler) { |
|||
this.ctx.$container.unbind('mouseup', this.mouseupHandler); |
|||
this.mouseupHandler = null; |
|||
} |
|||
if (this.mouseleaveHandler) { |
|||
this.ctx.$container.unbind('mouseleave', this.mouseleaveHandler); |
|||
this.mouseleaveHandler = null; |
|||
} |
|||
} |
|||
} |
|||
|
|||
/* eslint-enable angular/angularelement */ |
|||
Binary file not shown.
@ -1,684 +0,0 @@ |
|||
{ |
|||
"access": { |
|||
"unauthorized": "Unauthorized", |
|||
"unauthorized-access": "Unauthorized Access", |
|||
"unauthorized-access-text": "You should sign in to have access to this resource!", |
|||
"access-forbidden": "Access Forbidden", |
|||
"access-forbidden-text": "You haven't access rights to this location!<br/>Try to sign in with different user if you still wish to gain access to this location.", |
|||
"refresh-token-expired": "Session has expired", |
|||
"refresh-token-failed": "Unable to refresh session" |
|||
}, |
|||
"action": { |
|||
"activate": "Activate", |
|||
"suspend": "Suspend", |
|||
"save": "Save", |
|||
"saveAs": "Save as", |
|||
"cancel": "Cancel", |
|||
"ok": "OK", |
|||
"delete": "Delete", |
|||
"add": "Add", |
|||
"yes": "Yes", |
|||
"no": "No", |
|||
"update": "Update", |
|||
"remove": "Remove", |
|||
"search": "Search", |
|||
"assign": "Assign", |
|||
"unassign": "Unassign", |
|||
"apply": "Apply", |
|||
"apply-changes": "Apply changes", |
|||
"edit-mode": "Edit mode", |
|||
"enter-edit-mode": "Enter edit mode", |
|||
"decline-changes": "Decline changes", |
|||
"close": "Close", |
|||
"back": "Back", |
|||
"run": "Run", |
|||
"sign-in": "Sign in!", |
|||
"edit": "Edit", |
|||
"view": "View", |
|||
"create": "Create", |
|||
"drag": "Drag", |
|||
"refresh": "Refresh", |
|||
"undo": "Undo", |
|||
"copy": "Copy", |
|||
"paste": "Paste", |
|||
"import": "Import", |
|||
"export": "Export" |
|||
}, |
|||
"admin": { |
|||
"general": "General", |
|||
"general-settings": "General Settings", |
|||
"outgoing-mail": "Outgoing Mail", |
|||
"outgoing-mail-settings": "Outgoing Mail Settings", |
|||
"system-settings": "System Settings", |
|||
"test-mail-sent": "Test mail was successfully sent!", |
|||
"base-url": "Base URL", |
|||
"base-url-required": "Base URL is required.", |
|||
"mail-from": "Mail From", |
|||
"mail-from-required": "Mail From is required.", |
|||
"smtp-protocol": "SMTP protocol", |
|||
"smtp-host": "SMTP host", |
|||
"smtp-host-required": "SMTP host is required.", |
|||
"smtp-port": "SMTP port", |
|||
"smtp-port-required": "You must supply a smtp port.", |
|||
"smtp-port-invalid": "That doesn't look like a valid smtp port.", |
|||
"timeout-msec": "Timeout (msec)", |
|||
"timeout-required": "Timeout is required.", |
|||
"timeout-invalid": "That doesn't look like a valid timeout.", |
|||
"enable-tls": "Enable TLS", |
|||
"send-test-mail": "Send test mail" |
|||
}, |
|||
"attribute": { |
|||
"attributes": "Attributes", |
|||
"latest-telemetry": "Latest telemetry", |
|||
"attributes-scope": "Device attributes scope", |
|||
"scope-latest-telemetry": "Latest telemetry", |
|||
"scope-client": "Client attributes", |
|||
"scope-server": "Server attributes", |
|||
"scope-shared": "Shared attributes", |
|||
"add": "Add attribute", |
|||
"key": "Key", |
|||
"key-required": "Attribute key is required.", |
|||
"value": "Value", |
|||
"value-required": "Attribute value is required.", |
|||
"delete-attributes-title": "Are you sure you want to delete { count, select, 1 {1 attribute} other {# attributes} }?", |
|||
"delete-attributes-text": "Be careful, after the confirmation all selected attributes will be removed.", |
|||
"delete-attributes": "Delete attributes", |
|||
"enter-attribute-value": "Enter attribute value", |
|||
"show-on-widget": "Show on widget", |
|||
"widget-mode": "Widget mode", |
|||
"next-widget": "Next widget", |
|||
"prev-widget": "Previous widget", |
|||
"add-to-dashboard": "Add to dashboard", |
|||
"add-widget-to-dashboard": "Add widget to dashboard", |
|||
"selected-attributes": "{ count, select, 1 {1 attribute} other {# attributes} } selected", |
|||
"selected-telemetry": "{ count, select, 1 {1 telemetry unit} other {# telemetry units} } selected" |
|||
}, |
|||
"confirm-on-exit": { |
|||
"message": "You have unsaved changes. Are you sure you want to leave this page?", |
|||
"html-message": "You have unsaved changes.<br/>Are you sure you want to leave this page?", |
|||
"title": "Unsaved changes" |
|||
}, |
|||
"contact": { |
|||
"country": "Country", |
|||
"city": "City", |
|||
"state": "State", |
|||
"postal-code": "Postal code", |
|||
"postal-code-invalid": "Only digits are allowed.", |
|||
"address": "Address", |
|||
"address2": "Address 2", |
|||
"phone": "Phone", |
|||
"email": "Email", |
|||
"no-address": "No address" |
|||
}, |
|||
"common": { |
|||
"username": "Username", |
|||
"password": "Password", |
|||
"enter-username": "Enter username", |
|||
"enter-password": "Enter password", |
|||
"enter-search": "Enter search" |
|||
}, |
|||
"customer": { |
|||
"customers": "Customers", |
|||
"management": "Customer management", |
|||
"dashboard": "Customer Dashboard", |
|||
"dashboards": "Customer Dashboards", |
|||
"devices": "Customer Devices", |
|||
"add": "Add Customer", |
|||
"delete": "Delete customer", |
|||
"manage-customer-users": "Manage customer users", |
|||
"manage-customer-devices": "Manage customer devices", |
|||
"manage-customer-dashboards": "Manage customer dashboards", |
|||
"add-customer-text": "Add new customer", |
|||
"no-customers-text": "No customers found", |
|||
"customer-details": "Customer details", |
|||
"delete-customer-title": "Are you sure you want to delete the customer '{{customerTitle}}'?", |
|||
"delete-customer-text": "Be careful, after the confirmation the customer and all related data will become unrecoverable.", |
|||
"delete-customers-title": "Are you sure you want to delete { count, select, 1 {1 customer} other {# customers} }?", |
|||
"delete-customers-action-title": "Delete { count, select, 1 {1 customer} other {# customers} }", |
|||
"delete-customers-text": "Be careful, after the confirmation all selected customers will be removed and all related data will become unrecoverable.", |
|||
"manage-users": "Manage users", |
|||
"manage-devices": "Manage devices", |
|||
"manage-dashboards": "Manage dashboards", |
|||
"title": "Title", |
|||
"title-required": "Title is required.", |
|||
"description": "Description" |
|||
}, |
|||
"datetime": { |
|||
"date-from": "Date from", |
|||
"time-from": "Time from", |
|||
"date-to": "Date to", |
|||
"time-to": "Time to" |
|||
}, |
|||
"dashboard": { |
|||
"dashboard": "Dashboard", |
|||
"dashboards": "Dashboards", |
|||
"management": "Dashboard management", |
|||
"view-dashboards": "View Dashboards", |
|||
"add": "Add Dashboard", |
|||
"assign-dashboard-to-customer": "Assign Dashboard(s) To Customer", |
|||
"assign-dashboard-to-customer-text": "Please select the dashboards to assign to the customer", |
|||
"assign-to-customer-text": "Please select the customer to assign the dashboard(s)", |
|||
"assign-to-customer": "Assign to customer", |
|||
"unassign-from-customer": "Unassign from customer", |
|||
"no-dashboards-text": "No dashboards found", |
|||
"no-widgets": "No widgets configured", |
|||
"add-widget": "Add new widget", |
|||
"title": "Title", |
|||
"select-widget-title": "Select widget", |
|||
"select-widget-subtitle": "List of available widget types", |
|||
"delete": "Delete dashboard", |
|||
"title": "Title", |
|||
"title-required": "Title is required.", |
|||
"description": "Description", |
|||
"details": "Details", |
|||
"dashboard-details": "Dashboard details", |
|||
"add-dashboard-text": "Add new dashboard", |
|||
"no-dashboards-text": "No dashboards found", |
|||
"assign-dashboards": "Assign dashboards", |
|||
"assign-new-dashboard": "Assign new dashboard", |
|||
"assign-dashboards-text": "Assign { count, select, 1 {1 dashboard} other {# dashboards} } to customer", |
|||
"delete-dashboards": "Delete dashboards", |
|||
"unassign-dashboards": "Unassign dashboards", |
|||
"unassign-dashboards-action-title": "Unassign { count, select, 1 {1 dashboard} other {# dashboards} } from customer", |
|||
"delete-dashboard-title": "Are you sure you want to delete the dashboard '{{dashboardTitle}}'?", |
|||
"delete-dashboard-text": "Be careful, after the confirmation the dashboard and all related data will become unrecoverable.", |
|||
"delete-dashboards-title": "Are you sure you want to delete { count, select, 1 {1 dashboard} other {# dashboards} }?", |
|||
"delete-dashboards-action-title": "Delete { count, select, 1 {1 dashboard} other {# dashboards} }", |
|||
"delete-dashboards-text": "Be careful, after the confirmation all selected dashboards will be removed and all related data will become unrecoverable.", |
|||
"unassign-dashboard-title": "Are you sure you want to unassign the dashboard '{{dashboardTitle}}'?", |
|||
"unassign-dashboard-text": "After the confirmation the dashboard will be unassigned and won't be accessible by the customer.", |
|||
"unassign-dashboard": "Unassign dashboard", |
|||
"unassign-dashboards-title": "Are you sure you want to unassign { count, select, 1 {1 dashboard} other {# dashboards} }?", |
|||
"unassign-dashboards-text": "After the confirmation all selected dashboards will be unassigned and won't be accessible by the customer.", |
|||
"select-dashboard": "Select dashboard", |
|||
"no-dashboards-matching": "No dashboards matching '{{dashboard}}' were found.", |
|||
"dashboard-required": "Dashboard is required.", |
|||
"select-existing": "Select existing dashboard", |
|||
"create-new": "Create new dashboard", |
|||
"new-dashboard-title": "New dashboard title", |
|||
"open-dashboard": "Open dashboard", |
|||
"set-background": "Set background", |
|||
"background-color": "Background color", |
|||
"background-image": "Background image", |
|||
"no-image": "No image selected", |
|||
"drop-image": "Drop an image or click to select a file to upload.", |
|||
"settings": "Settings", |
|||
"columns-count": "Columns count", |
|||
"columns-count-required": "Columns count is required.", |
|||
"min-columns-count-message": "Only 10 minimum column count is allowed.", |
|||
"max-columns-count-message": "Only 1000 maximum column count is allowed.", |
|||
"widgets-margins": "Margin between widgets", |
|||
"horizontal-margin": "Horizontal margin", |
|||
"horizontal-margin-required": "Horizontal margin value is required.", |
|||
"min-horizontal-margin-message": "Only 0 is allowed as minimum horizontal margin value.", |
|||
"max-horizontal-margin-message": "Only 50 is allowed as maximum horizontal margin value.", |
|||
"vertical-margin": "Vertical margin", |
|||
"vertical-margin-required": "Vertical margin value is required.", |
|||
"min-vertical-margin-message": "Only 0 is allowed as minimum vertical margin value.", |
|||
"max-vertical-margin-message": "Only 50 is allowed as maximum vertical margin value.", |
|||
"display-title": "Display dashboard title", |
|||
"import": "Import dashboard", |
|||
"export": "Export dashboard", |
|||
"export-failed-error": "Unable to export dashboard: {error}", |
|||
"create-new-dashboard": "Create new dashboard", |
|||
"dashboard-file": "Dashboard file", |
|||
"invalid-dashboard-file-error": "Unable to import dashboard: Invalid dashboard data structure.", |
|||
"dashboard-import-missing-aliases-title": "Select missing devices for dashboard aliases", |
|||
"create-new-widget": "Create new widget", |
|||
"import-widget": "Import widget", |
|||
"widget-file": "Widget file", |
|||
"invalid-widget-file-error": "Unable to import widget: Invalid widget data structure.", |
|||
"widget-import-missing-aliases-title": "Select missing devices used by widget" |
|||
}, |
|||
"datakey": { |
|||
"settings": "Settings", |
|||
"advanced": "Advanced", |
|||
"label": "Label", |
|||
"color": "Color", |
|||
"data-generation-func": "Data generation function", |
|||
"use-data-post-processing-func": "Use data post-processing function", |
|||
"configuration": "Data key configuration", |
|||
"timeseries": "Timeseries", |
|||
"attributes": "Attributes", |
|||
"timeseries-required": "Device timeseries is required.", |
|||
"timeseries-or-attributes-required": "Device timeseries/attributes is required.", |
|||
"function-types": "Function types", |
|||
"function-types-required": "Function types is required." |
|||
}, |
|||
"datasource": { |
|||
"type": "Datasource type", |
|||
"add-datasource-prompt": "Please add datasource" |
|||
}, |
|||
"details": { |
|||
"edit-mode": "Edit mode", |
|||
"toggle-edit-mode": "Toggle edit mode" |
|||
}, |
|||
"device": { |
|||
"device": "Device", |
|||
"device-required": "Device is required.", |
|||
"devices": "Devices", |
|||
"management": "Device management", |
|||
"view-devices": "View Devices", |
|||
"device-alias": "Device alias", |
|||
"aliases": "Device aliases", |
|||
"no-alias-matching": "'{{alias}}' not found.", |
|||
"no-aliases-found": "No aliases found.", |
|||
"no-key-matching": "'{{key}}' not found.", |
|||
"no-keys-found": "No keys found.", |
|||
"create-new-alias": "Create a new one!", |
|||
"create-new-key": "Create a new one!", |
|||
"duplicate-alias-error": "Duplicate alias found '{{alias}}'.<br>Device aliases must be unique whithin the dashboard.", |
|||
"select-device-for-alias": "Select device for '{{alias}}' alias", |
|||
"no-devices-matching": "No devices matching '{{device}}' were found.", |
|||
"alias": "Alias", |
|||
"alias-required": "Device alias is required.", |
|||
"remove-alias": "Remove device alias", |
|||
"add-alias": "Add device alias", |
|||
"add": "Add Device", |
|||
"assign-to-customer": "Assign to customer", |
|||
"assign-device-to-customer": "Assign Device(s) To Customer", |
|||
"assign-device-to-customer-text": "Please select the devices to assign to the customer", |
|||
"no-devices-text": "No devices found", |
|||
"assign-to-customer-text": "Please select the customer to assign the device(s)", |
|||
"device-details": "Device details", |
|||
"add-device-text": "Add new device", |
|||
"credentials": "Credentials", |
|||
"manage-credentials": "Manage credentials", |
|||
"delete": "Delete device", |
|||
"assign-devices": "Assign devices", |
|||
"assign-devices-text": "Assign { count, select, 1 {1 device} other {# devices} } to customer", |
|||
"delete-devices": "Delete devices", |
|||
"unassign-from-customer": "Unassign from customer", |
|||
"unassign-devices": "Unassign devices", |
|||
"unassign-devices-action-title": "Unassign { count, select, 1 {1 device} other {# devices} } from customer", |
|||
"assign-new-device": "Assign new device", |
|||
"view-credentials": "View credentials", |
|||
"delete-device-title": "Are you sure you want to delete the device '{{deviceName}}'?", |
|||
"delete-device-text": "Be careful, after the confirmation the device and all related data will become unrecoverable.", |
|||
"delete-devices-title": "Are you sure you want to delete { count, select, 1 {1 device} other {# devices} }?", |
|||
"delete-devices-action-title": "Delete { count, select, 1 {1 device} other {# devices} }", |
|||
"delete-devices-text": "Be careful, after the confirmation all selected devices will be removed and all related data will become unrecoverable.", |
|||
"unassign-device-title": "Are you sure you want to unassign the device '{{deviceName}}'?", |
|||
"unassign-device-text": "After the confirmation the device will be unassigned and won't be accessible by the customer.", |
|||
"unassign-device": "Unassign device", |
|||
"unassign-devices-title": "Are you sure you want to unassign { count, select, 1 {1 device} other {# devices} }?", |
|||
"unassign-devices-text": "After the confirmation all selected devices will be unassigned and won't be accessible by the customer.", |
|||
"device-credentials": "Device Credentials", |
|||
"credentials-type": "Credentials type", |
|||
"access-token": "Access token", |
|||
"access-token-required": "Access token is required.", |
|||
"access-token-invalid": "Access token length must be from 1 to 20 characters.", |
|||
"rsa-key": "RSA public key", |
|||
"access-token-required": "RSA public key is required.", |
|||
"secret": "Secret", |
|||
"secret-required": "Secret is required.", |
|||
"name": "Name", |
|||
"name-required": "Name is required.", |
|||
"description": "Description", |
|||
"events": "Events", |
|||
"details": "Details", |
|||
"copyId": "Copy device Id", |
|||
"copyAccessToken": "Copy access token", |
|||
"idCopiedMessage": "Device Id has been copied to clipboard", |
|||
"accessTokenCopiedMessage": "Device access token has been copied to clipboard", |
|||
"assignedToCustomer": "Assigned to customer", |
|||
"unable-delete-device-alias-title": "Unable to delete device alias", |
|||
"unable-delete-device-alias-text": "Device alias '{{deviceAlias}}' can't be deleted as it used by the following widget(s):<br/>{{widgetsList}}", |
|||
"is-gateway": "Is gateway" |
|||
}, |
|||
"dialog": { |
|||
"close": "Close dialog" |
|||
}, |
|||
"error": { |
|||
"unable-to-connect": "Unable to connect to the server! Please check your internet connection.", |
|||
"unhandled-error-code": "Unhandled error code: {{errorCode}}", |
|||
"unknown-error": "Unknown error" |
|||
}, |
|||
"event": { |
|||
"event-type": "Event type", |
|||
"type-alarm": "Alarm", |
|||
"type-error": "Error", |
|||
"type-lc-event": "Lifecycle event", |
|||
"type-stats": "Statistics", |
|||
"no-events-prompt": "No events found", |
|||
"error": "Error", |
|||
"alarm": "Alarm", |
|||
"event-time": "Event time", |
|||
"server": "Server", |
|||
"body": "Body", |
|||
"method": "Method", |
|||
"event": "Event", |
|||
"status": "Status", |
|||
"success": "Success", |
|||
"failed": "Failed", |
|||
"messages-processed": "Messages processed", |
|||
"errors-occurred": "Errors occurred" |
|||
}, |
|||
"fullscreen": { |
|||
"expand": "Expand to fullscreen", |
|||
"exit": "Exit fullscreen", |
|||
"toggle": "Toggle fullscreen mode", |
|||
"fullscreen": "Fullscreen" |
|||
}, |
|||
"function": { |
|||
"function": "Function" |
|||
}, |
|||
"grid": { |
|||
"delete-item-title": "Are you sure you want to delete this item?", |
|||
"delete-item-text": "Be careful, after the confirmation this item and all related data will become unrecoverable.", |
|||
"delete-items-title": "Are you sure you want to delete { count, select, 1 {1 item} other {# items} }?", |
|||
"delete-items-action-title": "Delete { count, select, 1 {1 item} other {# items} }", |
|||
"delete-items-text": "Be careful, after the confirmation all selected items will be removed and all related data will become unrecoverable.", |
|||
"add-item-text": "Add new item", |
|||
"no-items-text": "No items found", |
|||
"item-details": "Item details", |
|||
"delete-item": "Delete Item", |
|||
"delete-items": "Delete Items", |
|||
"scroll-to-top": "Scroll to top" |
|||
}, |
|||
"help": { |
|||
"goto-help-page": "Go to help page" |
|||
}, |
|||
"home": { |
|||
"home": "Home", |
|||
"profile": "Profile", |
|||
"logout": "Logout", |
|||
"menu": "Menu", |
|||
"avatar": "Avatar", |
|||
"open-user-menu": "Open user menu" |
|||
}, |
|||
"import": { |
|||
"no-file": "No file selected", |
|||
"drop-file": "Drop a JSON file or click to select a file to upload." |
|||
}, |
|||
"item": { |
|||
"selected": "Selected" |
|||
}, |
|||
"js-func": { |
|||
"no-return-error": "Function must return value!", |
|||
"return-type-mismatch": "Function must return value of '{{type}}' type!" |
|||
}, |
|||
"login": { |
|||
"login": "Login", |
|||
"request-password-reset": "Request Password Reset", |
|||
"reset-password": "Reset Password", |
|||
"create-password": "Create Password", |
|||
"passwords-mismatch-error": "Entered passwords must be same!", |
|||
"password-again": "Password again", |
|||
"sign-in": "Please sign in", |
|||
"username": "Username (email)", |
|||
"remember-me": "Remember me", |
|||
"forgot-password": "Forgot Password?", |
|||
"login": "Login", |
|||
"password-reset": "Password reset", |
|||
"new-password": "New password", |
|||
"new-password-again": "New password again", |
|||
"password-link-sent-message": "Password reset link was successfully sent!", |
|||
"request-password-reset": "Request password reset", |
|||
"email": "Email" |
|||
}, |
|||
"plugin": { |
|||
"plugins": "Plugins", |
|||
"delete": "Delete plugin", |
|||
"activate": "Activate plugin", |
|||
"suspend": "Suspend plugin", |
|||
"active": "Active", |
|||
"suspended": "Suspended", |
|||
"name": "Name", |
|||
"name-required": "Name is required.", |
|||
"description": "Description", |
|||
"add": "Add Plugin", |
|||
"delete-plugin-title": "Are you sure you want to delete the plugin '{{pluginName}}'?", |
|||
"delete-plugin-text": "Be careful, after the confirmation the plugin and all related data will become unrecoverable.", |
|||
"delete-plugins-title": "Are you sure you want to delete { count, select, 1 {1 plugin} other {# plugins} }?", |
|||
"delete-plugins-action-title": "Delete { count, select, 1 {1 plugin} other {# plugins} }", |
|||
"delete-plugins-text": "Be careful, after the confirmation all selected plugins will be removed and all related data will become unrecoverable.", |
|||
"add-plugin-text": "Add new plugin", |
|||
"no-plugins-text": "No plugins found", |
|||
"plugin-details": "Plugin details", |
|||
"api-token": "API token", |
|||
"api-token-required": "API token is required.", |
|||
"type": "Plugin type", |
|||
"type-required": "Plugin type is required.", |
|||
"configuration": "Plugin configuration", |
|||
"system": "System", |
|||
"select-plugin": "Select plugin", |
|||
"plugin": "Plugin", |
|||
"no-plugins-matching": "No plugins matching '{{plugin}}' were found.", |
|||
"plugin-required": "Plugin is required.", |
|||
"plugin-require-match": "Please select an existing plugin.", |
|||
"events": "Events", |
|||
"details": "Details" |
|||
}, |
|||
"profile": { |
|||
"profile": "Profile", |
|||
"change-password": "Change Password", |
|||
"current-password": "Current password" |
|||
}, |
|||
"rule": { |
|||
"rules": "Rules", |
|||
"delete": "Delete rule", |
|||
"activate": "Activate rule", |
|||
"suspend": "Suspend rule", |
|||
"active": "Active", |
|||
"suspended": "Suspended", |
|||
"name": "Name", |
|||
"name-required": "Name is required.", |
|||
"description": "Description", |
|||
"add": "Add Rule", |
|||
"delete-rule-title": "Are you sure you want to delete the rule '{{ruleName}}'?", |
|||
"delete-rule-text": "Be careful, after the confirmation the rule and all related data will become unrecoverable.", |
|||
"delete-rules-title": "Are you sure you want to delete { count, select, 1 {1 rule} other {# rules} }?", |
|||
"delete-rules-action-title": "Delete { count, select, 1 {1 rule} other {# rules} }", |
|||
"delete-rules-text": "Be careful, after the confirmation all selected rules will be removed and all related data will become unrecoverable.", |
|||
"add-rule-text": "Add new rule", |
|||
"no-rules-text": "No rules found", |
|||
"rule-details": "Rule details", |
|||
"filters": "Filters", |
|||
"filter": "Filter", |
|||
"add-filter-prompt": "Please add filter", |
|||
"remove-filter": "Remove filter", |
|||
"add-filter": "Add filter", |
|||
"filter-name": "Filter name", |
|||
"filter-type": "Filter type", |
|||
"edit-filter": "Edit filter", |
|||
"view-filter": "View filter", |
|||
"component-name": "Name", |
|||
"component-name-required": "Name is required.", |
|||
"component-type": "Type", |
|||
"component-type-required": "Type is required.", |
|||
"processor": "Processor", |
|||
"no-processor-configured": "No processor configured", |
|||
"create-processor": "Create processor", |
|||
"processor": "Processor", |
|||
"processor-name": "Processor name", |
|||
"processor-type": "Processor type", |
|||
"plugin-action": "Plugin action", |
|||
"action-name": "Action name", |
|||
"action-type": "Action type", |
|||
"create-action-prompt": "Please create action", |
|||
"create-action": "Create action", |
|||
"details": "Details", |
|||
"events": "Events", |
|||
"system": "System" |
|||
}, |
|||
"rule-plugin": { |
|||
"management": "Rules and plugins management" |
|||
}, |
|||
"tenant": { |
|||
"tenants": "Tenants", |
|||
"management": "Tenant management", |
|||
"add": "Add Tenant", |
|||
"admins": "Admins", |
|||
"manage-tenant-admins": "Manage tenant admins", |
|||
"delete": "Delete tenant", |
|||
"add-tenant-text": "Add new tenant", |
|||
"no-tenants-text": "No tenants found", |
|||
"tenant-details": "Tenant details", |
|||
"delete-tenant-title": "Are you sure you want to delete the tenant '{{tenantTitle}}'?", |
|||
"delete-tenant-text": "Be careful, after the confirmation the tenant and all related data will become unrecoverable.", |
|||
"delete-tenants-title": "Are you sure you want to delete { count, select, 1 {1 tenant} other {# tenants} }?", |
|||
"delete-tenants-action-title": "Delete { count, select, 1 {1 tenant} other {# tenants} }", |
|||
"delete-tenants-text": "Be careful, after the confirmation all selected tenants will be removed and all related data will become unrecoverable.", |
|||
"title": "Title", |
|||
"title-required": "Title is required.", |
|||
"description": "Description" |
|||
}, |
|||
"timeinterval": { |
|||
"seconds-interval": "{ seconds, select, 1 {1 second} other {# seconds} }", |
|||
"minutes-interval": "{ minutes, select, 1 {1 minute} other {# minutes} }", |
|||
"hours-interval": "{ hours, select, 1 {1 hour} other {# hours} }", |
|||
"days-interval": "{ days, select, 1 {1 day} other {# days} }", |
|||
"days": "Days", |
|||
"hours": "Hours", |
|||
"minutes": "Minutes", |
|||
"seconds": "Seconds" |
|||
}, |
|||
"timewindow": { |
|||
"days": "{ days, select, 1 { day } other {# days } }", |
|||
"hours": "{ hours, select, 0 { hour } 1 {1 hour } other {# hours } }", |
|||
"minutes": "{ minutes, select, 0 { minute } 1 {1 minute } other {# minutes } }", |
|||
"seconds": "{ seconds, select, 0 { second } 1 {1 second } other {# seconds } }", |
|||
"realtime": "Realtime", |
|||
"history": "History", |
|||
"last-prefix": "last", |
|||
"period": "from {{ startTime }} to {{ endTime }}", |
|||
"edit": "Edit timewindow", |
|||
"date-range": "Date range", |
|||
"last": "Last", |
|||
"time-period": "Time period" |
|||
}, |
|||
"user": { |
|||
"users": "Users", |
|||
"customer-users": "Customer Users", |
|||
"tenant-admins": "Tenant Admins", |
|||
"sys-admin": "System administrator", |
|||
"tenant-admin": "Tenant administrator", |
|||
"customer": "Customer", |
|||
"anonymous": "Anonymous", |
|||
"add": "Add User", |
|||
"delete": "Delete user", |
|||
"add-user-text": "Add new user", |
|||
"no-users-text": "No users found", |
|||
"user-details": "User details", |
|||
"delete-user-title": "Are you sure you want to delete the user '{{userEmail}}'?", |
|||
"delete-user-text": "Be careful, after the confirmation the user and all related data will become unrecoverable.", |
|||
"delete-users-title": "Are you sure you want to delete { count, select, 1 {1 user} other {# users} }?", |
|||
"delete-users-action-title": "Delete { count, select, 1 {1 user} other {# users} }", |
|||
"delete-users-text": "Be careful, after the confirmation all selected users will be removed and all related data will become unrecoverable.", |
|||
"activation-email-sent-message": "Activation email was successfully sent!", |
|||
"resend-activation": "Resend activation", |
|||
"email": "Email", |
|||
"email-required": "Email is required.", |
|||
"first-name": "First Name", |
|||
"last-name": "Last Name", |
|||
"description": "Description" |
|||
}, |
|||
"value": { |
|||
"type": "Value type", |
|||
"string": "String", |
|||
"string-value": "String value", |
|||
"integer": "Integer", |
|||
"integer-value": "Integer value", |
|||
"invalid-integer-value": "Invalid integer value", |
|||
"double": "Double", |
|||
"double-value": "Double value", |
|||
"boolean": "Boolean", |
|||
"boolean-value": "Boolean value", |
|||
"false": "False", |
|||
"true": "True" |
|||
}, |
|||
"widget": { |
|||
"widget-library": "Widgets Library", |
|||
"widget-bundle": "Widgets Bundle", |
|||
"select-widgets-bundle": "Select widgets bundle", |
|||
"management": "Widget management", |
|||
"editor": "Widget Editor", |
|||
"widget-type-not-found": "Problem loading widget configuration.<br>Probably associated\n widget type was removed.", |
|||
"widget-type-load-error": "Widget wasn't loaded due to the following errors:", |
|||
"remove": "Remove widget", |
|||
"edit": "Edit widget", |
|||
"remove-widget-title": "Are you sure you want to remove the widget '{{widgetTitle}}'?", |
|||
"remove-widget-text": "After the confirmation the widget and all related data will become unrecoverable.", |
|||
"timeseries": "Time series", |
|||
"latest-values": "Latest values", |
|||
"rpc": "Control widget", |
|||
"static": "Static widget", |
|||
"select-widget-type": "Select widget type", |
|||
"missing-widget-title-error": "Widget title must be specified!", |
|||
"widget-saved": "Widget saved", |
|||
"unable-to-save-widget-error": "Unable to save widget! Widget has errors!", |
|||
"save": "Save widget", |
|||
"saveAs": "Save widget as", |
|||
"save-widget-type-as": "Save widget type as", |
|||
"save-widget-type-as-text": "Please enter new widget title and/or select target widgets bundle", |
|||
"toggle-fullscreen": "Toggle fullscreen", |
|||
"run": "Run widget", |
|||
"title": "Widget title", |
|||
"title-required": "Widget title is required.", |
|||
"type": "Widget type", |
|||
"resources": "Resources", |
|||
"resource-url": "JavaScript/CSS URI", |
|||
"remove-resource": "Remove resource", |
|||
"add-resource": "Add resource", |
|||
"html": "HTML", |
|||
"tidy": "Tidy", |
|||
"css": "CSS", |
|||
"settings-schema": "Settings schema", |
|||
"datakey-settings-schema": "Data key settings schema", |
|||
"javascript": "Javascript", |
|||
"remove-widget-type-title": "Are you sure you want to remove the widget type '{{widgetName}}'?", |
|||
"remove-widget-type-text": "After the confirmation the widget type and all related data will become unrecoverable.", |
|||
"remove-widget-type": "Remove widget type", |
|||
"add-widget-type": "Add new widget type", |
|||
"widget-type-load-failed-error": "Failed to load widget type!", |
|||
"widget-template-load-failed-error": "Failed to load widget template!", |
|||
"add": "Add Widget", |
|||
"undo": "Undo widget changes", |
|||
"export": "Export widget" |
|||
}, |
|||
"widgets-bundle": { |
|||
"current": "Current bundle", |
|||
"widgets-bundles": "Widgets Bundles", |
|||
"add": "Add Widgets Bundle", |
|||
"delete": "Delete widgets bundle", |
|||
"title": "Title", |
|||
"title-required": "Title is required.", |
|||
"add-widgets-bundle-text": "Add new widgets bundle", |
|||
"no-widgets-bundles-text": "No widgets bundles found", |
|||
"empty": "Widgets bundle is empty", |
|||
"details": "Details", |
|||
"widgets-bundle-details": "Widgets bundle details", |
|||
"delete-widgets-bundle-title": "Are you sure you want to delete the widgets bundle '{{widgetsBundleTitle}}'?", |
|||
"delete-widgets-bundle-text": "Be careful, after the confirmation the widgets bundle and all related data will become unrecoverable.", |
|||
"delete-widgets-bundles-title": "Are you sure you want to delete { count, select, 1 {1 widgets bundle} other {# widgets bundles} }?", |
|||
"delete-widgets-bundles-action-title": "Delete { count, select, 1 {1 widgets bundle} other {# widgets bundles} }", |
|||
"delete-widgets-bundles-text": "Be careful, after the confirmation all selected widgets bundles will be removed and all related data will become unrecoverable.", |
|||
"no-widgets-bundles-matching": "No widgets bundles matching '{{widgetsBundle}}' were found.", |
|||
"widgets-bundle-required": "Widgets bundle is required.", |
|||
"system": "System" |
|||
}, |
|||
"widget-config": { |
|||
"settings": "Settings", |
|||
"advanced": "Advanced", |
|||
"title": "Title", |
|||
"general-settings": "General settings", |
|||
"display-title": "Display title", |
|||
"drop-shadow": "Drop shadow", |
|||
"enable-fullscreen": "Enable fullscreen", |
|||
"background-color": "Background color", |
|||
"text-color": "Text color", |
|||
"padding": "Padding", |
|||
"title-style": "Title style", |
|||
"mobile-mode-settings": "Mobile mode settings", |
|||
"order": "Order", |
|||
"height": "Height", |
|||
"timewindow": "Timewindow", |
|||
"datasources": "Datasources", |
|||
"datasource-type": "Type", |
|||
"datasource-parameters": "Parameters", |
|||
"remove-datasource": "Remove datasource", |
|||
"add-datasource": "Add datasource", |
|||
"target-device": "Target device" |
|||
} |
|||
} |
|||
File diff suppressed because one or more lines are too long
Loading…
Reference in new issue