ka-Map

kaTool.js

Summary

No overview generated for 'kaTool.js'


Class Summary
kaNavigator kaNavigator is a general purpose navigation tool for kaMap instances.
kaTool kaTool API.
An API for building tools that work with kaMap.

Method Summary
static Object bind(m,o)
          
static void kaTool_redirect_onkeypress(e)
          

/**********************************************************************
 *
 * $Id: kaTool.js,v 1.34 2006/10/19 02:36:28 pspencer Exp $
 *
 * purpose: an API for kaMap tools with a default navigation tool provided
 *
 * author: Paul Spencer (pspencer@dmsolutions.ca)
 *
 * The original kaTool code was written by DM Solutions Group.
 *
 * TODO:
 * 
 **********************************************************************
 *
 * Copyright (c) 2005, DM Solutions Group Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
 * DEALINGS IN THE SOFTWARE.
 *
 **********************************************************************/

/*
 * includes code inspired by code in WindowManager.js
 * Copyright 2005 MetaCarta, Inc., released under the BSD License
 */

//globally 
var kaCurrentTool = null;

/**
 * @class
 * kaTool API.<br>
 * An API for building tools that work with kaMap.
 * To create a new tool, you need to have included this file first.  Next
 * create a function to instantiate your new tool.  All object construction
 * functions must include a parameter that references the kaMap object on which
 * they operate.<br>
 * The object construction function must call the kaTool constructor using the
 * following syntax:<br><br>
 * kaTool.apply( this, [oKaMap] );<br><br>
 * where oKaMap is the name of the parameter to the constructor function.
 * You should then set the tool's name (this.name) and overload any functions
 * for mouse handling etc.
 *
 * @constructor kaTool
 * kaTool is the base class for tools which operate on an instance of kaMap.
 * @param {Object} oKaMap the instance of kaMap on which this tool should operate
 */
function kaTool( oKaMap ) {
    /** the instance of kaMap on which this tool operates */
    this.kaMap = oKaMap;
    /** the name of this tool */
    this.name = 'kaTool';
    /** info tools get all events all the time */
    this.bInfoTool = false;
    
    // Default for mouse wheel: zoom in or out. (Mod D Badke)
    this.wheelPlus = new Array(oKaMap, oKaMap.zoomOut, null);
    this.wheelMinus = new Array(oKaMap, oKaMap.zoomIn, null);
    
    this.kaMap.registerTool( this );
};

/**
 * is this an info tool or a regular tool?
 */
kaTool.prototype.isInfoTool = function() {
    return this.bInfoTool;
};

/**
 * activate this tool.  Activating the tool causes any existing tools to be
 * deactivated.
 */
kaTool.prototype.activate = function() {
    this.kaMap.activateTool( this );
    document.kaCurrentTool = this;
};

/**
 * deactivate this tool.  
 */
kaTool.prototype.deactivate = function() {
    this.kaMap.deactivateTool( this );
    document.kaCurrentTool = null;
};

/**
 * handle mouse movement over the viewport of the kaMap.  This
  * method does nothing and should be overloaded by subclasses.
 * @param {Event} e the mouse event object
 */
kaTool.prototype.onmousemove = function(e) {
    return false;
};

/**
 * handle mouse down events on the viewport of the kaMap.  This
  * method does nothing and should be overloaded by subclasses.
 * @param {Event} e the mouse event object
 */
kaTool.prototype.onmousedown = function(e) {
    return false;
};

/**
 * handle mouse up events on the viewport of the kaMap.  This
  * method does nothing and should be overloaded by subclasses.
 * @param {Event} e the mouse event object
 */
kaTool.prototype.onmouseup = function(e) {
    return false;
};

/**
 * handle mouse doubleclicks on the viewport of the kaMap.  This
 * method does nothing and should be overloaded by subclasses.
 * @param {Event} e the mouse event object
 */
kaTool.prototype.ondblclick = function(e) {
    return false;
};

/**
 * Set the object and function to call when the mouse wheel
 * event triggers. The parameters are saved in the tool object
 * this is called for, and only affect that tool.
 * 
 * @param {array} plusSet  - parameters for positive wheel scroll
 * @param {array} minusSet - parameters for negative wheel scroll
 * 
 * plusSet and minusSet are arrays of structure:
 *   [0] - object to apply function for or null
 *   [1] - function to apply
 *   [2] - function arguments or null for no arguments
 * 
 * Set minusSet and/or plusSet to null to disable that scroll direction.
 * 
 * eg: --disable mouse wheel for navigator tool:
 * 				 myKaNavigator.setMouseWheel(null, null);
 * 
 *     --set navigator tool to zoom (same as default action):
 *         myKaNavigator.setMouseWheel([myKaMap, myKaMap.zoomIn, null],
 * 					 											     [myKaMap, myKaMap.zoomOut, null]);
 * 
 * (New D Badke)
 */
kaTool.prototype.setMouseWheel = function(minusSet, plusSet) {
	this.wheelMinus = minusSet;
	this.wheelPlus = plusSet;
};

/**
 * Handle mouse wheel events over the viewport of the kaMap.  This
 * applies a function set by the setMouseWheel function. If the function
 * is null, do nothing. (Mod D Badke)
 * 
 * @param {Event} e the mouse event object
 */
kaTool.prototype.onmousewheel = function(e) {
    e = (e)?e:((event)?event:null);
    var wheelDelta = e.wheelDelta ? e.wheelDelta : e.detail*-1;
    var wheelSet = null;
    if (wheelDelta > 0) 
    	wheelSet = this.wheelMinus;
    else
    	wheelSet = this.wheelPlus;
    
  	if (wheelSet) {
  		obj = (wheelSet[0]) ? wheelSet[0] : null;
  		func = (wheelSet[1]) ? wheelSet[1] : null;
  		args = (wheelSet[2]) ? wheelSet[2] : null;
  		if (func) {
			if (args) {
				func.apply(obj, args);
			} else{
			    func.apply(obj);
			}
  		}
    }
};

/**
 * adjust a page-relative pixel position into a kaMap relative
 * pixel position
 *
 * @param {Integer} x the x page coordinate to convert
 * @param {Integer} y the y page coordinate to convert
 * @return {Array} return an array containing the converted coordinates
 */
kaTool.prototype.adjustPixPosition = function( x, y ) {
    var obj = this.kaMap.domObj;
    var offsetLeft = 0;
    var offsetTop = 0;
    while (obj) {
        offsetLeft += parseInt(obj.offsetLeft);
        offsetTop += parseInt(obj.offsetTop);
        obj = obj.offsetParent;
    }
    
    var pX = parseInt(this.kaMap.theInsideLayer.style.left) + 
             offsetLeft - this.kaMap.xOrigin - x;
    var pY = parseInt(this.kaMap.theInsideLayer.style.top) + 
             offsetTop - this.kaMap.yOrigin - y;
             
    return [pX,pY];
};

/*
 * key press events are directed to the HTMLDocument rather than the
 * div on which we really wanted them to happen.  So we set the document
 * keypress handler to this function and redirect it to the kaMap core
 * keypress handler, which will eventually reach the onkeypress handler
 * of our current tool ... which by default is the keyboard navigation.
 *
 * To get the keyboard events in the first place, add the following when you
 * want the keypress events to be captured
 *
 * if (isIE4) document.onkeydown = kaTool_redirect_onkeypress;
 * document.onkeypress = kaTool_redirect_onkeypress;
 */
function kaTool_redirect_onkeypress(e) {
    if (document.kaCurrentTool) {
        document.kaCurrentTool.onkeypress(e);
    }
};

/**
 * handle keypress events.  Keypress events are normally dispatched
 * here rather than in a sub-class.
 * @param {Event} e the keypress event object
 */
kaTool.prototype.onkeypress = function(e) {
    e = (e)?e:((event)?event:null);
    if (e) {
        var charCode=(e.charCode)?e.charCode:e.keyCode;
        var b=true;
        var nStep = 16;
        switch(charCode) {
          case 38://up
            this.kaMap.moveBy(0,nStep);
            this.kaMap.triggerEvent( KAMAP_EXTENTS_CHANGED, this.kaMap.getGeoExtents() );
            break;
          case 40:
            this.kaMap.moveBy(0,-nStep);
            this.kaMap.triggerEvent( KAMAP_EXTENTS_CHANGED, this.kaMap.getGeoExtents() );
            break;
          case 37:
            this.kaMap.moveBy(nStep,0);
            this.kaMap.triggerEvent( KAMAP_EXTENTS_CHANGED, this.kaMap.getGeoExtents() );
            break;
          case 39:
            this.kaMap.moveBy(-nStep,0);
            this.kaMap.triggerEvent( KAMAP_EXTENTS_CHANGED, this.kaMap.getGeoExtents() );
            break;
          case 33:
            this.kaMap.slideBy(0, this.kaMap.viewportHeight/2);
            break;
          case 34:
            this.kaMap.slideBy(0,-this.kaMap.viewportHeight/2);
            break;
          case 36:
            this.kaMap.slideBy(this.kaMap.viewportWidth/2,0);
            break;
          case 35:
            this.kaMap.slideBy(-this.kaMap.viewportWidth/2,0);
            break;
          case 43: //ascii +
          case 61: //ascii =
            this.kaMap.zoomIn();
            break;
         case 45:
            this.kaMap.zoomOut();
            break;
          default:
            b=false;
        }
        if (b) {
            return this.cancelEvent(e);
        }
        return true;
    }
};

/**
 * handle the mouse moving over the kaMap viewport.  This is a method does
 * nothing and should be overloaded in a subclass
 * @param {Event} e the mouse event
 */
kaTool.prototype.onmouseover = function(e) {
    return false;
};

/**
 * handle the mouse leaving the kaMap viewport.  This is a method
 * releases the keypress handler and should be called from any
 * sub class that overloads this method.
 * @param {Event} e the mouse event
 */
kaTool.prototype.onmouseout = function(e) {
    if (this.kaMap.isIE4) {
        document.onkeydown = null;
    }
    document.onkeypress = null;
    return false;
};

/**
 * provide a cross-platform method of cancelling events, including
 * stopping of event bubbling and propagation.
 * @param {Event} e the event to cancel
 */
kaTool.prototype.cancelEvent = function(e) {
    e = (e)?e:((event)?event:null);
    e.cancelBubble = true;
    e.returnValue = false;
    if (e.stopPropogation) {
        e.stopPropogation();
    }
    if (e.preventDefault) {
        e.preventDefault();
    }
    return false;
};

/**
 * Construct a new kaNavigator instance on a given kaMap instance
 *
 * @class
 * kaNavigator is a general purpose navigation tool for kaMap instances.
 * It provides panning through click-and-drag, and various keyboard
 * navigation.
 *
 * @base kaTool
 * @constructor
 * @param {Object} oKaMap the kaMap instance to provide navigation for
 * @author Paul Spencer
 */
function kaNavigator( oKaMap ) {
    kaTool.apply( this, [oKaMap] );
    /** the name of this tool */
    this.name = 'kaNavigator';
    /** the cursor to use when the map is not being dragged */
	this.cursorNormal = ["url('images/grab.cur'),move", '-moz-grab', 'grab', 'move'];
	/** the cursor to use when the map is being dragged */
	this.cursorDrag = ["url('images/grabbing.cur'),move", '-moz-grabbing', 'grabbing', 'move'];
	/** the cursor to use over the map (by default) */
    this.cursor = this.cursorNormal;

    /** the image to use for this tool when it is active on the map */
    this.activeImage = this.kaMap.server + 'images/button_pan_3.png';

    /** the image to use for this tool when it is disabled */
    this.disabledImage = this.kaMap.server + 'images/button_pan_2.png';
    
    /** track the last x position of the mouse for panning */
    this.lastx = null;
    /** track the last y position of the mouse for panning */
    this.lasty = null;
    /** track whether the mouse is down or up for panning support */
    this.bMouseDown = false;
    
    for (var p in kaTool.prototype) {
        if (!kaNavigator.prototype[p])
            kaNavigator.prototype[p]= kaTool.prototype[p];
    }
};

/**
 * handle the mouse leaving the viewport.  If the mouse is down, stop
 * dragging.
 * @param {Event} e the mouse event object
 */
kaNavigator.prototype.onmouseout = function(e) {
	e = (e)?e:((event)?event:null);
    if (!e.target) e.target = e.srcElement;
    if (e.target.id == this.kaMap.domObj.id) {
        this.bMouseDown = false;
        return kaTool.prototype.onmouseout.apply(this, [e]);
    }
};

/**
 * handle the mouse moving inside viewport.  If the mouse is down, move
 * the map.
 * @param {Event} e the mouse event object
 */
kaNavigator.prototype.onmousemove = function(e) {
    e = (e)?e:((event)?event:null);
    
    if (!this.bMouseDown) {
        return false;
    }
    
    if (!this.kaMap.layersHidden) {
        this.kaMap.hideLayers();
    }
    var newTop = safeParseInt(this.kaMap.theInsideLayer.style.top);
    var newLeft = safeParseInt(this.kaMap.theInsideLayer.style.left);

    var x = e.pageX || (e.clientX +
          (document.documentElement.scrollLeft || document.body.scrollLeft));
    var y = e.pageY || (e.clientY +
                (document.documentElement.scrollTop || document.body.scrollTop));
    newTop = newTop - this.lasty + y;
    newLeft = newLeft - this.lastx + x;

    this.kaMap.theInsideLayer.style.top=newTop + 'px';
    this.kaMap.theInsideLayer.style.left=newLeft + 'px';

    this.kaMap.checkWrap.apply(this.kaMap, []);

    this.lastx=x;
    this.lasty=y;
    return false;
};

/**
 * handle mouse down events.  Start tracking mouse movement for panning.
 * @param {Event} e the mouse event object
 */
kaNavigator.prototype.onmousedown = function(e) {
    e = (e)?e:((event)?event:null);
    if (e.button==2) {
        return this.cancelEvent(e);
    } else {
		this.cursor = this.cursorDrag;
    	this.kaMap.setCursor(this.cursorDrag);
        if (this.kaMap.isIE4) {
            document.onkeydown = kaTool_redirect_onkeypress;
        }
        document.onkeypress = kaTool_redirect_onkeypress;
        
        this.bMouseDown=true;
        var x = e.pageX || (e.clientX +
             (document.documentElement.scrollLeft || document.body.scrollLeft));
        var y = e.pageY || (e.clientY +
             (document.documentElement.scrollTop || document.body.scrollTop));
        this.lastx=x;
        this.lasty=y;
        this.startx = this.lastx;
        this.starty = this.lasty;
        
        e.cancelBubble = true;
        e.returnValue = false;
        if (e.stopPropogation) e.stopPropogation();
        if (e.preventDefault) e.preventDefault();
        return false;
    }
};

var gDblClickTimer = null;
/**
 * handle the mouse up events.  Stop tracking mouse movement.
 * @param {Event} e the mouse event object
 */
kaNavigator.prototype.onmouseup = function(e) {
	this.cursor = this.cursorNormal;
    this.kaMap.setCursor(this.cursorNormal);
	
    e = (e)?e:((event)?event:null);
    this.bMouseDown=false;
    var x = e.pageX || (e.clientX +
        (document.documentElement.scrollLeft || document.body.scrollLeft));
    var y = e.pageY || (e.clientY +
        (document.documentElement.scrollTop || document.body.scrollTop));
    if (Math.abs(x-this.startx) < 2 &&
        Math.abs(y-this.starty) < 2) {
        if (!gDblClickTimer) {
            gDblClickTimer = window.setTimeout(bind(this.dispatchMapClicked, this, x, y), 250);
        }
    } else {
        gDblClickTimer = null;
        this.kaMap.showLayers();
        this.kaMap.triggerEvent(KAMAP_EXTENTS_CHANGED, this.kaMap.getGeoExtents());        
    }
    return false;
};

kaNavigator.prototype.dispatchMapClicked = function(px,py) {
    var a = this.adjustPixPosition( px,py );
    var p = this.kaMap.pixToGeo( a[0],a[1] );
    gDblClickTimer=null;
    this.kaMap.triggerEvent(KAMAP_MAP_CLICKED, p);
};

/**
 * handle a double-click event by sliding the map to the point that was clicked.
 * @param {Event} e the mouse event object
 */
kaNavigator.prototype.ondblclick = function(e) {
    if (gDblClickTimer) {
        window.clearTimeout(gDblClickTimer);
        gDblClickTimer = null;
    }
    e = (e)?e:((event)?event:null);
    var x = e.pageX || (e.clientX +
        (document.documentElement.scrollLeft || document.body.scrollLeft));
    var y = e.pageY || (e.clientY +
        (document.documentElement.scrollTop || document.body.scrollTop));
    var a = this.adjustPixPosition( x,y );
    var p = this.kaMap.pixToGeo( a[0], a[1] );
    this.kaMap.zoomTo(p[0],p[1]);
};

//TODO: this is a temporary patch until we add prototype/scriptaculous support.
function bind(m,o) {
    var __method = arguments[0];
    var __object = arguments[1];
    var args = [];
    for (var i=2; i<arguments.length; i++) { args.push(arguments[i]) }
    return function() { return __method.apply(__object, args); }
}

ka-Map

Documentation generated by JSDoc on Mon Feb 5 08:25:15 2007