1055 lines
34 KiB
JavaScript
1055 lines
34 KiB
JavaScript
/*
|
|
* Copyright © 2016-2018 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 './dashboard.scss';
|
|
|
|
import 'javascript-detect-element-resize/detect-element-resize';
|
|
import angularGridster from 'angular-gridster';
|
|
import thingsboardTypes from '../common/types.constant';
|
|
import thingsboardApiWidget from '../api/widget.service';
|
|
import thingsboardWidget from './widget/widget.directive';
|
|
import thingsboardToast from '../services/toast';
|
|
import thingsboardTimewindow from './timewindow.directive';
|
|
import thingsboardEvents from './tb-event-directives';
|
|
import thingsboardMousepointMenu from './mousepoint-menu.directive';
|
|
|
|
/* eslint-disable import/no-unresolved, import/default */
|
|
|
|
import dashboardTemplate from './dashboard.tpl.html';
|
|
|
|
/* eslint-enable import/no-unresolved, import/default */
|
|
|
|
/* eslint-disable angular/angularelement */
|
|
|
|
export default angular.module('thingsboard.directives.dashboard', [thingsboardTypes,
|
|
thingsboardToast,
|
|
thingsboardApiWidget,
|
|
thingsboardWidget,
|
|
thingsboardTimewindow,
|
|
thingsboardEvents,
|
|
thingsboardMousepointMenu,
|
|
angularGridster.name])
|
|
.directive('tbDashboard', Dashboard)
|
|
.name;
|
|
|
|
/*@ngInject*/
|
|
function Dashboard() {
|
|
return {
|
|
restrict: "E",
|
|
scope: true,
|
|
bindToController: {
|
|
widgets: '=',
|
|
widgetLayouts: '=?',
|
|
aliasController: '=',
|
|
stateController: '=',
|
|
dashboardTimewindow: '=?',
|
|
columns: '=',
|
|
margins: '=',
|
|
isEdit: '=',
|
|
autofillHeight: '=',
|
|
mobileAutofillHeight: '=?',
|
|
mobileRowHeight: '=?',
|
|
isMobile: '=',
|
|
isMobileDisabled: '=?',
|
|
isEditActionEnabled: '=',
|
|
isExportActionEnabled: '=',
|
|
isRemoveActionEnabled: '=',
|
|
onEditWidget: '&?',
|
|
onExportWidget: '&?',
|
|
onRemoveWidget: '&?',
|
|
onWidgetMouseDown: '&?',
|
|
onWidgetClicked: '&?',
|
|
prepareDashboardContextMenu: '&?',
|
|
prepareWidgetContextMenu: '&?',
|
|
loadWidgets: '&?',
|
|
onInit: '&?',
|
|
onInitFailed: '&?',
|
|
dashboardStyle: '=?',
|
|
dashboardClass: '=?',
|
|
ignoreLoading: '=?'
|
|
},
|
|
controller: DashboardController,
|
|
controllerAs: 'vm',
|
|
templateUrl: dashboardTemplate
|
|
};
|
|
}
|
|
|
|
/*@ngInject*/
|
|
function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, $mdUtil, $q, timeService, types, utils) {
|
|
|
|
var highlightedMode = false;
|
|
var highlightedWidget = null;
|
|
var selectedWidget = null;
|
|
|
|
var gridsterParent = angular.element('#gridster-parent', $element);
|
|
var gridsterElement = angular.element('#gridster-child', gridsterParent);
|
|
|
|
var vm = this;
|
|
|
|
vm.gridster = null;
|
|
|
|
vm.isMobileDisabled = angular.isDefined(vm.isMobileDisabled) ? vm.isMobileDisabled : false;
|
|
|
|
vm.isMobileSize = false;
|
|
|
|
if (!('dashboardTimewindow' in vm)) {
|
|
vm.dashboardTimewindow = timeService.defaultTimewindow();
|
|
}
|
|
|
|
vm.dashboardLoading = true;
|
|
vm.visibleRect = {
|
|
top: 0,
|
|
bottom: 0,
|
|
left: 0,
|
|
right: 0
|
|
};
|
|
vm.gridsterOpts = {
|
|
pushing: false,
|
|
floating: false,
|
|
swapping: false,
|
|
maxRows: 100,
|
|
columns: vm.columns ? vm.columns : 24,
|
|
margins: vm.margins ? vm.margins : [10, 10],
|
|
minSizeX: 1,
|
|
minSizeY: 1,
|
|
defaultSizeX: 8,
|
|
defaultSizeY: 6,
|
|
resizable: {
|
|
enabled: vm.isEdit
|
|
},
|
|
draggable: {
|
|
enabled: vm.isEdit
|
|
},
|
|
saveGridItemCalculatedHeightInMobile: true
|
|
};
|
|
|
|
updateMobileOpts();
|
|
|
|
vm.widgetLayoutInfo = {
|
|
};
|
|
|
|
vm.widgetIds = [];
|
|
|
|
vm.widgetItemMap = {
|
|
sizeX: 'vm.widgetLayoutInfo[widget.id].sizeX',
|
|
sizeY: 'vm.widgetLayoutInfo[widget.id].sizeY',
|
|
row: 'vm.widgetLayoutInfo[widget.id].row',
|
|
col: 'vm.widgetLayoutInfo[widget.id].col',
|
|
minSizeY: 'widget.minSizeY',
|
|
maxSizeY: 'widget.maxSizeY'
|
|
};
|
|
|
|
/*vm.widgetItemMap = {
|
|
sizeX: 'vm.widgetSizeX(widget)',
|
|
sizeY: 'vm.widgetSizeY(widget)',
|
|
row: 'vm.widgetRow(widget)',
|
|
col: 'vm.widgetCol(widget)',
|
|
minSizeY: 'widget.minSizeY',
|
|
maxSizeY: 'widget.maxSizeY'
|
|
};*/
|
|
|
|
vm.isWidgetExpanded = false;
|
|
vm.isHighlighted = isHighlighted;
|
|
vm.isNotHighlighted = isNotHighlighted;
|
|
vm.selectWidget = selectWidget;
|
|
vm.getSelectedWidget = getSelectedWidget;
|
|
vm.highlightWidget = highlightWidget;
|
|
vm.resetHighlight = resetHighlight;
|
|
|
|
vm.onWidgetFullscreenChanged = onWidgetFullscreenChanged;
|
|
|
|
vm.isAutofillHeight = autofillHeight;
|
|
|
|
vm.widgetMouseDown = widgetMouseDown;
|
|
vm.widgetClicked = widgetClicked;
|
|
|
|
vm.widgetSizeX = widgetSizeX;
|
|
vm.widgetSizeY = widgetSizeY;
|
|
vm.widgetRow = widgetRow;
|
|
vm.widgetCol = widgetCol;
|
|
vm.widgetStyle = widgetStyle;
|
|
vm.showWidgetTitle = showWidgetTitle;
|
|
vm.hasWidgetTitleTemplate = hasWidgetTitleTemplate;
|
|
vm.widgetTitleTemplate = widgetTitleTemplate;
|
|
vm.showWidgetTitlePanel = showWidgetTitlePanel;
|
|
vm.showWidgetActions = showWidgetActions;
|
|
vm.widgetTitleStyle = widgetTitleStyle;
|
|
vm.widgetTitle = widgetTitle;
|
|
vm.customWidgetHeaderActions = customWidgetHeaderActions;
|
|
vm.widgetActions = widgetActions;
|
|
vm.dropWidgetShadow = dropWidgetShadow;
|
|
vm.enableWidgetFullscreen = enableWidgetFullscreen;
|
|
vm.hasTimewindow = hasTimewindow;
|
|
vm.hasAggregation = hasAggregation;
|
|
vm.editWidget = editWidget;
|
|
vm.exportWidget = exportWidget;
|
|
vm.removeWidget = removeWidget;
|
|
vm.loading = loading;
|
|
|
|
vm.openDashboardContextMenu = openDashboardContextMenu;
|
|
vm.openWidgetContextMenu = openWidgetContextMenu;
|
|
|
|
vm.getEventGridPosition = getEventGridPosition;
|
|
vm.reload = reload;
|
|
|
|
vm.contextMenuItems = [];
|
|
vm.contextMenuEvent = null;
|
|
|
|
vm.widgetContextMenuItems = [];
|
|
vm.widgetContextMenuEvent = null;
|
|
|
|
vm.dashboardTimewindowApi = {
|
|
onResetTimewindow: function() {
|
|
$timeout(function() {
|
|
if (vm.originalDashboardTimewindow) {
|
|
vm.dashboardTimewindow = angular.copy(vm.originalDashboardTimewindow);
|
|
vm.originalDashboardTimewindow = null;
|
|
}
|
|
}, 0);
|
|
},
|
|
onUpdateTimewindow: function(startTimeMs, endTimeMs) {
|
|
if (!vm.originalDashboardTimewindow) {
|
|
vm.originalDashboardTimewindow = angular.copy(vm.dashboardTimewindow);
|
|
}
|
|
$timeout(function() {
|
|
vm.dashboardTimewindow = timeService.toHistoryTimewindow(vm.dashboardTimewindow, startTimeMs, endTimeMs);
|
|
}, 0);
|
|
}
|
|
};
|
|
|
|
addResizeListener(gridsterParent[0], onGridsterParentResize); // eslint-disable-line no-undef
|
|
|
|
$scope.$on("$destroy", function () {
|
|
removeResizeListener(gridsterParent[0], onGridsterParentResize); // eslint-disable-line no-undef
|
|
});
|
|
|
|
function onGridsterParentResize() {
|
|
if (gridsterParent.height() && autofillHeight()) {
|
|
updateMobileOpts();
|
|
}
|
|
}
|
|
|
|
//TODO: widgets visibility
|
|
/*gridsterParent.scroll(function () {
|
|
updateVisibleRect();
|
|
});
|
|
|
|
gridsterParent.resize(function () {
|
|
updateVisibleRect();
|
|
});*/
|
|
|
|
function updateMobileOpts() {
|
|
var isMobileDisabled = vm.isMobileDisabled === true;
|
|
var isMobile = vm.isMobile === true && !isMobileDisabled;
|
|
var mobileBreakPoint = isMobileDisabled ? 0 : (isMobile ? 20000 : 960);
|
|
|
|
if (!isMobile && !isMobileDisabled) {
|
|
isMobile = !$mdMedia('gt-sm');
|
|
}
|
|
|
|
if (vm.gridsterOpts.isMobile != isMobile) {
|
|
vm.gridsterOpts.isMobile = isMobile;
|
|
vm.gridsterOpts.mobileModeEnabled = isMobile;
|
|
}
|
|
if (vm.gridsterOpts.mobileBreakPoint != mobileBreakPoint) {
|
|
vm.gridsterOpts.mobileBreakPoint = mobileBreakPoint;
|
|
}
|
|
detectRowSize(isMobile).then(
|
|
function(rowHeight) {
|
|
if (vm.gridsterOpts.rowHeight != rowHeight) {
|
|
vm.gridsterOpts.rowHeight = rowHeight;
|
|
}
|
|
}
|
|
);
|
|
vm.isMobileSize = checkIsMobileSize();
|
|
}
|
|
|
|
function checkIsMobileSize() {
|
|
var isMobileDisabled = vm.isMobileDisabled === true;
|
|
var isMobileSize = vm.isMobile === true && !isMobileDisabled;
|
|
if (!isMobileSize && !isMobileDisabled) {
|
|
isMobileSize = !$mdMedia('gt-sm');
|
|
}
|
|
return isMobileSize;
|
|
}
|
|
|
|
$scope.$watch('vm.columns', function () {
|
|
var columns = vm.columns ? vm.columns : 24;
|
|
if (vm.gridsterOpts.columns != columns) {
|
|
vm.gridsterOpts.columns = columns;
|
|
if (vm.gridster) {
|
|
vm.gridster.columns = vm.columns;
|
|
updateGridsterParams();
|
|
}
|
|
//TODO: widgets visibility
|
|
//updateVisibleRect();
|
|
}
|
|
});
|
|
|
|
$scope.$watch(function() {
|
|
return $mdMedia('gt-sm') + ',' + vm.isMobile + ',' + vm.isMobileDisabled;
|
|
}, function() {
|
|
updateMobileOpts();
|
|
sortWidgets();
|
|
});
|
|
|
|
$scope.$watch(function() {
|
|
return vm.autofillHeight + ',' + vm.mobileAutofillHeight + ',' + vm.mobileRowHeight;
|
|
}, function () {
|
|
updateMobileOpts();
|
|
});
|
|
|
|
$scope.$watch('vm.margins', function () {
|
|
var margins = vm.margins ? vm.margins : [10, 10];
|
|
if (!angular.equals(vm.gridsterOpts.margins, margins)) {
|
|
vm.gridsterOpts.margins = margins;
|
|
updateMobileOpts();
|
|
if (vm.gridster) {
|
|
vm.gridster.margins = vm.margins;
|
|
updateGridsterParams();
|
|
}
|
|
//TODO: widgets visibility
|
|
//updateVisibleRect();
|
|
}
|
|
});
|
|
|
|
$scope.$watch('vm.isEdit', function () {
|
|
vm.gridsterOpts.resizable.enabled = vm.isEdit;
|
|
vm.gridsterOpts.draggable.enabled = vm.isEdit;
|
|
$scope.$broadcast('toggleDashboardEditMode', vm.isEdit);
|
|
});
|
|
|
|
$scope.$watch('vm.isMobileSize', function (newVal, prevVal) {
|
|
if (!angular.equals(newVal, prevVal)) {
|
|
$scope.$broadcast('mobileModeChanged', vm.isMobileSize);
|
|
}
|
|
});
|
|
|
|
$scope.$watchCollection('vm.widgets', function () {
|
|
var ids = [];
|
|
for (var i=0;i<vm.widgets.length;i++) {
|
|
var widget = vm.widgets[i];
|
|
if (!widget.id) {
|
|
widget.id = utils.guid();
|
|
}
|
|
ids.push(widget.id);
|
|
}
|
|
ids.sort(function (id1, id2) {
|
|
return id1.localeCompare(id2);
|
|
});
|
|
if (angular.equals(ids, vm.widgetIds)) {
|
|
return;
|
|
}
|
|
vm.widgetIds = ids;
|
|
for (i=0;i<vm.widgets.length;i++) {
|
|
widget = vm.widgets[i];
|
|
var layoutInfoObject = vm.widgetLayoutInfo[widget.id];
|
|
if (!layoutInfoObject) {
|
|
layoutInfoObject = {
|
|
widget: widget
|
|
};
|
|
Object.defineProperty(layoutInfoObject, 'sizeX', {
|
|
get: function() { return widgetSizeX(this.widget) },
|
|
set: function(newSizeX) { setWidgetSizeX(this.widget, newSizeX)}
|
|
});
|
|
Object.defineProperty(layoutInfoObject, 'sizeY', {
|
|
get: function() { return widgetSizeY(this.widget) },
|
|
set: function(newSizeY) { setWidgetSizeY(this.widget, newSizeY)}
|
|
});
|
|
Object.defineProperty(layoutInfoObject, 'row', {
|
|
get: function() { return widgetRow(this.widget) },
|
|
set: function(newRow) { setWidgetRow(this.widget, newRow)}
|
|
});
|
|
Object.defineProperty(layoutInfoObject, 'col', {
|
|
get: function() { return widgetCol(this.widget) },
|
|
set: function(newCol) { setWidgetCol(this.widget, newCol)}
|
|
});
|
|
vm.widgetLayoutInfo[widget.id] = layoutInfoObject;
|
|
}
|
|
}
|
|
for (var widgetId in vm.widgetLayoutInfo) {
|
|
if (ids.indexOf(widgetId) === -1) {
|
|
delete vm.widgetLayoutInfo[widgetId];
|
|
}
|
|
}
|
|
sortWidgets();
|
|
$mdUtil.nextTick(function () {
|
|
if (autofillHeight()) {
|
|
updateMobileOpts();
|
|
}
|
|
});
|
|
});
|
|
|
|
$scope.$watch('vm.widgetLayouts', function () {
|
|
updateMobileOpts();
|
|
sortWidgets();
|
|
});
|
|
|
|
$scope.$on('gridster-resized', function (event, sizes, theGridster) {
|
|
if (checkIsLocalGridsterElement(theGridster)) {
|
|
vm.gridster = theGridster;
|
|
setupGridster(vm.gridster);
|
|
vm.isResizing = false;
|
|
//TODO: widgets visibility
|
|
//updateVisibleRect(false, true);
|
|
}
|
|
});
|
|
|
|
$scope.$on('gridster-mobile-changed', function (event, theGridster) {
|
|
if (checkIsLocalGridsterElement(theGridster)) {
|
|
vm.gridster = theGridster;
|
|
setupGridster(vm.gridster);
|
|
detectRowSize(vm.gridster.isMobile).then(
|
|
function(rowHeight) {
|
|
if (vm.gridsterOpts.rowHeight != rowHeight) {
|
|
vm.gridsterOpts.rowHeight = rowHeight;
|
|
updateGridsterParams();
|
|
}
|
|
}
|
|
);
|
|
vm.isMobileSize = checkIsMobileSize();
|
|
|
|
//TODO: widgets visibility
|
|
/*$timeout(function () {
|
|
updateVisibleRect(true);
|
|
}, 500, false);*/
|
|
}
|
|
});
|
|
|
|
function autofillHeight() {
|
|
if (vm.gridsterOpts.isMobile) {
|
|
return angular.isDefined(vm.mobileAutofillHeight) ? vm.mobileAutofillHeight : false;
|
|
} else {
|
|
return angular.isDefined(vm.autofillHeight) ? vm.autofillHeight : false;
|
|
}
|
|
}
|
|
|
|
function detectViewportHeight() {
|
|
var deferred = $q.defer();
|
|
var viewportHeight = gridsterParent.height();
|
|
if (viewportHeight) {
|
|
deferred.resolve(viewportHeight);
|
|
} else {
|
|
$scope.viewportHeightWatch = $scope.$watch(function() { return gridsterParent.height(); },
|
|
function(viewportHeight) {
|
|
if (viewportHeight) {
|
|
$scope.viewportHeightWatch();
|
|
deferred.resolve(viewportHeight);
|
|
}
|
|
}
|
|
);
|
|
}
|
|
return deferred.promise;
|
|
}
|
|
|
|
function detectRowSize(isMobile) {
|
|
var deferred = $q.defer();
|
|
var rowHeight;
|
|
if (autofillHeight()) {
|
|
detectViewportHeight().then(
|
|
function(viewportHeight) {
|
|
var totalRows = 0;
|
|
for (var i = 0; i < vm.widgets.length; i++) {
|
|
var w = vm.widgets[i];
|
|
var sizeY = widgetSizeY(w);
|
|
if (isMobile) {
|
|
totalRows += sizeY;
|
|
} else {
|
|
var row = widgetRow(w);
|
|
var bottom = row + sizeY;
|
|
totalRows = Math.max(totalRows, bottom);
|
|
}
|
|
}
|
|
rowHeight = (viewportHeight - vm.gridsterOpts.margins[1]*(vm.widgets.length+1) + vm.gridsterOpts.margins[0]*vm.widgets.length) / totalRows;
|
|
deferred.resolve(rowHeight);
|
|
}
|
|
);
|
|
} else if (isMobile) {
|
|
rowHeight = angular.isDefined(vm.mobileRowHeight) ? vm.mobileRowHeight : 70;
|
|
deferred.resolve(rowHeight);
|
|
} else {
|
|
rowHeight = 'match';
|
|
deferred.resolve(rowHeight);
|
|
}
|
|
return deferred.promise;
|
|
}
|
|
|
|
function widgetOrder(widget) {
|
|
var order;
|
|
var hasLayout = vm.widgetLayouts && vm.widgetLayouts[widget.id];
|
|
if (hasLayout && angular.isDefined(vm.widgetLayouts[widget.id].mobileOrder)
|
|
&& vm.widgetLayouts[widget.id].mobileOrder >= 0) {
|
|
order = vm.widgetLayouts[widget.id].mobileOrder;
|
|
} else if (angular.isDefined(widget.config.mobileOrder) && widget.config.mobileOrder >= 0) {
|
|
order = widget.config.mobileOrder;
|
|
} else if (hasLayout) {
|
|
order = vm.widgetLayouts[widget.id].row;
|
|
} else {
|
|
order = widget.row;
|
|
}
|
|
return order;
|
|
}
|
|
|
|
$scope.$on('widgetPositionChanged', function () {
|
|
sortWidgets();
|
|
});
|
|
|
|
loadDashboard();
|
|
|
|
function sortWidgets() {
|
|
vm.widgets.sort(function (widget1, widget2) {
|
|
var row1 = widgetOrder(widget1);
|
|
var row2 = widgetOrder(widget2);
|
|
var res = row1 - row2;
|
|
if (res === 0) {
|
|
res = widgetCol(widget1) - widgetCol(widget2);
|
|
}
|
|
return res;
|
|
});
|
|
}
|
|
|
|
function reload() {
|
|
loadDashboard();
|
|
}
|
|
|
|
function loadDashboard() {
|
|
$timeout(function () {
|
|
if (vm.loadWidgets) {
|
|
var promise = vm.loadWidgets();
|
|
if (promise) {
|
|
promise.then(function () {
|
|
dashboardLoaded();
|
|
}, function () {
|
|
dashboardLoaded();
|
|
});
|
|
} else {
|
|
dashboardLoaded();
|
|
}
|
|
} else {
|
|
dashboardLoaded();
|
|
}
|
|
}, 0, false);
|
|
}
|
|
|
|
function updateGridsterParams() {
|
|
if (vm.gridster) {
|
|
if (vm.gridster.colWidth === 'auto') {
|
|
vm.gridster.curColWidth = (vm.gridster.curWidth + (vm.gridster.outerMargin ? -vm.gridster.margins[1] : vm.gridster.margins[1])) / vm.gridster.columns;
|
|
} else {
|
|
vm.gridster.curColWidth = vm.gridster.colWidth;
|
|
}
|
|
vm.gridster.curRowHeight = vm.gridster.rowHeight;
|
|
if (angular.isString(vm.gridster.rowHeight)) {
|
|
if (vm.gridster.rowHeight === 'match') {
|
|
vm.gridster.curRowHeight = Math.round(vm.gridster.curColWidth);
|
|
} else if (vm.gridster.rowHeight.indexOf('*') !== -1) {
|
|
vm.gridster.curRowHeight = Math.round(vm.gridster.curColWidth * vm.gridster.rowHeight.replace('*', '').replace(' ', ''));
|
|
} else if (vm.gridster.rowHeight.indexOf('/') !== -1) {
|
|
vm.gridster.curRowHeight = Math.round(vm.gridster.curColWidth / vm.gridster.rowHeight.replace('/', '').replace(' ', ''));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//TODO: widgets visibility
|
|
/*function updateVisibleRect (force, containerResized) {
|
|
if (vm.gridster) {
|
|
var position = $(vm.gridster.$element).position()
|
|
if (position) {
|
|
var viewportWidth = gridsterParent.width();
|
|
var viewportHeight = gridsterParent.height();
|
|
var top = -position.top;
|
|
var bottom = top + viewportHeight;
|
|
var left = -position.left;
|
|
var right = left + viewportWidth;
|
|
|
|
var newVisibleRect = {
|
|
top: vm.gridster.pixelsToRows(top),
|
|
topPx: top,
|
|
bottom: vm.gridster.pixelsToRows(bottom),
|
|
bottomPx: bottom,
|
|
left: vm.gridster.pixelsToColumns(left),
|
|
right: vm.gridster.pixelsToColumns(right),
|
|
isMobile: vm.gridster.isMobile,
|
|
curRowHeight: vm.gridster.curRowHeight,
|
|
containerResized: containerResized
|
|
};
|
|
|
|
if (force ||
|
|
newVisibleRect.top != vm.visibleRect.top ||
|
|
newVisibleRect.topPx != vm.visibleRect.topPx ||
|
|
newVisibleRect.bottom != vm.visibleRect.bottom ||
|
|
newVisibleRect.bottomPx != vm.visibleRect.bottomPx ||
|
|
newVisibleRect.left != vm.visibleRect.left ||
|
|
newVisibleRect.right != vm.visibleRect.right ||
|
|
newVisibleRect.isMobile != vm.visibleRect.isMobile ||
|
|
newVisibleRect.curRowHeight != vm.visibleRect.curRowHeight ||
|
|
newVisibleRect.containerResized != vm.visibleRect.containerResized) {
|
|
vm.visibleRect = newVisibleRect;
|
|
$scope.$broadcast('visibleRectChanged', vm.visibleRect);
|
|
}
|
|
}
|
|
}
|
|
}*/
|
|
|
|
function checkIsLocalGridsterElement (gridster) {
|
|
return gridsterElement && gridsterElement[0] === gridster.$element[0];
|
|
}
|
|
|
|
function onWidgetFullscreenChanged(expanded, widget) {
|
|
vm.isWidgetExpanded = expanded;
|
|
$scope.$broadcast('onWidgetFullscreenChanged', vm.isWidgetExpanded, widget);
|
|
}
|
|
|
|
function widgetMouseDown ($event, widget) {
|
|
if (vm.onWidgetMouseDown) {
|
|
vm.onWidgetMouseDown({event: $event, widget: widget});
|
|
}
|
|
}
|
|
|
|
function widgetClicked ($event, widget) {
|
|
if (vm.onWidgetClicked) {
|
|
vm.onWidgetClicked({event: $event, widget: widget});
|
|
}
|
|
}
|
|
|
|
function openDashboardContextMenu($event, $mdOpenMousepointMenu) {
|
|
if (vm.prepareDashboardContextMenu) {
|
|
vm.contextMenuItems = vm.prepareDashboardContextMenu();
|
|
if (vm.contextMenuItems && vm.contextMenuItems.length > 0) {
|
|
vm.contextMenuEvent = $event;
|
|
$mdOpenMousepointMenu($event);
|
|
}
|
|
}
|
|
}
|
|
|
|
function openWidgetContextMenu($event, widget, $mdOpenMousepointMenu) {
|
|
if (vm.prepareWidgetContextMenu) {
|
|
vm.widgetContextMenuItems = vm.prepareWidgetContextMenu({widget: widget});
|
|
if (vm.widgetContextMenuItems && vm.widgetContextMenuItems.length > 0) {
|
|
vm.widgetContextMenuEvent = $event;
|
|
$mdOpenMousepointMenu($event);
|
|
}
|
|
}
|
|
}
|
|
|
|
function getEventGridPosition(event) {
|
|
var pos = {
|
|
row: 0,
|
|
column: 0
|
|
}
|
|
if (!gridsterParent) {
|
|
return pos;
|
|
}
|
|
var offset = gridsterParent.offset();
|
|
var x = event.pageX - offset.left + gridsterParent.scrollLeft();
|
|
var y = event.pageY - offset.top + gridsterParent.scrollTop();
|
|
if (vm.gridster) {
|
|
pos.row = vm.gridster.pixelsToRows(y);
|
|
pos.column = vm.gridster.pixelsToColumns(x);
|
|
}
|
|
return pos;
|
|
}
|
|
|
|
function editWidget ($event, widget) {
|
|
if ($event) {
|
|
$event.stopPropagation();
|
|
}
|
|
if (vm.isEditActionEnabled && vm.onEditWidget) {
|
|
vm.onEditWidget({event: $event, widget: widget});
|
|
}
|
|
}
|
|
|
|
function exportWidget ($event, widget) {
|
|
if ($event) {
|
|
$event.stopPropagation();
|
|
}
|
|
if (vm.isExportActionEnabled && vm.onExportWidget) {
|
|
vm.onExportWidget({event: $event, widget: widget});
|
|
}
|
|
}
|
|
|
|
function removeWidget($event, widget) {
|
|
if ($event) {
|
|
$event.stopPropagation();
|
|
}
|
|
if (vm.isRemoveActionEnabled && vm.onRemoveWidget) {
|
|
vm.onRemoveWidget({event: $event, widget: widget});
|
|
}
|
|
}
|
|
|
|
function highlightWidget(widget, delay) {
|
|
if (!highlightedMode || highlightedWidget != widget) {
|
|
highlightedMode = true;
|
|
highlightedWidget = widget;
|
|
scrollToWidget(widget, delay);
|
|
}
|
|
}
|
|
|
|
function selectWidget(widget, delay) {
|
|
if (selectedWidget != widget) {
|
|
selectedWidget = widget;
|
|
scrollToWidget(widget, delay);
|
|
}
|
|
}
|
|
|
|
function scrollToWidget(widget, delay) {
|
|
if (vm.gridster) {
|
|
var item = angular.element('.gridster-item', vm.gridster.$element)[vm.widgets.indexOf(widget)];
|
|
if (item) {
|
|
var height = angular.element(item).outerHeight(true);
|
|
var rectHeight = gridsterParent.height();
|
|
var offset = (rectHeight - height) / 2;
|
|
var scrollTop = item.offsetTop;
|
|
if (offset > 0) {
|
|
scrollTop -= offset;
|
|
}
|
|
gridsterParent.animate({
|
|
scrollTop: scrollTop
|
|
}, delay);
|
|
}
|
|
}
|
|
}
|
|
|
|
function getSelectedWidget() {
|
|
return selectedWidget;
|
|
}
|
|
|
|
function resetHighlight() {
|
|
highlightedMode = false;
|
|
highlightedWidget = null;
|
|
selectedWidget = null;
|
|
}
|
|
|
|
function isHighlighted(widget) {
|
|
return (highlightedMode && highlightedWidget === widget) || (selectedWidget === widget);
|
|
}
|
|
|
|
function isNotHighlighted(widget) {
|
|
return highlightedMode && highlightedWidget != widget;
|
|
}
|
|
|
|
function widgetSizeX(widget) {
|
|
if (vm.widgetLayouts && vm.widgetLayouts[widget.id]) {
|
|
return vm.widgetLayouts[widget.id].sizeX;
|
|
} else {
|
|
return widget.sizeX;
|
|
}
|
|
}
|
|
|
|
function setWidgetSizeX(widget, sizeX) {
|
|
if (!vm.gridsterOpts.isMobile) {
|
|
if (vm.widgetLayouts && vm.widgetLayouts[widget.id]) {
|
|
vm.widgetLayouts[widget.id].sizeX = sizeX;
|
|
} else {
|
|
widget.sizeX = sizeX;
|
|
}
|
|
}
|
|
}
|
|
|
|
function widgetSizeY(widget) {
|
|
if (vm.gridsterOpts.isMobile && !vm.mobileAutofillHeight) {
|
|
var mobileHeight;
|
|
if (vm.widgetLayouts && vm.widgetLayouts[widget.id]) {
|
|
mobileHeight = vm.widgetLayouts[widget.id].mobileHeight;
|
|
}
|
|
if (!mobileHeight && widget.config.mobileHeight) {
|
|
mobileHeight = widget.config.mobileHeight;
|
|
}
|
|
if (mobileHeight) {
|
|
return mobileHeight;
|
|
} else {
|
|
return widget.sizeY * 24 / vm.gridsterOpts.columns;
|
|
}
|
|
} else {
|
|
if (vm.widgetLayouts && vm.widgetLayouts[widget.id]) {
|
|
return vm.widgetLayouts[widget.id].sizeY;
|
|
} else {
|
|
return widget.sizeY;
|
|
}
|
|
}
|
|
}
|
|
|
|
function setWidgetSizeY(widget, sizeY) {
|
|
if (!vm.gridsterOpts.isMobile && !vm.autofillHeight) {
|
|
if (vm.widgetLayouts && vm.widgetLayouts[widget.id]) {
|
|
vm.widgetLayouts[widget.id].sizeY = sizeY;
|
|
} else {
|
|
widget.sizeY = sizeY;
|
|
}
|
|
}
|
|
}
|
|
|
|
function widgetRow(widget) {
|
|
if (vm.widgetLayouts && vm.widgetLayouts[widget.id]) {
|
|
return vm.widgetLayouts[widget.id].row;
|
|
} else {
|
|
return widget.row;
|
|
}
|
|
}
|
|
|
|
function setWidgetRow(widget, row) {
|
|
if (!vm.gridsterOpts.isMobile) {
|
|
if (vm.widgetLayouts && vm.widgetLayouts[widget.id]) {
|
|
vm.widgetLayouts[widget.id].row = row;
|
|
} else {
|
|
widget.row = row;
|
|
}
|
|
}
|
|
}
|
|
|
|
function widgetCol(widget) {
|
|
if (vm.widgetLayouts && vm.widgetLayouts[widget.id]) {
|
|
return vm.widgetLayouts[widget.id].col;
|
|
} else {
|
|
return widget.col;
|
|
}
|
|
}
|
|
|
|
function setWidgetCol(widget, col) {
|
|
if (!vm.gridsterOpts.isMobile) {
|
|
if (vm.widgetLayouts && vm.widgetLayouts[widget.id]) {
|
|
vm.widgetLayouts[widget.id].col = col;
|
|
} else {
|
|
widget.col = col;
|
|
}
|
|
}
|
|
}
|
|
|
|
function widgetStyle(widget) {
|
|
var style = {cursor: 'pointer',
|
|
color: widgetColor(widget),
|
|
backgroundColor: widgetBackgroundColor(widget),
|
|
padding: widgetPadding(widget),
|
|
margin: widgetMargin(widget)};
|
|
if (angular.isDefined(widget.config.widgetStyle)) {
|
|
Object.assign(style, widget.config.widgetStyle);
|
|
}
|
|
return style;
|
|
}
|
|
|
|
function widgetColor(widget) {
|
|
if (widget.config.color) {
|
|
return widget.config.color;
|
|
} else {
|
|
return 'rgba(0, 0, 0, 0.87)';
|
|
}
|
|
}
|
|
|
|
function widgetBackgroundColor(widget) {
|
|
if (widget.config.backgroundColor) {
|
|
return widget.config.backgroundColor;
|
|
} else {
|
|
return '#fff';
|
|
}
|
|
}
|
|
|
|
function widgetPadding(widget) {
|
|
if (widget.config.padding) {
|
|
return widget.config.padding;
|
|
} else {
|
|
return '8px';
|
|
}
|
|
}
|
|
|
|
function widgetMargin(widget) {
|
|
if (widget.config.margin) {
|
|
return widget.config.margin;
|
|
} else {
|
|
return '0px';
|
|
}
|
|
}
|
|
|
|
function showWidgetTitle(widget) {
|
|
if (angular.isDefined(widget.config.showTitle)) {
|
|
return widget.config.showTitle;
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
function hasWidgetTitleTemplate(widget) {
|
|
var ctx = widgetContext(widget);
|
|
if (ctx && ctx.widgetTitleTemplate) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
function widgetTitleTemplate(widget) {
|
|
var ctx = widgetContext(widget);
|
|
if (ctx && ctx.widgetTitleTemplate) {
|
|
return ctx.widgetTitleTemplate;
|
|
} else {
|
|
return '';
|
|
}
|
|
}
|
|
|
|
function showWidgetTitlePanel(widget) {
|
|
var ctx = widgetContext(widget);
|
|
if (ctx && ctx.hideTitlePanel) {
|
|
return false;
|
|
} else {
|
|
return hasWidgetTitleTemplate(widget) || showWidgetTitle(widget) || hasTimewindow(widget);
|
|
}
|
|
}
|
|
|
|
function showWidgetActions(widget) {
|
|
var ctx = widgetContext(widget);
|
|
if (ctx && ctx.hideTitlePanel) {
|
|
return false;
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
function widgetTitleStyle(widget) {
|
|
if (angular.isDefined(widget.config.titleStyle)) {
|
|
return widget.config.titleStyle;
|
|
} else {
|
|
return {};
|
|
}
|
|
}
|
|
|
|
function widgetTitle(widget) {
|
|
var ctx = widgetContext(widget);
|
|
if (ctx && ctx.widgetTitle
|
|
&& ctx.widgetTitle.length) {
|
|
return ctx.widgetTitle;
|
|
} else {
|
|
return widget.config.title;
|
|
}
|
|
}
|
|
|
|
function customWidgetHeaderActions(widget) {
|
|
var ctx = widgetContext(widget);
|
|
if (ctx && ctx.customHeaderActions && ctx.customHeaderActions.length) {
|
|
return ctx.customHeaderActions;
|
|
} else {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
function widgetActions(widget) {
|
|
var ctx = widgetContext(widget);
|
|
if (ctx && ctx.widgetActions && ctx.widgetActions.length) {
|
|
return ctx.widgetActions;
|
|
} else {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
function widgetContext(widget) {
|
|
var context;
|
|
if (widget.$ctx) {
|
|
context = widget.$ctx();
|
|
}
|
|
return context;
|
|
}
|
|
|
|
function dropWidgetShadow(widget) {
|
|
if (angular.isDefined(widget.config.dropShadow)) {
|
|
return widget.config.dropShadow;
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
function enableWidgetFullscreen(widget) {
|
|
if (angular.isDefined(widget.config.enableFullscreen)) {
|
|
return widget.config.enableFullscreen;
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
function hasTimewindow(widget) {
|
|
if (widget.type === types.widgetType.timeseries.value || widget.type === types.widgetType.alarm.value) {
|
|
return angular.isDefined(widget.config.useDashboardTimewindow) ?
|
|
!widget.config.useDashboardTimewindow : false;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
function hasAggregation(widget) {
|
|
return widget.type === types.widgetType.timeseries.value;
|
|
}
|
|
|
|
function adoptMaxRows() {
|
|
if (vm.widgets) {
|
|
var maxRows = vm.gridsterOpts.maxRows;
|
|
for (var i = 0; i < vm.widgets.length; i++) {
|
|
var w = vm.widgets[i];
|
|
var bottom = widgetRow(w) + widgetSizeY(w);
|
|
maxRows = Math.max(maxRows, bottom);
|
|
}
|
|
vm.gridsterOpts.maxRows = Math.max(maxRows, vm.gridsterOpts.maxRows);
|
|
}
|
|
}
|
|
|
|
function dashboardLoaded() {
|
|
$mdUtil.nextTick(function () {
|
|
if (vm.dashboardTimewindowWatch) {
|
|
vm.dashboardTimewindowWatch();
|
|
vm.dashboardTimewindowWatch = null;
|
|
}
|
|
vm.dashboardTimewindowWatch = $scope.$watch('vm.dashboardTimewindow', function () {
|
|
$scope.$broadcast('dashboardTimewindowChanged', vm.dashboardTimewindow);
|
|
}, true);
|
|
adoptMaxRows();
|
|
vm.dashboardLoading = false;
|
|
if ($scope.gridsterScopeWatcher) {
|
|
$scope.gridsterScopeWatcher();
|
|
}
|
|
$scope.gridsterScopeWatcher = $scope.$watch(
|
|
function() {
|
|
var hasScope = gridsterElement.scope() ? true : false;
|
|
return hasScope;
|
|
},
|
|
function(hasScope) {
|
|
if (hasScope) {
|
|
$scope.gridsterScopeWatcher();
|
|
$scope.gridsterScopeWatcher = null;
|
|
var gridsterScope = gridsterElement.scope();
|
|
vm.gridster = gridsterScope.gridster;
|
|
setupGridster(vm.gridster);
|
|
if (vm.onInit) {
|
|
vm.onInit({dashboard: vm});
|
|
}
|
|
}
|
|
}
|
|
);
|
|
});
|
|
}
|
|
|
|
function setupGridster(gridster) {
|
|
if (gridster) {
|
|
if (!gridster.origMoveOverlappingItems) {
|
|
gridster.origMoveOverlappingItems = gridster.moveOverlappingItems;
|
|
gridster.moveOverlappingItems = () => {};
|
|
}
|
|
}
|
|
}
|
|
|
|
function loading() {
|
|
return !vm.ignoreLoading && $rootScope.loading;
|
|
}
|
|
|
|
}
|
|
|
|
/* eslint-enable angular/angularelement */
|