API Docs for: 2.0.0

public/src/pointer.js

// SAGE2 is available for use under the SAGE2 Software License
//
// University of Illinois at Chicago's Electronic Visualization Laboratory (EVL)
// and University of Hawai'i at Manoa's Laboratory for Advanced Visualization and
// Applications (LAVA)
//
// See full text, terms and conditions in the LICENSE.txt included file
//
// Copyright (c) 2014

"use strict";

/**
 * @module client
 * @submodule Pointer
 */

/**
 * Graphical representation of a pointer, using Snap.svg and SVG
 *
 * @class Pointer
 * @constructor
 */
function Pointer() {

	// Variable definitions
	this.div                = null;
	this.snap               = null;
	this.pointerIcon        = null;
	this.pointerIconLoaded  = null;
	this.appModeIcon        = null;
	this.appModeIconLoaded  = null;
	this.winModeIcon        = null;
	this.winModeIconLoaded  = null;
	this.labelBG            = null;
	this.labelText          = null;
	this.color              = null;
	this.sourceType         = null;
	this.labelBGWidth       = null;

	/**
	* Init method, creates a div to attach Snap rendering into it
	*
	* @method init
	* @param id {String} id of the div supporting the pointer
	* @param label {String} label for the username
	* @param color {String} color for the pointer
	* @param width {Number} width in pixel
	* @param height {Number} height in pixel
	*/
	this.init = function(id, label, color, width, height) {
		this.div  = document.getElementById(id);
		this.snap = new Snap(width, height);
		this.div.appendChild(this.snap.node);

		this.color = color;
		this.mode  = 0;

		var pointerIconSize    = Math.round(height * 0.65);
		var pointerIconX       = Math.round(height * 0.25);
		var pointerIconY       = Math.round(height * 0.20);
		this.pointerIconLoaded = false;

		var winModeIconSize    = Math.round(height * 0.330);
		var winModeIconX       = Math.round(height * 0.0925);
		var winModeIconY       = Math.round(height * 0.044167);
		this.winModeIconLoaded = false;

		var appModeIconSize    = Math.round(height * 0.330);
		var appModeIconX       = Math.round(height * 0.0925);
		var appModeIconY       = Math.round(height * 0.044167);
		this.appModeIconLoaded = false;

		// Keep a copy of icon size to update width of snap
		this.iconWidth = pointerIconSize;

		var labelBGX = Math.round(height * 0.40);
		var labelBGY = Math.round(height * 0.65);
		var labelTextX    = Math.round(height * 0.5425);
		var labelTextY    = Math.round(height * 0.8475);
		var labelTextSize = Math.round(0.17 * height);
		var labelBGHeight = Math.round(height * 0.275);
		this.labelBGWidth = Math.round(height * 1.00);

		var _this = this;

		Snap.load("images/SAGE2 Pointer Arrow.svg", function(f) {
			_this.pointerIcon = f.select("svg");
			_this.pointerIcon.attr({
				id: "pointerIcon",
				x: pointerIconX,
				y: pointerIconY,
				width: pointerIconSize,
				height: pointerIconSize,
				preserveAspectRatio: "xMinYMin meet"
			});
			// add the loaded element into the SVG graph
			_this.snap.append(_this.pointerIcon);
			// mark it as loaded
			_this.pointerIconLoaded = true;
			// if both icons loaded, update colors
			if (_this.winModeIconLoaded === true && _this.appModeIconLoaded) {
				_this.updateIconColors();
			}
		});

		Snap.load("images/SAGE2 Window Manipulation.svg", function(f) {
			_this.winModeIcon = f.select("svg");
			_this.winModeIcon.attr({
				id: "winModeIcon",
				x: winModeIconX,
				y: winModeIconY,
				width: winModeIconSize,
				height: winModeIconSize,
				preserveAspectRatio: "xMinYMin meet"
			});
			// add the loaded element into the SVG graph
			_this.snap.prepend(_this.winModeIcon);
			// mark it as loaded
			_this.winModeIconLoaded = true;
			// if both icons loaded, update colors
			if (_this.pointerIconLoaded === true && _this.appModeIconLoaded === true) {
				_this.updateIconColors();
			}
		});

		Snap.load("images/SAGE2 Application Interaction.svg", function(f) {
			_this.appModeIcon = f.select("svg");
			_this.appModeIcon.attr({
				id: "appModeIcon",
				x: appModeIconX,
				y: appModeIconY,
				width: appModeIconSize,
				height: appModeIconSize,
				preserveAspectRatio: "xMinYMin meet"
			});

			_this.snap.prepend(_this.appModeIcon);

			_this.appModeIconLoaded = true;
			if (_this.pointerIconLoaded === true && _this.winModeIconLoaded === true) {
				_this.updateIconColors();
			}
		});

		// Black background, transparent
		this.labelBG = this.snap.rect(labelBGX, labelBGY, this.labelBGWidth, labelBGHeight, labelBGHeight / 2, labelBGHeight / 2);
		this.labelBG.attr({
			fill: "rgba(0, 0, 0, 0.6)"
		});

		// Arimo: SAGE2 "official" font
		this.labelText = this.snap.text(labelTextX, labelTextY, label).attr({
			fill: "#FFFFFF",
			fontSize: labelTextSize + "px",
			fontFamily: "Arimo"
		});

		// Get the size of the text and padding
		this.labelBGWidth = this.labelText.node.getBoundingClientRect().width + labelBGHeight;
		this.labelBG.attr({width: this.labelBGWidth});
		// Update width of parent SVG (snap)
		this.snap.attr({width: this.labelBGWidth + this.iconWidth});
	};

	/**
	* Change the color of the pointer
	*
	* @method setColor
	* @param color {String} color for the pointer
	*/
	this.setColor = function(color) {
		this.color = color;
		this.updateIconColors();
	};

	/**
	* Change the label of the pointer (user name)
	*
	* @method setLabel
	* @param label {String} label for the username
	*/
	this.setLabel = function(label) {
		this.labelText.attr({text: label});
		var labelBGHeight = Math.round(this.snap.node.getBoundingClientRect().height * 0.275);
		// Get the size of the text and padding
		this.labelBGWidth = this.labelText.node.getBoundingClientRect().width + labelBGHeight;
		this.labelBG.attr({width: this.labelBGWidth});
		// Update width of parent SVG (snap)
		this.snap.attr({width: this.labelBGWidth + this.iconWidth});
	};

	/**
	* Change the type of pointer: touch, mouse, ...
	*
	* @method setSourceType
	* @param type {String} new type of pointer
	*/
	this.setSourceType = function(type) {
		this.sourceType = type;
		this.updateIconColors();
	};

	/**
	* Switch between window manipulation and application interaction
	*
	* @method changeMode
	* @param mode {Number} new pointer mode: 0 window manipulation, 1 application interaction
	*/
	this.changeMode = function(mode) {
		this.mode = mode;
		this.updateIconColors();
	};

	/**
	* Recalculate the boxe around the pointer label
	*
	* @method updateBox
	* @param scale {Number} new scale for client -1
	*/
	this.updateBox = function(scale) {
		this.labelBG.attr({width: this.labelBGWidth / scale});
	};

	/**
	* Update the colors based on mode and type
	*
	* @method updateIconColors
	*/
	this.updateIconColors = function() {
		if (this.sourceType === "Touch") {
			if (this.pointerIconLoaded) {
				this.colorSVG(this.pointerIcon, "#000000", this.color);
			}
			if (this.winModeIconLoaded) {
				this.colorSVG(this.winModeIcon, "#000000", this.color);
			}
			if (this.appModeIconLoaded) {
				this.colorSVG(this.appModeIcon, "#000000", this.color);
			}

			// window manipulation
			if (this.mode === 0) {
				if (this.pointerIconLoaded) {
					this.pointerIcon.attr({display: "none"});
				}
				if (this.winModeIconLoaded) {
					this.winModeIcon.attr({display: ""});
				}
				if (this.appModeIconLoaded) {
					this.appModeIcon.attr({display: "none"});
				}
				this.labelText.attr({display: "none"});
				this.labelBG.attr({display: "none"});
			} else if (this.mode === 1) {
				// application interaction
				if (this.pointerIconLoaded) {
					this.pointerIcon.attr({display: "none"});
				}
				if (this.winModeIconLoaded) {
					this.winModeIcon.attr({display: "none"});
				}
				if (this.appModeIconLoaded) {
					this.appModeIcon.attr({display: ""});
				}
				this.labelText.attr({display: "none"});
				this.labelBG.attr({display: "none"});
			}
		} else {
			if (this.pointerIconLoaded) {
				this.colorSVG(this.pointerIcon, "#000000", this.color);
			}
			if (this.winModeIconLoaded) {
				this.colorSVG(this.winModeIcon, "#000000", "#FFFFFF");
			}
			if (this.appModeIconLoaded) {
				this.colorSVG(this.appModeIcon, "#000000", "#FFFFFF");
			}

			// window manipulation
			if (this.mode === 0) {
				if (this.winModeIconLoaded) {
					this.winModeIcon.attr({display: ""});
				}
				if (this.appModeIconLoaded) {
					this.appModeIcon.attr({display: "none"});
				}
			} else if (this.mode === 1) {
				// application interaction
				if (this.winModeIconLoaded) {
					this.winModeIcon.attr({display: "none"});
				}
				if (this.appModeIconLoaded) {
					this.appModeIcon.attr({display: "none"});
				}
			}

		}
	};

	/**
	* Utility function to modify the color of SVG elememts
	*
	* @method colorSVG
	* @param svg {Object} svg element
	* @param stroke {Object} stroke color
	* @param fill {Object} fill color
	*/
	this.colorSVG = function(svg, stroke, fill) {
		var rects = svg.selectAll("rect");
		if (rects) {
			rects.attr({fill: fill, stroke: stroke});
		}
		var circles = svg.selectAll("circle");
		if (circles) {
			circles.attr({fill: fill, stroke: stroke});
		}
		var ellipses = svg.selectAll("ellipse");
		if (ellipses) {
			ellipses.attr({fill: fill, stroke: stroke});
		}
		var polygons = svg.selectAll("polygon");
		if (polygons) {
			polygons.attr({fill: fill, stroke: stroke});
		}
		var paths = svg.selectAll("path");
		if (paths) {
			paths.attr({fill: fill, stroke: stroke});
		}
	};

}