Save
Saving
  • G gresler_nec

    I know this is old, but I'm working on something similar in SVG. I took a stab at modifying jqSimpleConnect, and it appears to work in a Mango user module. Here's what I did in case @BobDay still needs it or anyone else finds it useful.

    First, I just put a copy of jqSimpleConnect.js in my public filestore, importing it in the define section of my user module. That let me start playing with it in the Chrome dev console until I could get it working. It defaults to putting the lines in the body, which are hidden behind the Mango UI. I tweaked it to use the Mango UI view area where custom pages are displayed and accounted for relative positioning. Finally, I wrapped it in a service.

    I won't assert that this is correct way, but on a simple test page I could successfully recreate the basic jqSimpleConnect example.

    In the user module, reference it in the three locations needed to make it a service.

    define([
        'angular',
        'require',
        ...
        './services/simpleConnectService.js',
    ],
    function(angular, require, ..., simpleConnectService) {
    'use strict';
    var yourModule = angular.module('yourModule', []);
    yourModule.service('simpleConnect', [simpleConnectService]);
    ...
    

    I didn't bother actually testing directives. I just injected it into a random test component I had, logged it to the console, saved as variable, and played with it interactively from there.

    temp1.connect('#div_a', '#div_b', {radius: 8, color: 'green'});
    

    Now for the wrapped/modified jQuery. I left comments to show what I changed.

    define([], function() {
    'use strict';
    
    // SimpleConnectService wraps jqSimpleConnect as an AngularJS service for Mango.
    // There are a few tweaks to make it work with the Mango dashboards, see "NOTE:" comments for modifications.
    function SimpleConnectService() {
    
        /*
        * «Copyright 2012 José F. Maldonado»
        *
        * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
        */
    
        /**
         * Declare namespace
         */
        // NOTE: Use the service itself.
        // jqSimpleConnect = new Object();
        let jqSimpleConnect = this;
    
        /**
         * This member is an auxiliary counter used for generate unique identifiers.
         */
        jqSimpleConnect._idGenerator = 0;
    
        /**
         * This member is an associative array which contains all the document's connections.
         */
        jqSimpleConnect._connections = new Object();
    
        /**
         * Positions a connection, acording to the position of the elements which connects.
         * 
         * @param {object} connection A connection object.
         */
        jqSimpleConnect._positionConnection = function(connection) {
            // Calculate the positions of the element's center.
    
            // NOTE: Get the position of the Mango UI view for displaying custom pages.
            let uiOffset = jQuery('div.ma-ui-main-view > div[ui-view]').offset();
            let uiPos = jQuery('div.ma-ui-main-view > div[ui-view]').position();
            uiPos.left = parseInt(uiOffset.left) - parseInt(uiPos.left);
            uiPos.top = parseInt(uiOffset.top) - parseInt(uiPos.top);
    
            // Calculate the positions of the element's center.
            var posA = connection.elementA.offset();
            // NOTE: Use the UI offset to calculate a relative offset.
            // posA.left = parseInt(posA.left, 10) + parseInt(connection.elementA.outerWidth()/2, 10);
            // posA.top = parseInt(posA.top, 10) + parseInt(connection.elementA.outerHeight()/2, 10);
            posA.left = parseInt(posA.left, 10) - uiPos.left + parseInt(connection.elementA.outerWidth()/2, 10);
            posA.top = parseInt(posA.top, 10) - uiPos.top + parseInt(connection.elementA.outerHeight()/2, 10);
    
            var posB = connection.elementB.offset();
            // NOTE: Use the UI offset to calculate a relative offset.
            // posB.left = parseInt(posB.left, 10) + parseInt(connection.elementB.outerWidth()/2, 10);
            // posB.top = parseInt(posB.top, 10) + parseInt(connection.elementB.outerHeight()/2, 10);
            posB.left = parseInt(posB.left, 10) - uiPos.left + parseInt(connection.elementB.outerWidth()/2, 10);
            posB.top = parseInt(posB.top, 10) - uiPos.top + parseInt(connection.elementB.outerHeight()/2, 10);
    
            // Get the line's elements.
            var line1 = jQuery('#' + connection.id + '_1');
            var line2 = jQuery('#' + connection.id + '_2');
            var line3 = jQuery('#' + connection.id + '_3');
    
            // Verify if the elements are aligned in a horizontal or vertical line.
            if(posA.left == posB.left || posA.top == posB.top) {
                // Uses only one line (hide the other two).
                line1.show();
                line2.hide();
                line3.hide();
    
                // Verify if the line must be vertical or horizonal.
                if(posA.left == posB.left) {
                    // Vertical line.
                    jqSimpleConnect._positionVerticalLine(line1, posA, posB, connection.radius, connection.roundedCorners);
                } else {
                    // Horizontal line.
                    jqSimpleConnect._positionHorizontalLine(line1, posA, posB, connection.radius, connection.roundedCorners);
                }
            } else {
                // Verify if must use two lines or three.
                if(connection.anchorA != connection.anchorB) {
                    // Use two lines (hide the third).
                    line1.show();
                    line2.show();
                    line3.hide();
        
                    // Check the anchors of the elements.
                    var corner = new Object();
                    if(connection.anchorA == 'vertical') {
                        // Find the corner's position.
                        corner.left = posA.left;
                        corner.top = posB.top;
                        
                        // Draw lines.
                        jqSimpleConnect._positionVerticalLine(line1, posA, corner, connection.radius, connection.roundedCorners);
                        jqSimpleConnect._positionHorizontalLine(line2, posB, corner, connection.radius, connection.roundedCorners);
                    } else {
                        // Find the corner's position.
                        corner.left = posB.left;
                        corner.top = posA.top;
                        
                        // Draw lines.
                        jqSimpleConnect._positionVerticalLine(line1, posB, corner, connection.radius, connection.roundedCorners);
                        jqSimpleConnect._positionHorizontalLine(line2, posA, corner, connection.radius, connection.roundedCorners);
                    }
                } else {
                    // Use three lines.
                    line1.show();
                    line2.show();
                    line3.show();
                    
                    // Declare connection points.
                    var corner1 = new Object();
                    var corner2 = new Object();
                    
                    // Find if the middle's line must be vertical o horizontal.
                    if(connection.anchorA == 'vertical') {
                        // Middle's line must be horizontal.
                        corner1.top = parseInt((posA.top + posB.top)/2, 10);
                        corner2.top = corner1.top;
                        corner1.left = posA.left;
                        corner2.left = posB.left;
                        
                        // Draw lines.
                        jqSimpleConnect._positionVerticalLine(line1, posA, corner1, connection.radius, connection.roundedCorners);
                        jqSimpleConnect._positionVerticalLine(line2, posB, corner2, connection.radius, connection.roundedCorners);
                        jqSimpleConnect._positionHorizontalLine(line3, corner1, corner2, connection.radius, connection.roundedCorners);
                    } else {
                        // Middle's line must be vertical.
                        corner1.left = parseInt((posA.left + posB.left)/2, 10);
                        corner2.left = corner1.left;
                        corner1.top = posA.top;
                        corner2.top = posB.top;
                        
                        // Draw lines.
                        jqSimpleConnect._positionHorizontalLine(line1, posA, corner1, connection.radius, connection.roundedCorners);
                        jqSimpleConnect._positionHorizontalLine(line2, posB, corner2, connection.radius, connection.roundedCorners);
                        jqSimpleConnect._positionVerticalLine(line3, corner1, corner2, connection.radius, connection.roundedCorners);
                    }
                }
            }
        }
    
        /**
         * Draws a vertical line, between the two points, by changing the properties of a HTML element.
         *
         *@param {object} jqElement A jQuery object of the HTML element used for represent the line.
        *@param {object} point1 An object with the properties 'left' and 'top' representing the position of the first point.
        *@param {object} point2 An object with the properties 'left' and 'top' representing the position of the second point.
        *@param {integer} radius The line's radius.
        *@param {boolean} roundedCorners A boolean indicating if the corners are going to be round.
        */
        jqSimpleConnect._positionVerticalLine = function(jqElement, point1, point2, radius, roundedCorners) {
            var halfRadius = parseInt(radius/2, 10);
            jqElement.css('left', point1.left - halfRadius);
            jqElement.css('top', ((point1.top > point2.top)? (point2.top - halfRadius) : (point1.top - halfRadius)));
            jqElement.css('width', radius + 'px');
            jqElement.css('height', ((point1.top > point2.top)? (point1.top - point2.top + radius) : (point2.top - point1.top + radius) ) + 'px');
        }
    
        /**
         * Draws a horizontal line, between the two points, by changing the properties of a HTML element.
         *
         *@param {object} jqElement A jQuery object of the HTML element used for represent the line.
        *@param {object} point1 An object with the properties 'left' and 'top' representing the position of the first point.
        *@param {object} point2 An object with the properties 'left' and 'top' representing the position of the second point.
        *@param {integer} radius The line's radius.
        *@param {boolean} roundedCorners A boolean indicating if the corners are going to be round.
        */
        jqSimpleConnect._positionHorizontalLine = function(jqElement, point1, point2, radius, roundedCorners) {
            var halfRadius = parseInt(radius/2, 10);
            jqElement.css('top', point1.top - halfRadius);
            jqElement.css('left', ((point1.left > point2.left)? (point2.left - halfRadius) : (point1.left - halfRadius)));
            jqElement.css('height', radius + 'px');
            jqElement.css('width', ((point1.left > point2.left)? (point1.left - point2.left + radius) : (point2.left - point1.left + radius) ) + 'px');
        }
    
        /**
         * Draws a connection between two elements.
         *
         * @param {object} elementA A CSS selector or a jQuery's object for select the first element.
         * @param {object} elementB A CSS selector or a jQuery's object for select the second element.
         * @param {object} options An associative array with the properties 'color' (which defines the color of the connection), 'radius' (the width of the
         * connection), 'roundedCorners' (a boolean indicating if the corners must be round), 'anchorA' (the anchor type of the first element, which can be 
         * 'horizontal' or 'vertical') and 'anchorB' (the anchor type of second element).
         * @returns {string} The connection identifier or 'null' if the connection could not be draw.
         */
        jqSimpleConnect.connect = function(elementA, elementB, options) {
            // Verify if the element's selector are ok.
            // NOTE: Use length instead of size(). AngularJS/Mango's jQuery doesn't have size.
            // if(elementA == null || jQuery(elementA).size() == 0 ||
            //    elementB == null || jQuery(elementB).size() == 0) {
            //    return null;
            //    }
            if(elementA == null || jQuery(elementA).length == 0 ||
            elementB == null || jQuery(elementB).length == 0) {
                // NOTE: Yell at me when I make a typo. Remove when it's working, or make this more useful.
                console.warn('failed to locate elements');
            return null;
            }
    
            // NOTE: Use length instead of size() here too.
            elementA = jQuery(elementA);
            // if(elementA.size() > 1) elementA = elementA.first();
            if(elementA.length > 1) elementA = elementA.first();
            elementB = jQuery(elementB);
            // if(elementB.size() > 1) elementB = elementB.first();
            if(elementB.length > 1) elementB = elementB.first();
    
            // Create connection object.
            var connection = new Object();
            connection.id = 'jqSimpleConnect_' + jqSimpleConnect._idGenerator++;
            connection.elementA = elementA;
            connection.elementB = elementB;
            connection.color = (options != null && options.color != null)? options.color + '' : '#808080';
            connection.radius = (options != null && options.radius != null && !isNaN(options.radius))? parseInt(options.radius, 10) : 5;
            connection.anchorA = (options != null && options.anchorA != null && (options.anchorA == 'vertical' || options.anchorA == 'horizontal'))? options.anchorA : 'horizontal';
            connection.anchorB = (options != null && options.anchorB != null && (options.anchorB == 'vertical' || options.anchorB == 'horizontal'))? options.anchorB : 'horizontal';
            connection.roundedCorners = options != null && options.roundedCorners != null && (options.roundedCorners == true || options.roundedCorners == 'true');
            connection.click = (options != null && options.click != null)? options.click : null;
            connection.mouseover = (options != null && options.mouseover != null)? options.mouseover : null;
            connection.mouseout = (options != null && options.mouseout != null)? options.mouseout : null;
            
            // Add connection to the connection's list.
            jqSimpleConnect._connections[connection.id] = connection;
    
            // Create HTML elements.
            var div = '<div id="divUniqueIdentifier" class="jqSimpleConnect '+connection.id+'" ' + 
                    'style="width:'+connection.radius+'px; ' +
                            'height:'+connection.radius+'px; ' +
                            'background-color:'+connection.color+'; ' +
                            (connection.roundedCorners? 'border-radius:'+parseInt(connection.radius/2,10)+'px; -webkit-border-radius:'+parseInt(connection.radius/2,10)+'px; -moz-border-radius:'+parseInt(connection.radius/2,10)+'px; ' : '') + 
                            'position:absolute;"></div>';
            // NOTE: 'body' will place elements behind the page. Instead of messing with z-index, use the Mango UI view.
            // jQuery('body').prepend(div.replace('divUniqueIdentifier', connection.id + '_1'));
            // jQuery('body').prepend(div.replace('divUniqueIdentifier', connection.id + '_2'));
            // jQuery('body').prepend(div.replace('divUniqueIdentifier', connection.id + '_3'));
            jQuery('div.ma-ui-main-view > div[ui-view]').prepend(div.replace('divUniqueIdentifier', connection.id + '_1'));
            jQuery('div.ma-ui-main-view > div[ui-view]').prepend(div.replace('divUniqueIdentifier', connection.id + '_2'));
            jQuery('div.ma-ui-main-view > div[ui-view]').prepend(div.replace('divUniqueIdentifier', connection.id + '_3'));
    
            jQuery("."+connection.id).click(function() {
                if(typeof connection.click == "function") {
                    connection.click(connection);
                }
            }).on("mouseover", function() {
                if(typeof connection.mouseover == "function") {
                    connection.mouseover(connection);
                }
            }).on("mouseout", function() {
                if(typeof connection.mouseout == "function") {
                    connection.mouseout(connection);
                }
            });
            
            // Position connection.
            jqSimpleConnect._positionConnection(connection);
            
            // Return result.
            return connection.id;
        }
    
        /**
         * Repaints a connection.
         *
         * @param {string} connectionId The connection identifier.
         * @returns {boolean} 'true' if the operation was done, 'false' if the connection no exists.
         */
        jqSimpleConnect.repaintConnection = function(connectionId) {
            var connection = jqSimpleConnect._connections[connectionId];
            if(connection != null) {
                jqSimpleConnect._positionConnection(connection);
                return true;
            }
            return false;
        }
    
        /**
         * Repaints all the connections.
         */
        jqSimpleConnect.repaintAll = function() {
            for(var key in jqSimpleConnect._connections) {
                jqSimpleConnect._positionConnection(jqSimpleConnect._connections[key]);
            }
        }
    
        /**
         * Removes a connection.
         *
         * @param {string} connectionId The connection identifier.
         * @returns {boolean} 'true' if the operation was done, 'false' if the connection no exists.
         */
        jqSimpleConnect.removeConnection = function(connectionId) {
            if(jqSimpleConnect._connections[connectionId] != null) {
                // Remove HTML element.
                jQuery('.jqSimpleConnect.'+connectionId).remove();
                
                // Remove connection data.
                jqSimpleConnect._connections[connectionId] = null;
                delete jqSimpleConnect._connections[connectionId];
                
                // Return result.
                return true;
            }
            return false;
        }
    
        /**
         * Removes all the connections.
         */
        jqSimpleConnect.removeAll = function() {
            // Remove HTML elements.
            jQuery('.jqSimpleConnect').remove();
            
            // Clear connections list.
            for(var key in jqSimpleConnect._connections) {
                jqSimpleConnect._connections[key] = null;
                delete jqSimpleConnect._connections[key];
            }
        }
    
    
    // End of jqSimpleConnect.
    } return SimpleConnectService;
    });
    

    posted in User help read more
  • G gresler_nec

    Taking a different approach, this example works for copying the value. So it should get me what I need, but I'd still like to know if there is a way to get the count of rows for a given variable or named range if possible.

    In this example my timestamp is the first column, and epoch is the second column. I have headers above the named ranges, so it starts at row 1. This also assumes that the 'Date__EPOCH' range is empty when post processing starts.

    ExcelReportUtility.openNamedRange('Date__EPOCH', false);
    var timestamp = null;
    var i = 1;
    do {
        timestamp = ExcelReportUtility.getString(0, 0, i);
        if (timestamp == null) {
            break;
        }
        ExcelReportUtility.writeStringToNamedRange('Date__EPOCH', timestamp);
        i += 1;
    }while (timestamp != null);
    

    posted in User help read more
  • G gresler_nec

    I have an Excel report template that needs the timestamp in two columns (locale and epoch). Currently I have all data populated in the report, minus the column for epoch.

    Is there a way to get the range of cells added to the report in post processing, so I can update the second column in the script?

    I've tried ExcelReportUtility.getUsedRanges(), but I'm not sure what type of object the keys map to. It looks like this in the log output. The typeof says object, but I haven't found any object/array/string functions, or keys/methods, that work on it yet.

    {Date__EPOCH=Date__EPOCH @ Sheet1!$B$2-->Sheet1!$B$6}
    

    openNamedRange is fine for writing, but it doesn't return anything or have a corresponding function for reading. The majority of the other functions seem to be for reading/writing known cells.

    This other post only gives the report's start/end time, not the data in the report itself.

    https://forum.infiniteautomation.com/topic/4091/excel-reports-post-processing-script-question/7

    If there's any documentation on these objects, available source code, or a way to get them to show up in the developer console instead of as text in the script output that would be helpful. I haven't been able to locate the source code for the Excel reporting.

    I have the code I need to do any kind of conversion on the timestamps, I really just can't figure out what to key off of for my loop. I also can't reference the variable name for the timestamps. Only the points have variables. Any help is appreciated.

    posted in User help read more
  • G gresler_nec

    Is there a way to upgrade a MangoES device running version 3.2.2 without an internet connection? We have a few MangoES devices at sites that have very limited internet access, but the offline update feature is in Mango 3.4. Is this something that can still be accomplished maybe with the old Mango 2 pages or other means?

    posted in MangoES Hardware read more