GpsGate Server JavaScript API

Map  1.0.0

GpsGate Server JavaScript API > Map > marker.js (source view)
Search:
 
Filters
/**
 * Copyright Franson Technology AB, Sweden, 2009
 * http://gpsgate.com, http://franson.com
 *
 * author Fredrik Blomqvist
 *
 * @module Map
 *
 */

/*
 * todo: create a MultiIconMaker? specify several images than can either be changed depending on state and/or
 * changed based on direction param. (in case user doesn't want to use vector graphics)
 */

var Franson = Franson || {};
/*
 * namespace
 * //class Franson.Map
 * //static
 */
Franson.Map = Franson.Map || {};


/**
 * note that you should (in general) not use this to set params but rather
 * use a literal. Your literal will then be merged with these defaults.
 * (mostly a test to see howto document optionals)
 * todo: if ok use this object as default-template in constructor also
 * literal
 * @class Franson.Map.Marker.options
 */
Franson.Map.Marker.options =
{
	/**
	 * @config title
	 * @type string
	 * @default null
	 */
	title: null,
	/**
	 * @config clickable
	 * @type boolean
	 * @default true
	 */
	clickable: true,
	/**
	 * @config draggable
	 * @type boolean
	 * @default false
	 */
	draggable: false,

	hide: false

	// ....
};


/**
 * basic marker, interface similar to <a href="http://code.google.com/apis/maps/documentation/reference.html#GMarker">GMarker</a> <br />
 * (todo: could actually mimic almost all of GMarker interface for convenience)
 * todo: make this into a baseclass for inheritance?
 * todo: create an isMarkerLike validator? (decide on minimal interface (and create a BaseMarker or IMarker?))
 * @param {LatLng} latlng
 * @param {Franson.Map.Marker.options} [options] see <a href="Franson.Map.Marker.options.html">default options</a>
 * @config title
 * @config clickable
 * @class Franson.Map.Marker
 * @extends Franson.Map.IOverlay
 * @constructor
 */
Franson.Map.Marker = function(latlng, options)
{
	/**
	 * @private
	 * @type LatLng
	 */
	this._latlng = latlng;

	// todo: document
	this._options = MochiKit.Base.setdefault(options, {
		icon: null, // null means create default icon. string means image url. (todo: hmm, detect html-Image obj? so user can specify click-regions etc)
		anchor: { x: 0, y: 0 }, // only really necessary if using bitmap icon (icon = 'url' above) (todo: if using this I guess we could just as well apply it to all icons?)
		title: null, // string
		hide: false, // initially hidden?
		clickable: true, // todo: if using delayed attachment this is not necesary!  (though it might be used if we want(not) to get overlays in the surface's click event?)
		draggable: false
		// color, style etc?
	});

	/**
	 * @private
	 * @type dojox.gfx.Shape
	 */
	this._icon = this._options.icon;

	/**
	 * @private
	 */
	this._clickHandler = null;

	/**
	 * @private
	 */
	this._dragHandlers = null;

	/**
	 * @private
	 * @type Franson.Map.ILayer
	 */
	this._layer = null;

	/**
	 * @private
	 * @type boolean
	 */
	this._hidden = false;

}; // Franson.Map.Marker


// methods
Franson.Map.Marker.prototype =
{
	/**
	 * destructor
	 * @method destroy
	 */
	destroy: function()
	{
		this.remove();
		disconnectAll(this);
		this._icon = null;
		this._layer = null;
	},

	/**
	 * @method getIcon
	 * @return {dojox.gfx.Shape}
	 */
	getIcon: function()
	{
		return this._icon;
	},

	// setIcon?

	/**
	 * @method getTitle
	 * @return {string}
	 */
	getTitle: function()
	{
		return this._options.title;
	},

	/**
	 * @method hide
	 */
	hide: function()
	{
		if (!this._hidden)
		{
			this._hidden = true;
			Franson.Graphics.hide(this._icon);
		}
		// let this always fire
		signal(this, 'onvisibilitychanged', false);
	},

	/**
	 * @method show
	 */
	show: function()
	{
		if (this._hidden)
		{
			this._hidden = false;
			Franson.Graphics.show(this._icon);
		}
		// let this always fire
		signal(this, 'onvisibilitychanged', true);
	},

	/**
	 * @method isHidden
	 * @return {boolean}
	 */
	isHidden: function()
	{
		return this._hidden;
		// return Franson.Graphics.isHidden(this._icon);
	},

	/**
	 * get the position
	 * @method getLatLng
	 * @return {LatLng}
	 */
	getLatLng: function()
	{
		return this._latlng;
	},

	/**
	 * set the position
	 * @method setLatLng
	 * @param {LatLng} latlng
	 */
	setLatLng: function(latlng)
	{
		this._latlng = latlng;

		if (this._layer !== null) // can't issue a redraw if not initialize() has been called
			this.redraw(true);
	},

	// todo: isDraggable etc?

	/**
	 * @method initialize
	 * @param {Franson.Map.ILayer} layer
	 * @protected
	 */
	initialize: function(layer)
	{
		this._layer = layer;

		if (this._options.icon == null)
		{
			// create default icon
			this._options.icon = this._icon = Franson.Graphics.Shape.createPinIcon(null, this._layer.getRoot()); // last param is only for the IE case...
		}
		else if (typeof(this._options.icon) == 'string')
		{
			// or skip overwriting options.icon in this case?
			this._options.icon = this._icon = Franson.Graphics.Shape.createBitmapIcon(this._options.icon, this._options.anchor, this._layer.getRoot()); // last param is only for the IE case...
		}

		//this._layer.getRoot().add(this._icon);

		if (this._options.title !== null)
			Franson.Graphics.setTitle(this._icon, this._options.title);

		if (this._options.clickable)
		{
			Franson.Graphics.setCursor(this._icon, Franson.Util.isIE() ? 'hand' : 'pointer');

			this._clickHandler = this._icon.connect('onclick', this, function(e)
			{
				this._icon.moveToFront(); // ok?
				signal(this, 'onclick', this._latlng);
			});
		}

		// todo: expose methods to enable/disable drag-mode also?
		if (this._options.draggable)
		{
			// todo: implement the google-style helper cross below the marker if we want to be fancy.

			var moveHandle = Franson.Graphics.enableMoveable(this._icon); // todo: fwd events from moving to be able to update the latlng + support dynamic enabling/disabling of draggable mode

			this._dragHandlers = [
				dojo.connect(moveHandle, 'onMoveStart', this, function()
				{
					signal(this, 'ondragstart', this._latlng);
				}),

				dojo.connect(moveHandle, 'onMove', this, function()
				{
					var pix = Franson.Graphics.getPosition(this._icon);

					var prj = this._layer.getProjection();
					var newLatLng = prj.fromDivPixelToLatLng(pix);
					this._latlng = newLatLng;

					signal(this, 'ondrag', this._latlng);
				}),

				dojo.connect(moveHandle, 'onMoveStop', this, function()
				{
					signal(this, 'ondragend', this._latlng);
				})
			];
		}

		if (this._options.hide)
			this.hide();
	},

	/**
	 * @method redraw
	 * @param {boolean} [force=false]
	 * @protected
	 */
	redraw: function(force)
	{
		if (force && !this._hidden)
		{
			if (this._layer.getSurface()._getCullBounds().containsLatLng(this._latlng)) // todo: better culling
			{
				var pos = this._layer.getProjection().fromLatLngToDivPixel(this._latlng);
				Franson.Graphics.setPosition(this._icon, pos);
				Franson.Graphics.show(this._icon);
			}
			else
			{
				Franson.Graphics.hide(this._icon);
			}
		}
	},

	/**
	 * note that you should(must) not call this directly,
	 * rather use <code>map.removeOverlay(marker)</code> (which will call this)
	 * see <a href="http://code.google.com/apis/maps/documentation/reference.html#GOverlay.remove">GOverlay.remove()</a>
	 * @method remove
	 * @protected
	 */
	remove: function()
	{
		if (this._icon)
		{
			if (this._clickHandler != null)
			{
				this._icon.disconnect(this._clickHandler);
				this._clickHandler = null;
			}

			if (this._dragHandlers != null)
			{
				forEach(this._dragHandlers, dojo.disconnect);
				this._dragHandlers = null;
			}

			if (this._options.draggable)
			{
				Franson.Graphics.disableMoveable(this._icon);
			}

			this._icon.removeShape();

			signal(this, 'onremove');
		}
	}

}; // Franson.Map.Marker.prototype


/**
 * (if options.clickable)
 * @event onclick
 * @param {LatLng} latlng
 */

/**
 * (if options.draggable)
 * @event ondragstart
 * @param {LatLng} latlng
 */

/**
 * (if options.draggable)
 * @event ondrag
 * @param {LatLng} latlng
 */

/**
 * (if options.draggable)
 * @event ondragend
 * @param {LatLng} latlng
 */

/**
 * fired in <a href="#method_show">show()</a> and <a href="#method_hide">hide()</a> <br />
 * see <a href="http://code.google.com/apis/maps/documentation/reference.html#GMarker.visibilitychanged">GMarker.visibilitychanged</a>
 * @event onvisibilitychanged
 * @param {boolean} visible
 */

/**
 * fired in <a href="#method_remove">remove()</a>
 * @event onremove
 */

// todo: expose more click-events? dblclick etc

Copyright © 2009 Franson Technology AB, Sweden. All rights reserved.