var webmap = webmap || {}; webmap.modules.map = {}; /// Namespace for map modules. /// Create a new webmap. /** * \param container A reference to the container element. * \param canvas_width The width of the canvas. * \param canvas_height The width of the canvas. */ webmap.Map = function(container, canvas_width, canvas_height) { // Call parent constructor. webmap.Extendable.call(this, webmap.modules.map); // Copy parameters. this.container = container; this.canvas_width = canvas_width; this.canvas_height = canvas_height; this.selected = null; // Create the SVG root element. this.root = document.createElementNS(webmap.svgns, "svg"); this.root.setAttribute("version", 1.1); this.root.setAttribute("baseProfile", "tiny"); this.root.setAttribute("class", "webmap"); this.root.setAttribute("width", this.canvas_width); this.root.setAttribute("height", this.canvas_height); this.root = this.container.appendChild(this.root); this.root.webmap = this; // Create a reference point outside of the transformed group. this.ref_rect = document.createElementNS(webmap.svgns, "rect"); this.ref_rect.setAttribute("id", "ref_rect"); this.ref_rect.setAttribute("x", 0); this.ref_rect.setAttribute("y", 0); this.ref_rect.width = this.root.width; this.ref_rect.height = this.root.height; this.ref_rect.setAttribute("fill", "none"); this.ref_rect.setAttribute("stroke", "none"); this.ref_rect = this.root.appendChild(this.ref_rect); // Create the world group this.world = document.createElementNS(webmap.svgns, "g"); this.world.setAttribute("id", "world"); this.world = this.root.appendChild(this.world); // Create initial view and virtual map transform. this.world_tf = this.root.createSVGMatrix().translate(this.canvas_width * 0.5, this.canvas_height * 0.5).scaleNonUniform(1, -1); this.applyView(); this.mouseClickListener = this.mouseClick.bind(this); this.root.addEventListener("click", this.mouseClickListener, false); } webmap.extend(webmap.Extendable, webmap.Map); /// Get the bounding rectangle of the SVG viewport. /** * Returned coordinates are relative to the parent viewport. */ webmap.Map.prototype.getBoundingRect = function() { return this.ref_rect.getBoundingClientRect(); } /// Add an image to the map. /** * \param iri The IRI identifying the image. * \param angle The rotation of the image in degrees. * \param x The X coordinate of the bottom left corner of the image. * \param y The Y coordinate of the bottom left corner of the image. * \param width The virtual width of the image. * \param height The virtual width of the image. * \return The created image. */ webmap.Map.prototype.addImage = function(iri, x, y, width, height) { var img = document.createElementNS(webmap.svgns, "image"); img.setAttributeNS(webmap.xlinkns, "href", iri); img.setAttribute("width", width); img.setAttribute("height", height); img.setAttribute("preserveAspectRatio", "none"); img.setAttribute("viewbox", "defer"); img.setAttribute("x", 0); img.setAttribute("y", 0); var tf = this.root.createSVGMatrix() .translate(x, y) .translate(width * 0.5, height * 0.5) .scaleNonUniform(1, -1) // Flip the Y axis to correct for the right handed coordinate system. .translate(width * -0.5, height * -0.5) img.transform.baseVal.initialize(img.transform.baseVal.createSVGTransformFromMatrix(tf)); this.world.appendChild(img); return img; } /// Remove an image from the map. /** * \param img The image to remove, as returned from addImage(). */ webmap.Map.prototype.removeImage = function(img) { if (img.parentNode === this.world) this.world.removeChild(img); } /// Add a robot to the map. /** * \param robot The robot to add. */ webmap.Map.prototype.addRobot = function(robot) { if (robot.map && robot.map !== this) { robot.map.removeRobot(robot); } else if (robot.map === this) { return; } robot.map = this; this.world.appendChild(robot.svg); this.notifyModules("onAddRobot", robot); } /// Remove a robot from the map. /** * \param robot The robot to remove. * \return True if the robot was on the map and has been removed, false otherwise. */ webmap.Map.prototype.removeRobot = function(robot) { if (!robot.map || robot.map !== this) return false; if (robot.svg.parentNode) robot.svg.parentNode.removeChild(robot.svg); this.notifyModules("onRemoveRobot", robot); return true; } /// Change the selected robot. /** * \param robot The robot to select. */ webmap.Map.prototype.setSelected = function(robot) { if (this.selected) this.selected.setSelected(false); this.selected = robot; if (this.selected) this.selected.setSelected(true); /// Notify all interested modules. this.notifyModules("onSelect"); } /// Apply world transforms. /** * Changing the view allows you to zoom in/out on parts of the map, * and to rotate the map. */ webmap.Map.prototype.applyView = function() { this.world.transform.baseVal.initialize(this.world.transform.baseVal.createSVGTransformFromMatrix(this.world_tf)); } /// Translate the world. /** * \param x The X offset to translate by. * \param y The Y offset to translate by. */ webmap.Map.prototype.translate = function(x, y) { this.world_tf = this.root.createSVGMatrix().translate(x, y).multiply(this.world_tf); this.applyView(); } /// Scale the world around a viewport point. /** * \param factor The factor to scale by. * \param x The X coordinate of the viewport point to use as center. * \param y The Y coordinate of the viewport point to use as center. */ webmap.Map.prototype.scale = function(factor, x, y) { if (x == undefined) x = this.map.canvas_width * 0.5; if (y == undefined) y = this.map.canvas_height * 0.5; this.world_tf = this.root.createSVGMatrix().translate(x - x * factor, y - y * factor).scale(factor).multiply(this.world_tf); this.applyView(); } /// Rotate the world around a given point. /** * \param angle The angle to rotate by. * \param x The X coordinate of the viewport point to use as center. * \param y The Y coordinate of the viewport point to use as center. */ webmap.Map.prototype.rotate = function(angle, x, y) { this.world_tf = this.root.createSVGMatrix().translate(x, y).rotate(angle).translate(-x, -y).multiply(this.world_tf); this.applyView(); } /// Handle mouse clicks. webmap.Map.prototype.mouseClick = function(event) { // Clear the selection. this.setSelected(null); }