/**
* Copyright Franson Technology AB, Sweden, 2009
* <br />
* <a href="http://gpsgate.com/">http://gpsgate.com</a>, <a href="http://franson.com/">http://franson.com</a>
* <br /><br />
* author Fredrik Blomqvist
*
* @module Map
*
*/
var Franson = Franson || {};
/*
* namespace
* //class Franson.Map
* //static
*/
Franson.Map = Franson.Map || {};
/**
* marker to be used in VT. includes textlabel and arrow marker
* todo: inherit from Marker
* todo: move to VT module
* @param {Franson.GateUser} vehicle
* @param {literal} [options]
* @class Franson.Map.VehicleMarker
* @extends Franson.Map.IOverlay
* @constructor
*/
Franson.Map.VehicleMarker = function(vehicle, options)
{
this._options = MochiKit.Base.setdefault(options, {
hide: false, // initially hidden?
markerType: 'arrow',
showText: true,
rotate: true,
getLegendText: vehicle.getName()
// todo: showTextLabel, iconType, font, fontSize, size/scale etc
});
// disable rotate for needle
this._options.rotate = this._options.markerType == 'needle' ? false : this._options.rotate;
/**
* @private @type Franson.GateUser
*/
this._vehicle = vehicle;
this._vehicle._hidden = false; // force in a visible state, hackish but ok for now.
/**
* group object that holds the arrow- and label-icon
* @private @type {dojox.gfx.Group/Shape}
*/
this._icon = null;
// children to _icon but added as members for easy access
this._arrowIcon = null;
this._nameLabel = null;
/**
* @private
*/
this._clickHandler = null;
// todo: fwd more events? (click is handled in initialize)
/**
* @private @type Franson.Map.Layer
*/
this._layer = null;
};
// methods
Franson.Map.VehicleMarker.prototype =
{
/**
* Overlay interface
* todo: not quite ok with layer structure..
* @method initialize
* @param {Franson.Map.ILayer} layer
* @protected
*/
initialize: function(layer) // similar to GMap::initialize(map)
{
this._layer = layer;
var projection = layer.getProjection();
// todo: ugly.. (move this to GateUser?)
// todo: better config of this
var color = typeof(this._vehicle.attributes["MarkerColor"]) == 'undefined' ? '#000000' : '#' + this._vehicle.attributes["MarkerColor"].value;
// group for convenience
this._icon = this._layer.getRoot().createGroup();
this._arrowIcon = this._options.markerType == 'arrow' ? Franson.Graphics.Shape.createArrowIcon(8, color, this._icon) : Franson.Graphics.Shape.createNeedleIcon(8, color, this._icon);
if (this._options.showText)
{
var bbArrow = Franson.Graphics.calcBounds(this._arrowIcon);
this._nameLabel = Franson.Graphics.Shape.createTextLabel(this._options.getLegendText(this._vehicle), {
backgroundColor: color,
// anchor to always be above the arrow (hmm, could perhaps make this dynamic depending on the arrow direction?)
anchor: { x: bbArrow.w, y: bbArrow.h-5 }
}, this._icon);
}
Franson.Graphics.setTitle(this._icon, this._vehicle.getName());
// indicate clickability
Franson.Graphics.setCursor(this._icon, Franson.Util.isIE() ? 'hand' : 'pointer');
this._clickHandler = this._icon.connect('onclick', this, function(e)
{
this._icon.moveToFront(); // or make this a logic on the client side?
var latlng = this._vehicle.getTrackPoint().pos;
signal(this, 'onclick', latlng);
});
if (this._options.hide)
this.hide();
},
/**
* @method getIcon
* @return {dojox.gfx.Shape}
*/
getIcon: function()
{
return this._icon;
},
/**
* destructor
* @method destroy
*/
destroy: function()
{
this.remove();
disconnectAll(this);
this._arrowIcon = this._nameLabel = this._icon = null;
},
/**
* Overlay interface
* @method redraw
* @param {boolean} force
* @protected
*/
redraw: function(force)
{
if (!force || this._vehicle._hidden)
return;
var tp = this._vehicle.getTrackPoint();
var cullBounds = this._layer.getSurface()._getCullBounds();
if (cullBounds.containsLatLng(tp.pos))
{
var pos = this._layer.getProjection().fromLatLngToDivPixel(tp.pos); // observe that we delay setting the position even if hidden to not crash IE/VML..
Franson.Graphics.setPosition(this._icon, pos);
if (this._options.rotate)
{
var rot = Franson.Math.degToRad(tp.vel.heading);
this._arrowIcon.setTransform(dojox.gfx.matrix.rotate(rot));
}
Franson.Graphics.show(this._icon); // not same as this.show()!
}
else
{
Franson.Graphics.hide(this._icon); // not same as this.hide()!
}
},
/**
* ok? vehicle is optional (or take just a TrackPoint?)
* @method update
* @param {Franson.GateUser} [vehicle] if not supplied uses the initially set vehicle
*/
update: function(vehicle)
{
this._vehicle = vehicle || this._vehicle;
this.redraw(true);
},
/**
* <a href="http://code.google.com/apis/maps/documentation/reference.html#GOverlay.remove">GOverlay.remove</a>
* @protected
*/
remove: function()
{
if (this._icon)
{
if (this._clickHandler != null)
{
this._icon.disconnect(this._clickHandler);
this._clickHandler = null;
}
this._icon.removeShape();
signal(this, 'onremove');
}
},
/**
* @method hide
*/
hide: function()
{
if (!this._vehicle._hidden)
{
this._vehicle._hidden = true;
Franson.Graphics.hide(this._icon);
}
// let event fire anyway
signal(this, 'onvisibilitychanged', false);
},
/**
* @method show
*/
show: function()
{
if (this._vehicle._hidden)
{
this._vehicle._hidden = false;
Franson.Graphics.show(this._icon);
this.redraw(true); // position isn't updated when hidden
}
// let event fire anyway
signal(this, 'onvisibilitychanged', true);
},
/**
* @method isHidden
* @return {boolean}
*/
isHidden: function()
{
return this._vehicle._hidden;
// return Franson.Graphics.isHidden(this._icon);
},
/**
* @method setStatus
* @param {boolean} active
*/
setStatus: function(active)
{
this._arrowIcon.setActive(active);
if (this._nameLabel != null)
this._nameLabel.setActive(active);
}
}; // Franson.Map.VehicleMarker.prototype
/**
* fired in hide() and show()
* @event onvisibilitychanged
* @param {boolean} visible
*/
/**
* fired in remove()
* @event onremove
*/
/**
* @event onclick
* @param {LatLng} latlng
*/