File: /home/eliteafr/pmb/javascript/dojo/dojo/pmbmaps.js.uncompressed.js
require({cache:{
'dojox/geo/openlayers/widget/Map':function(){
define([
"dojo/_base/lang",
"dojo/_base/declare",
"dojo/_base/array",
"dojo/dom-geometry",
"dojo/query",
"dijit/_Widget",
"../_base",
"../Map",
"../Layer",
"../GfxLayer"
], function(lang, declare, array, domgeo, query, Widget, openlayers, Map, Layer, GfxLayer){
return declare("dojox.geo.openlayers.widget.Map", Widget, {
// summary:
// A widget version of the `dojox.geo.openlayers.Map` component.
// description:
// The `dojox.geo.openlayers.widget.Map` widget is the widget
// version of the `dojox.geo.openlayers.Map` component.
// With this widget, user can specify some attributes in the markup such as
//
// - `baseLayerType`: The type of the base layer. Permitted values are
// - `initialLocation`: The initial location as for the dojox.geo.openlayers.Map.fitTo method
// - `touchHandler`: Tells if we attach touch handler or not.
//
// example:
// | <div id="map" dojoType="dojox.geo.openlayers.widget.Map" baseLayerType="Google" initialLocation="{
// | position: [7.154126, 43.651748],
// | extent: 0.2 }"
// | style="background-color: #b5d0d0; width: 100%; height: 100%;">
//
// baseLayerType: String
// Base layer type as defined in `dojox.geo.openlayer.BaseLayerType`. Can be one of:
//
// - `OSM`
// - `WMS`
// - `Google`
// - `VirtualEarth`
// - `Yahoo`
// - `ArcGIS`
baseLayerType: openlayers.BaseLayerType.OSM,
// initialLocation: String
// The part of the map shown at startup time. It is the string description of the location shown at
// startup time. Format is the same as for the `dojox.geo.openlayers.widget.Map.fitTo`
// method.
// | {
// | bounds: [ulx, uly, lrx, lry]
// | }
// The map is fit on the specified bounds expressed as decimal degrees latitude and longitude.
// The bounds are defined with their upper left and lower right corners coordinates.
//
// | {
// | position: [longitude, latitude],
// | extent: degrees
// | }
// The map is fit on the specified position showing the extent `<extent>` around
// the specified center position.
initialLocation: null,
// touchHandler: Boolean
// Tells if the touch handler should be attached to the map or not.
// Touch handler handles touch events so that the widget can be used
// on mobile applications.
touchHandler: false,
// map: [readonly] Map
// The underlying `dojox/geo/openlayers/Map` object.
map : null,
startup: function(){
// summary:
// Processing after the DOM fragment is added to the document
this.inherited(arguments);
this.map.initialFit({
initialLocation: this.initialLocation
});
},
buildRendering: function(){
// summary:
// Construct the UI for this widget, creates the real dojox.geo.openlayers.Map object.
// tags:
// protected
this.inherited(arguments);
var div = this.domNode;
var map = new Map(div, {
baseLayerType: this.baseLayerType,
touchHandler: this.touchHandler
});
this.map = map;
this._makeLayers();
},
_makeLayers: function(){
// summary:
// Creates layers defined as markup.
// tags:
// private
var n = this.domNode;
var layers = /* ?? query. */query("> .layer", n);
array.forEach(layers, function(l){
var type = l.getAttribute("type");
var name = l.getAttribute("name");
var cls = "dojox.geo.openlayers." + type;
var p = lang.getObject(cls);
if(p){
var layer = new p(name, {});
if(layer){
this.map.addLayer(layer);
}
}
}, this);
},
resize : function(b,h){
// summary:
// Resize the widget.
// description:
// Resize the domNode and the widget to the dimensions of a box of the following form:
// `{ l: 50, t: 200, w: 300: h: 150 }`
// b: Object|Number?
// If passed, denotes the new size of the widget.
// Can be either nothing (widget adapts to the div),
// an Object describing a box, or a Number representing the width.
// h: Number?
// The new height. Requires that a width has been specified in the first parameter.
var olm = this.map.getOLMap();
var box;
switch(arguments.length){
case 0:
// case 0, do not resize the div, just the surface
break;
case 1:
// argument, override node box
box = lang.mixin({}, b);
domgeo.setMarginBox(olm.div, box);
break;
case 2:
// two argument, width, height
box = {
w: arguments[0],
h: arguments[1]
};
domgeo.setMarginBox(olm.div, box);
break;
}
olm.updateSize();
}
});
});
},
'dojox/geo/openlayers/_base':function(){
define(["dojo/_base/lang"], function(lang){
var openlayers = lang.getObject("dojox.geo.openlayers", true);
/*===== openlayers = dojox.geo.openlayers; =====*/
openlayers.BaseLayerType = {
// summary:
// Defines the base layer types to be used at Map construction time or
// with the setBaseLayerType function.
// description:
// This object defines the base layer types to be used at Map construction
// time or with the setBaseLayerType function.
// OSM: String
// The Open Street Map base layer type selector.
OSM: "OSM",
// Transport: String
// The Open Cycle Map transport layer type selector.
Transport: "OSM.Transport",
// WMS: String
// The Web Map Server base layer type selector.
WMS: "WMS",
// GOOGLE: String
// The Google base layer type selector.
GOOGLE: "Google",
// VIRTUAL_EARTH: String
// The Virtual Earth base layer type selector.
VIRTUAL_EARTH: "VirtualEarth",
// BING: String
// Same as Virtual Earth
BING: "VirtualEarth",
// YAHOO: String
// The Yahoo base layer type selector.
YAHOO: "Yahoo",
// ARCGIS: String
// The ESRI ARCGis base layer selector.
ARCGIS: "ArcGIS"
};
openlayers.EPSG4326 = new OpenLayers.Projection("EPSG:4326");
var re = /^\s*(\d{1,3})[D°]\s*(\d{1,2})[M']\s*(\d{1,2}\.?\d*)\s*(S|"|'')\s*([NSEWnsew]{0,1})\s*$/i;
openlayers.parseDMS = function(v, toDecimal){
// summary:
// Parses the specified string and returns degree minute second or decimal degree.
// description:
// Parses the specified string and returns degree minute second or decimal degree.
// v: String
// The string to parse
// toDecimal: Boolean
// Specifies if the result should be returned in decimal degrees or in an array
// containing the degrees, minutes, seconds values.
// returns: Float|Array
// the parsed value in decimal degrees or an array containing the degrees, minutes, seconds values.
var res = re.exec(v);
if(res == null || res.length < 5){
return parseFloat(v);
}
var d = parseFloat(res[1]);
var m = parseFloat(res[2]);
var s = parseFloat(res[3]);
var nsew = res[5];
if(toDecimal){
var lc = nsew.toLowerCase();
var dd = d + (m + s / 60.0) / 60.0;
if(lc == "w" || lc == "s"){
dd = -dd;
}
return dd;
}
return [d, m, s, nsew];
};
return openlayers;
});
},
'dojox/geo/openlayers/Map':function(){
define([
"dojo/_base/kernel",
"dojo/_base/declare",
"dojo/_base/lang",
"dojo/_base/array",
"dojo/_base/json",
"dojo/dom",
"dojo/dom-style",
"./_base",
"./TouchInteractionSupport",
"./Layer",
"./Patch"
], function(kernel, declare, lang, array, json, dom, style, openlayers, TouchInteractionSupport, Layer, Patch){
kernel.experimental("dojox.geo.openlayers.Map");
Patch.patchGFX();
/*=====
dojox.geo.openlayers.__MapArgs = {
// summary:
// The keyword arguments that can be passed in a Map constructor.
// baseLayerType: String
// type of the base layer. Can be any of
//
// - `dojox.geo.openlayers.BaseLayerType.OSM`: Open Street Map base layer
// - `dojox.geo.openlayers.BaseLayerType.Transport`: Open Street Map Transport base layer (opencyclemap.org)
// - `dojox.geo.openlayers.BaseLayerType.WMS`: Web Map Service layer
// - `dojox.geo.openlayers.BaseLayerType.GOOGLE`: Google layer
// - `dojox.geo.openlayers.BaseLayerType.VIRTUAL_EARTH`: Virtual Earth layer
// - `dojox.geo.openlayers.BaseLayerType.BING`: Bing layer
// - `dojox.geo.openlayers.BaseLayerType.YAHOO`: Yahoo layer
// - `dojox.geo.openlayers.BaseLayerType.ARCGIS`: ESRI ArgGIS layer
// baseLayerName: String
// The name of the base layer.
// baseLayerUrl: String
// Some layer may need an url such as Web Map Server.
// baseLayerOptions: String
// Additional specific options passed to OpensLayers layer, such as The list of layer to display, for Web Map Server layer.
};
=====*/
return declare("dojox.geo.openlayers.Map", null, {
// summary:
// A map viewer based on the OpenLayers library.
//
// description:
// The `dojox.geo.openlayers.Map` object allows to view maps from various map providers.
// It encapsulates an `OpenLayers.Map` object on which most operations are delegated.
// GFX layers can be added to display GFX georeferenced shapes as well as Dojo widgets.
// Parameters can be passed as argument at construction time to define the base layer
// type and the base layer parameters such as url or options depending on the type
// specified. These parameters can be any of:
//
// _baseLayerType_: type of the base layer. Can be any of:
//
// - `dojox.geo.openlayers.BaseLayerType.OSM`: Open Street Map base layer
// - `dojox.geo.openlayers.BaseLayerType.Transport`: Open Street Map Transport base layer (opencyclemap.org)
// - `dojox.geo.openlayers.BaseLayerType.WMS`: Web Map Service layer
// - `dojox.geo.openlayers.BaseLayerType.GOOGLE`: Google layer
// - `dojox.geo.openlayers.BaseLayerType.VIRTUAL_EARTH`: Virtual Earth layer
// - `dojox.geo.openlayers.BaseLayerType.BING`: Bing layer
// - `dojox.geo.openlayers.BaseLayerType.YAHOO`: Yahoo layer
// - `dojox.geo.openlayers.BaseLayerType.ARCGIS`: ESRI ArgGIS layer
//
// Note that access to commercial server such as Google, Virtual Earth or Yahoo may need specific licencing.
//
// The parameters value also include:
//
// - `baseLayerName`: The name of the base layer.
// - `baseLayerUrl`: Some layer may need an url such as Web Map Server
// - `baseLayerOptions`: Additional specific options passed to OpensLayers layer,
// such as The list of layer to display, for Web Map Server layer.
//
// example:
// | var map = new dojox.geo.openlayers.widget.Map(div, {
// | baseLayerType: dojox.geo.openlayers.BaseLayerType.OSM,
// | baseLayerName: 'Open Street Map Layer'
// | });
// olMap: OpenLayers.Map
// The underlying OpenLayers.Map object.
// Should be accessed on read mode only.
olMap: null,
_tp: null,
constructor: function(div, options){
// summary:
// Constructs a new Map object
if(!options){
options = {};
}
div = dom.byId(div);
this._tp = {
x: 0,
y: 0
};
var opts = options.openLayersMapOptions;
if(!opts){
opts = {
controls: [new OpenLayers.Control.ScaleLine({
maxWidth: 200
}), new OpenLayers.Control.Navigation()]
};
}
if(options.accessible){
var kbd = new OpenLayers.Control.KeyboardDefaults();
if(!opts.controls){
opts.controls = [];
}
opts.controls.push(kbd);
}
var baseLayerType = options.baseLayerType;
if(!baseLayerType){
baseLayerType = openlayers.BaseLayerType.OSM;
}
var map = new OpenLayers.Map(div, opts);
this.olMap = map;
this._layerDictionary = {
olLayers: [],
layers: []
};
if(options.touchHandler){
this._touchControl = new TouchInteractionSupport(map);
}
var base = this._createBaseLayer(options);
this.addLayer(base);
this.initialFit(options);
},
initialFit: function(params){
// summary:
// Performs an initial fit to contents.
// tags:
// protected
var o = params.initialLocation;
if(!o){
o = [-160, 70, 160, -70];
}
this.fitTo(o);
},
setBaseLayerType: function(type){
// summary:
// Set the base layer type, replacing the existing base layer
// type: dojox/geo/openlayers.BaseLayerType
// base layer type
// returns:
// The newly created layer.
if(type == this.baseLayerType){
return null; // Layer
}
var o = null;
if(typeof type == "string"){
o = {
baseLayerName: type,
baseLayerType: type
};
this.baseLayerType = type;
}else if(typeof type == "object"){
o = type;
this.baseLayerType = o.baseLayerType;
}
var bl = null;
if(o != null){
bl = this._createBaseLayer(o);
if(bl != null){
var olm = this.olMap;
var ob = olm.getZoom();
var oc = olm.getCenter();
var recenter = !!oc && !!olm.baseLayer && !!olm.baseLayer.map;
if(recenter){
var proj = olm.getProjectionObject();
if(proj != null){
oc = oc.transform(proj, openlayers.EPSG4326);
}
}
var old = olm.baseLayer;
if(old != null){
var l = this._getLayer(old);
this.removeLayer(l);
}
if(bl != null){
this.addLayer(bl);
}
if(recenter){
proj = olm.getProjectionObject();
if(proj != null){
oc = oc.transform(openlayers.EPSG4326, proj);
}
olm.setCenter(oc, ob);
}
}
}
return bl;
},
getBaseLayerType: function(){
// summary:
// Returns the base layer type.
// returns:
// The current base layer type.
return this.baseLayerType; // openlayers.BaseLayerType
},
getScale: function(geodesic){
// summary:
// Returns the current scale
// geodesic: Boolean
// Tell if geodesic calculation should be performed. If set to
// true, the scale will be calculated based on the horizontal size of the
// pixel in the center of the map viewport.
var scale = null;
var om = this.olMap;
if(geodesic){
var units = om.getUnits();
if(!units){
return null; // Number
}
var inches = OpenLayers.INCHES_PER_UNIT;
scale = (om.getGeodesicPixelSize().w || 0.000001) * inches["km"] * OpenLayers.DOTS_PER_INCH;
}else{
scale = om.getScale();
}
return scale; // Number
},
getOLMap: function(){
// summary:
// gets the underlying OpenLayers map object.
// returns:
// The underlying OpenLayers map object.
return this.olMap; // OpenLayers.Map
},
_createBaseLayer: function(params){
// summary:
// Creates the base layer.
// tags:
// private
var base = null;
var type = params.baseLayerType;
var url = params.baseLayerUrl;
var name = params.baseLayerName;
var options = params.baseLayerOptions;
if(!name){
name = type;
}
if(!options){
options = {};
}
switch(type){
case openlayers.BaseLayerType.OSM:
options.transitionEffect = "resize";
// base = new OpenLayers.Layer.OSM(name, url, options);
base = new Layer(name, {
olLayer: new OpenLayers.Layer.OSM(name, url, options)
});
break;
case openlayers.BaseLayerType.Transport:
options.transitionEffect = "resize";
base = new Layer(name, {
olLayer: new OpenLayers.Layer.OSM.TransportMap(name, url, options)
});
break;
case openlayers.BaseLayerType.WMS:
if(!url){
url = "http://labs.metacarta.com/wms/vmap0";
if(!options.layers){
options.layers = "basic";
}
}
base = new Layer(name, {
olLayer: new OpenLayers.Layer.WMS(name, url, options, {
transitionEffect: "resize"
})
});
break;
case openlayers.BaseLayerType.GOOGLE:
base = new Layer(name, {
olLayer: new OpenLayers.Layer.Google(name, options)
});
break;
case openlayers.BaseLayerType.VIRTUAL_EARTH:
base = new Layer(name, {
olLayer: new OpenLayers.Layer.VirtualEarth(name, options)
});
break;
case openlayers.BaseLayerType.YAHOO:
// base = new OpenLayers.Layer.Yahoo(name);
base = new Layer(name, {
olLayer: new OpenLayers.Layer.Yahoo(name, options)
});
break;
case openlayers.BaseLayerType.ARCGIS:
if(!url){
url = "http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_StreetMap_World_2D/MapServer/export";
}
base = new Layer(name, {
olLayer: new OpenLayers.Layer.ArcGIS93Rest(name, url, options, {})
});
break;
}
if(base == null){
if(type instanceof OpenLayers.Layer){
base = type;
}else{
options.transitionEffect = "resize";
base = new Layer(name, {
olLayer: new OpenLayers.Layer.OSM(name, url, options)
});
this.baseLayerType = openlayers.BaseLayerType.OSM;
}
}
return base;
},
removeLayer: function(layer){
// summary:
// Remove the specified layer from the map.
// layer: Layer
// The layer to remove from the map.
var om = this.olMap;
var i = array.indexOf(this._layerDictionary.layers, layer);
if(i > 0){
this._layerDictionary.layers.splice(i, 1);
}
var oll = layer.olLayer;
var j = array.indexOf(this._layerDictionary.olLayers, oll);
if(j > 0){
this._layerDictionary.olLayers.splice(i, j);
}
om.removeLayer(oll, false);
},
layerIndex: function(layer, index){
// summary:
// Set or retrieve the layer index.
// description:
// Set or get the layer index, that is the z-order of the layer.
// if the index parameter is provided, the layer index is set to
// this value. If the index parameter is not provided, the index of
// the layer is returned.
// layer: Layer
// the layer to retrieve the index.
// index: int?
// index of the layer
// returns:
// the index of the layer.
var olm = this.olMap;
if(!index){
return olm.getLayerIndex(layer.olLayer);
}
//olm.raiseLayer(layer.olLayer, index);
olm.setLayerIndex(layer.olLayer, index);
this._layerDictionary.layers.sort(function(l1, l2){
return olm.getLayerIndex(l1.olLayer) - olm.getLayerIndex(l2.olLayer);
});
this._layerDictionary.olLayers.sort(function(l1, l2){
return olm.getLayerIndex(l1) - olm.getLayerIndex(l2);
});
return index; // Number
},
addLayer: function(layer){
// summary:
// Add the specified layer to the map.
// layer: Layer
// The layer to add to the map.
layer.dojoMap = this;
var om = this.olMap;
var ol = layer.olLayer;
this._layerDictionary.olLayers.push(ol);
this._layerDictionary.layers.push(layer);
om.addLayer(ol);
layer.added();
},
_getLayer: function(/*OpenLayer.Layer */ol){
// summary:
// Retrieve the dojox.geo.openlayer.Layer from the OpenLayer.Layer
// tags:
// private
var i = array.indexOf(this._layerDictionary.olLayers, ol);
if(i != -1){
return this._layerDictionary.layers[i];
}
return null;
},
getLayer: function(property, value){
// summary:
// Returns the layer whose property matches the value.
// property: String
// The property to check
// value: Object
// The value to match
// returns:
// The layer(s) matching the property's value. Since multiple layers
// match the property's value the return value is an array.
// example:
// var layers = map.getLayer("name", "Layer Name");
var om = this.olMap;
var ols = om.getBy("layers", property, value);
var ret = new Array(); //[];
array.forEach(ols, function(ol){
ret.push(this._getLayer(ol));
}, this);
return ret; // Layer[]
},
getLayerCount: function(){
// summary:
// Returns the count of layers of this map.
// returns:
// The number of layers of this map.
var om = this.olMap;
if(om.layers == null){
return 0;
}
return om.layers.length; // Number
},
fitTo: function(o){
// summary:
// Fits the map on a point,or an area
// description:
// Fits the map on the point or extent specified as parameter.
// o: Object
// Object with key values fit parameters or a JSON string.
// example:
// Examples of arguments passed to the fitTo function:
// | null
// The map is fit on full extent
//
// | {
// | bounds: [ulx, uly, lrx, lry]
// | }
// The map is fit on the specified bounds expressed as decimal degrees latitude and longitude.
// The bounds are defined with their upper left and lower right corners coordinates.
//
// | {
// | position: [longitude, latitude],
// | extent: degrees
// | }
// The map is fit on the specified position showing the extent `<extent>` around
// the specified center position.
var map = this.olMap;
var from = openlayers.EPSG4326;
if(o == null){
var c = this.transformXY(0, 0, from);
map.setCenter(new OpenLayers.LonLat(c.x, c.y));
return;
}
var b = null;
if(typeof o == "string"){
var j = json.fromJson(o);
}else{
j = o;
}
var ul;
var lr;
if(j.hasOwnProperty("bounds")){
var a = j.bounds;
b = new OpenLayers.Bounds();
ul = this.transformXY(a[0], a[1], from);
b.left = ul.x;
b.top = ul.y;
lr = this.transformXY(a[2], a[3], from);
b.right = lr.x;
b.bottom = lr.y;
}
if(b == null){
if(j.hasOwnProperty("position")){
var p = j.position;
var e = j.hasOwnProperty("extent") ? j.extent : 1;
if(typeof e == "string"){
e = parseFloat(e);
}
b = new OpenLayers.Bounds();
ul = this.transformXY(p[0] - e, p[1] + e, from);
b.left = ul.x;
b.top = ul.y;
lr = this.transformXY(p[0] + e, p[1] - e, from);
b.right = lr.x;
b.bottom = lr.y;
}
}
if(b == null){
if(o.length == 4){
b = new OpenLayers.Bounds();
// TODO Choose the correct method
if(false){
b.left = o[0];
b.top = o[1];
b.right = o[2];
b.bottom = o[3];
}else{
ul = this.transformXY(o[0], o[1], from);
b.left = ul.x;
b.top = ul.y;
lr = this.transformXY(o[2], o[3], from);
b.right = lr.x;
b.bottom = lr.y;
}
}
}
if(b != null){
map.zoomToExtent(b, true);
}
},
transform: function(p, from, to){
// summary:
// Transforms the point passed as argument, expressed in the <em>from</em>
// coordinate system to the map coordinate system.
// description:
// Transforms the point passed as argument without modifying it. The point is supposed to be expressed
// in the <em>from</em> coordinate system and is transformed to the map coordinate system.
// p: Object {x, y}
// The point to transform
// from: OpenLayers.Projection
// The projection in which the point is expressed.
return this.transformXY(p.x, p.y, from, to);
},
transformXY: function(x, y, from, to){
// summary:
// Transforms the coordinates passed as argument, expressed in the <em>from</em>
// coordinate system to the map coordinate system.
// description:
// Transforms the coordinates passed as argument. The coordinate are supposed to be expressed
// in the <em>from</em> coordinate system and are transformed to the map coordinate system.
// x: Number
// The longitude coordinate to transform.
// y: Number
// The latitude coordinate to transform.
// from: OpenLayers.Projection?
// The projection in which the point is expressed, or EPSG4326 is not specified.
// to: OpenLayers.Projection?
// The projection in which the point is converted to. In not specifed, the map projection is used.
// returns:
// The transformed coordinate as an {x,y} Object.
var tp = this._tp;
tp.x = x;
tp.y = y;
if(!from){
from = openlayers.EPSG4326;
}
if(!to){
to = this.olMap.getProjectionObject();
}
tp = OpenLayers.Projection.transform(tp, from, to);
return tp; // Object
}
});
});
},
'dojox/geo/openlayers/TouchInteractionSupport':function(){
define([
"dojo/_base/declare",
"dojo/_base/connect",
"dojo/_base/html",
"dojo/_base/lang",
"dojo/_base/event",
"dojo/_base/window"
], function(declare, connect, html, lang, event, win){
return declare("dojox.geo.openlayers.TouchInteractionSupport", null, {
// summary:
// class to handle touch interactions on a OpenLayers.Map widget
// tags:
// private
_map: null,
_centerTouchLocation: null,
_touchMoveListener: null,
_touchEndListener: null,
_initialFingerSpacing: null,
_initialScale: null,
_tapCount: null,
_tapThreshold: null,
_lastTap: null,
constructor: function(map){
// summary:
// Constructs a new TouchInteractionSupport instance
// map: OpenLayers.Map
// the Map widget this class provides touch navigation for.
this._map = map;
this._centerTouchLocation = new OpenLayers.LonLat(0, 0);
var div = this._map.div;
// install touch listeners
connect.connect(div, "touchstart", this, this._touchStartHandler);
connect.connect(div, "touchmove", this, this._touchMoveHandler);
connect.connect(div, "touchend", this, this._touchEndHandler);
this._tapCount = 0;
this._lastTap = {
x: 0,
y: 0
};
this._tapThreshold = 100; // square distance in pixels
},
_getTouchBarycenter: function(touchEvent){
// summary:
// returns the midpoint of the two first fingers (or the first finger location if only one)
// touchEvent: TouchEvent
// a touch event
// returns:
// the midpoint as an {x,y} object.
// tags:
// private
var touches = touchEvent.touches;
var firstTouch = touches[0];
var secondTouch = null;
if(touches.length > 1){
secondTouch = touches[1];
}else{
secondTouch = touches[0];
}
var marginBox = html.marginBox(this._map.div);
var middleX = (firstTouch.pageX + secondTouch.pageX) / 2.0 - marginBox.l;
var middleY = (firstTouch.pageY + secondTouch.pageY) / 2.0 - marginBox.t;
return {
x: middleX,
y: middleY
}; // Object
},
_getFingerSpacing: function(touchEvent){
// summary:
// computes the distance between the first two fingers
// touchEvent: Event
// a touch event
// returns: float
// a distance. -1 if less that 2 fingers
// tags:
// private
var touches = touchEvent.touches;
var spacing = -1;
if(touches.length >= 2){
var dx = (touches[1].pageX - touches[0].pageX);
var dy = (touches[1].pageY - touches[0].pageY);
spacing = Math.sqrt(dx * dx + dy * dy);
}
return spacing;
},
_isDoubleTap: function(touchEvent){
// summary:
// checks whether the specified touchStart event is a double tap
// (i.e. follows closely a previous touchStart at approximately the same location)
// touchEvent: TouchEvent
// a touch event
// returns: boolean
// true if this event is considered a double tap
// tags:
// private
var isDoubleTap = false;
var touches = touchEvent.touches;
if((this._tapCount > 0) && touches.length == 1){
// test distance from last tap
var dx = (touches[0].pageX - this._lastTap.x);
var dy = (touches[0].pageY - this._lastTap.y);
var distance = dx * dx + dy * dy;
if(distance < this._tapThreshold){
isDoubleTap = true;
}else{
this._tapCount = 0;
}
}
this._tapCount++;
this._lastTap.x = touches[0].pageX;
this._lastTap.y = touches[0].pageY;
setTimeout(lang.hitch(this, function(){
this._tapCount = 0;
}), 300);
return isDoubleTap;
},
_doubleTapHandler: function(touchEvent){
// summary:
// action performed on the map when a double tap was triggered
// touchEvent: TouchEvent
// a touch event
// tags:
// private
// perform a basic 2x zoom on touch
var touches = touchEvent.touches;
var marginBox = html.marginBox(this._map.div);
var offX = touches[0].pageX - marginBox.l;
var offY = touches[0].pageY - marginBox.t;
// clicked map point before zooming
var mapPoint = this._map.getLonLatFromPixel(new OpenLayers.Pixel(offX, offY));
// zoom increment power
this._map.setCenter(new OpenLayers.LonLat(mapPoint.lon, mapPoint.lat), this._map.getZoom() + 1);
},
_touchStartHandler: function(touchEvent){
// summary:
// action performed on the map when a touch start was triggered
// touchEvent: Event
// a touch event
// tags:
// private
event.stop(touchEvent);
// test double tap
if(this._isDoubleTap(touchEvent)){
this._doubleTapHandler(touchEvent);
return;
}
// compute map midpoint between fingers
var middlePoint = this._getTouchBarycenter(touchEvent);
this._centerTouchLocation = this._map.getLonLatFromPixel(new OpenLayers.Pixel(middlePoint.x, middlePoint.y));
// store initial finger spacing to compute zoom later
this._initialFingerSpacing = this._getFingerSpacing(touchEvent);
// store initial map scale
this._initialScale = this._map.getScale();
// install touch move and up listeners (if not done by other fingers before)
if(!this._touchMoveListener){
this._touchMoveListener = connect.connect(win.global, "touchmove", this, this._touchMoveHandler);
}
if(!this._touchEndListener){
this._touchEndListener = connect.connect(win.global, "touchend", this, this._touchEndHandler);
}
},
_touchEndHandler: function(touchEvent){
// summary:
// action performed on the map when a touch end was triggered
// touchEvent: Event
// a touch event
// tags:
// private
event.stop(touchEvent);
var touches = touchEvent.touches;
if(touches.length == 0){
// disconnect listeners only when all fingers are up
if(this._touchMoveListener){
connect.disconnect(this._touchMoveListener);
this._touchMoveListener = null;
}
if(this._touchEndListener){
connect.disconnect(this._touchEndListener);
this._touchEndListener = null;
}
}else{
// recompute touch center
var middlePoint = this._getTouchBarycenter(touchEvent);
this._centerTouchLocation = this._map.getLonLatFromPixel(new OpenLayers.Pixel(middlePoint.x, middlePoint.y));
}
},
_touchMoveHandler: function(touchEvent){
// summary:
// action performed on the map when a touch move was triggered
// touchEvent: Event
// a touch event
// tags:
// private
// prevent browser interaction
event.stop(touchEvent);
var middlePoint = this._getTouchBarycenter(touchEvent);
// compute map offset
var mapPoint = this._map.getLonLatFromPixel(new OpenLayers.Pixel(middlePoint.x, middlePoint.y));
var mapOffsetLon = mapPoint.lon - this._centerTouchLocation.lon;
var mapOffsetLat = mapPoint.lat - this._centerTouchLocation.lat;
// compute scale factor
var scaleFactor = 1;
var touches = touchEvent.touches;
if(touches.length >= 2){
var fingerSpacing = this._getFingerSpacing(touchEvent);
scaleFactor = fingerSpacing / this._initialFingerSpacing;
// weird openlayer bug: setting several times the same scale value lead to visual zoom...
this._map.zoomToScale(this._initialScale / scaleFactor);
}
// adjust map center on barycenter
var currentMapCenter = this._map.getCenter();
this._map.setCenter(new OpenLayers.LonLat(currentMapCenter.lon - mapOffsetLon, currentMapCenter.lat
- mapOffsetLat));
}
});
});
},
'dojox/geo/openlayers/Layer':function(){
define([
"dojo/_base/declare",
"dojo/_base/lang",
"dojo/_base/array",
"dojo/_base/sniff",
"./Feature"
], function(declare, lang, array, sniff, Feature){
return declare("dojox.geo.openlayers.Layer", null, {
// summary:
// Base layer class for dojox.geo.openlayers.Map specific layers extending OpenLayers.Layer class.
// This layer class accepts Features which encapsulates graphic objects to be added to the map.
// This layer class encapsulates an OpenLayers.Layer.
// This class provides Feature management such as add, remove and feature access.
constructor: function(name, options){
// summary:
// Constructs a new Layer.
// name: String
// The name of the layer.
// options: Object
// Options passed to the underlying OpenLayers.Layer object.
var ol = options ? options.olLayer : null;
if(!ol){
ol = lang.delegate(new OpenLayers.Layer(name, options));
}
this.olLayer = ol;
this._features = null;
this.olLayer.events.register("moveend", this, lang.hitch(this, this.moveTo));
},
renderFeature: function(/* Feature */f){
// summary:
// Called when rendering a feature is necessary.
// f: Feature
// The feature to draw.
f.render();
},
getDojoMap: function(){
return this.dojoMap;
},
addFeature: function(f){
// summary:
// Add a feature or an array of features to the layer.
// f: Feature|Feature[]
// The Feature or array of features to add.
if(lang.isArray(f)){
array.forEach(f, function(item){
this.addFeature(item);
}, this);
return;
}
if(this._features == null){
this._features = [];
}
this._features.push(f);
f._setLayer(this);
},
removeFeature: function(f){
// summary:
// Removes a feature or an array of features from the layer.
// f: Feature|Feature[]
// The Feature or array of features to remove.
var ft = this._features;
if(ft == null){
return;
}
if(f instanceof Array){
f = f.slice(0);
array.forEach(f, function(item){
this.removeFeature(item);
}, this);
return;
}
var i = array.indexOf(ft, f);
if(i != -1){
ft.splice(i, 1);
}
f._setLayer(null);
f.remove();
},
removeFeatureAt: function(index){
// summary:
// Remove the feature at the specified index.
// index: int
// The index of the feature to remove.
var ft = this._features;
var f = ft[index];
if(!f){
return;
}
ft.splice(index, 1);
f._setLayer(null);
f.remove();
},
getFeatures: function(){
// summary:
// Returns the feature hold by this layer.
// returns:
// The untouched array of features hold by this layer.
return this._features; // Feature[]
},
getFeatureAt: function(i){
// summary:
// Returns the i-th feature of this layer.
// i: Number
// The index of the feature to return.
// returns:
// The i-th feature of this layer.
if(this._features == null){
return undefined;
}
return this._features[i]; // Feature
},
getFeatureCount: function(){
// summary:
// Returns the number of the features contained by this layer.
// returns:
// The number of the features contained by this layer.
if(this._features == null){
return 0;
}
return this._features.length; // Number
},
clear: function(){
// summary:
// Removes all the features from this layer.
var fa = this.getFeatures();
this.removeFeature(fa);
},
moveTo: function(event){
// summary:
// Called when the layer is panned or zoomed.
// event: MouseEvent
// The event
if(event.zoomChanged){
if(this._features == null){
return;
}
array.forEach(this._features, function(f){
this.renderFeature(f);
}, this);
}
},
redraw: function(){
// summary:
// Redraws this layer
if(sniff.isIE){
setTimeout(lang.hitch(this, function(){
this.olLayer.redraw();
}, 0));
}else{
this.olLayer.redraw();
}
},
added: function(){
// summary:
// Called when the layer is added to the map
}
});
});
},
'dojox/geo/openlayers/Feature':function(){
define([
"dojo/_base/kernel",
"dojo/_base/declare",
"./_base"
], function(dojo, declare, openlayers){
return declare("dojox.geo.openlayers.Feature", null, {
// summary:
// A Feature encapsulates an item so that it can be added to a Layer.
// This class is not attended to be used as it, but serve as a base class
// for specific features such as GeometryFeature which can display georeferenced
// geometries and WidgetFeature which can display georeferenced widgets.
constructor: function(){
// summary:
// Construct a new Feature
this._layer = null;
this._coordSys = openlayers.EPSG4326;
},
getCoordinateSystem: function(){
// summary:
// Returns the coordinate system in which coordinates of this feature are expressed.
// returns:
// The coordinate system in which coordinates of this feature are expressed.
return this._coordSys; // OpenLayers.Projection
},
setCoordinateSystem: function(/* OpenLayers.Projection */cs){
// summary:
// Set the coordinate system in which coordinates of this feature are expressed.
// cs: OpenLayers.Projection
// The coordinate system in which coordinates of this feature are expressed.
this._coordSys = cs;
},
getLayer: function(){
// summary:
// Returns the Layer to which this feature belongs.
// returns:
// The layer to which this feature belongs.
return this._layer; // dojox/geo/openlayers/Layer
},
_setLayer: function(/* dojox/geo/openlayers/Layer */l){
// summary:
// Sets the layer to which this Feature belongs
// description:
// Called when the feature is added to the Layer.
// tags:
// private
this._layer = l;
},
render: function(){
// summary:
// subclasses implements drawing specific behavior.
},
remove: function(){
// summary:
// Subclasses implements specific behavior.
// Called when removed from the layer.
},
_getLocalXY: function(p){
// summary:
// From projected coordinates to screen coordinates
// p: Object
// Object with x and y fields
// tags:
// private
var x = p.x;
var y = p.y;
var layer = this.getLayer();
var resolution = layer.olLayer.map.getResolution();
var extent = layer.olLayer.getExtent();
var rx = (x / resolution + (-extent.left / resolution));
var ry = ((extent.top / resolution) - y / resolution);
return [rx, ry];
}
});
});
},
'dojox/geo/openlayers/Patch':function(){
define([
"dojo/_base/kernel",
"dojo/_base/lang", // dojo.extend getObject
"dojo/_base/sniff", // dojo.isIE
"dojox/gfx",
"dojox/gfx/shape"
], function(dojo, lang, sniff, gfx, shape){
var dgo = lang.getObject("geo.openlayers", true, dojox);
dgo.Patch = {
patchMethod: function(/*Object*/type, /*String*/method, /*Function*/execBefore, /*Function*/
execAfter){
// summary:
// Patches the specified method of the given type so that the 'execBefore' (resp. 'execAfter') function is
// called before (resp. after) invoking the legacy implementation.
// description:
// The execBefore function is invoked with the following parameter:
// execBefore(method, arguments) where 'method' is the patched method name and 'arguments' the arguments received
// by the legacy implementation.
// The execAfter function is invoked with the following parameter:
// execBefore(method, returnValue, arguments) where 'method' is the patched method name, 'returnValue' the value
// returned by the legacy implementation and 'arguments' the arguments received by the legacy implementation.
// type: Object
// the type to patch.
// method: String
// the method name.
// execBefore: Function
// the function to execute before the legacy implementation.
// execAfter: Function
// the function to execute after the legacy implementation.
// tags:
// private
var old = type.prototype[method];
type.prototype[method] = function(){
var callee = method;
if(execBefore){
execBefore.call(this, callee, arguments);
}
var ret = old.apply(this, arguments);
if(execAfter){
ret = execAfter.call(this, callee, ret, arguments) || ret;
}
return ret;
};
},
patchGFX: function(){
var vmlFixRawNodePath = function(){
if(!this.rawNode.path){
this.rawNode.path = {};
}
};
var vmlFixFillColors = function(){
if(this.rawNode.fill && !this.rawNode.fill.colors){
this.rawNode.fill.colors = {};
}
};
if(sniff.isIE <= 8 && gfx.renderer === "vml"){
this.patchMethod(gfx.Line, "setShape", vmlFixRawNodePath, null);
this.patchMethod(gfx.Polyline, "setShape", vmlFixRawNodePath, null);
this.patchMethod(gfx.Path, "setShape", vmlFixRawNodePath, null);
this.patchMethod(shape.Shape, "setFill", vmlFixFillColors, null);
}
}
};
return dgo.Patch;
});
},
'dojox/gfx':function(){
define(["dojo/_base/lang", "./gfx/_base", "./gfx/renderer!"],
function(lang, gfxBase, renderer){
// module:
// dojox/gfx
// summary:
// This the root of the Dojo Graphics package
gfxBase.switchTo(renderer);
return gfxBase;
});
},
'dojox/gfx/_base':function(){
define(["dojo/_base/kernel", "dojo/_base/lang", "dojo/_base/Color", "dojo/_base/sniff", "dojo/_base/window",
"dojo/_base/array","dojo/dom", "dojo/dom-construct","dojo/dom-geometry"],
function(kernel, lang, Color, has, win, arr, dom, domConstruct, domGeom){
// module:
// dojox/gfx
// summary:
// This module contains common core Graphics API used by different graphics renderers.
var g = lang.getObject("dojox.gfx", true),
b = g._base = {};
// candidates for dojox.style (work on VML and SVG nodes)
g._hasClass = function(/*DomNode*/node, /*String*/classStr){
// summary:
// Returns whether or not the specified classes are a portion of the
// class list currently applied to the node.
// return (new RegExp('(^|\\s+)'+classStr+'(\\s+|$)')).test(node.className) // Boolean
var cls = node.getAttribute("className");
return cls && (" " + cls + " ").indexOf(" " + classStr + " ") >= 0; // Boolean
};
g._addClass = function(/*DomNode*/node, /*String*/classStr){
// summary:
// Adds the specified classes to the end of the class list on the
// passed node.
var cls = node.getAttribute("className") || "";
if(!cls || (" " + cls + " ").indexOf(" " + classStr + " ") < 0){
node.setAttribute("className", cls + (cls ? " " : "") + classStr);
}
};
g._removeClass = function(/*DomNode*/node, /*String*/classStr){
// summary:
// Removes classes from node.
var cls = node.getAttribute("className");
if(cls){
node.setAttribute(
"className",
cls.replace(new RegExp('(^|\\s+)' + classStr + '(\\s+|$)'), "$1$2")
);
}
};
// candidate for dojox.html.metrics (dynamic font resize handler is not implemented here)
// derived from Morris John's emResized measurer
b._getFontMeasurements = function(){
// summary:
// Returns an object that has pixel equivilents of standard font
// size values.
var heights = {
'1em': 0, '1ex': 0, '100%': 0, '12pt': 0, '16px': 0, 'xx-small': 0,
'x-small': 0, 'small': 0, 'medium': 0, 'large': 0, 'x-large': 0,
'xx-large': 0
};
var p, oldStyle;
if(has("ie")){
// We do a font-size fix if and only if one isn't applied already.
// NOTE: If someone set the fontSize on the HTML Element, this will kill it.
oldStyle = win.doc.documentElement.style.fontSize || "";
if(!oldStyle){
win.doc.documentElement.style.fontSize="100%";
}
}
// set up the measuring node.
var div = domConstruct.create("div", {style: {
position: "absolute",
left: "0",
top: "-100px",
width: "30px",
height: "1000em",
borderWidth: "0",
margin: "0",
padding: "0",
outline: "none",
lineHeight: "1",
overflow: "hidden"
}}, win.body());
// do the measurements.
for(p in heights){
div.style.fontSize = p;
heights[p] = Math.round(div.offsetHeight * 12/16) * 16/12 / 1000;
}
if(has("ie")){
// Restore the font to its old style.
win.doc.documentElement.style.fontSize = oldStyle;
}
win.body().removeChild(div);
return heights; //object
};
var fontMeasurements = null;
b._getCachedFontMeasurements = function(recalculate){
if(recalculate || !fontMeasurements){
fontMeasurements = b._getFontMeasurements();
}
return fontMeasurements;
};
// candidate for dojox.html.metrics
var measuringNode = null, empty = {};
b._getTextBox = function( /*String*/ text,
/*Object*/ style,
/*String?*/ className){
var m, s, al = arguments.length;
var i, box;
if(!measuringNode){
measuringNode = domConstruct.create("div", {style: {
position: "absolute",
top: "-10000px",
left: "0",
visibility: "hidden"
}}, win.body());
}
m = measuringNode;
// reset styles
m.className = "";
s = m.style;
s.borderWidth = "0";
s.margin = "0";
s.padding = "0";
s.outline = "0";
// set new style
if(al > 1 && style){
for(i in style){
if(i in empty){ continue; }
s[i] = style[i];
}
}
// set classes
if(al > 2 && className){
m.className = className;
}
// take a measure
m.innerHTML = text;
if(m.getBoundingClientRect){
var bcr = m.getBoundingClientRect();
box = {l: bcr.left, t: bcr.top, w: bcr.width || (bcr.right - bcr.left), h: bcr.height || (bcr.bottom - bcr.top)};
}else{
box = domGeom.getMarginBox(m);
}
m.innerHTML = "";
return box;
};
b._computeTextLocation = function(/*g.defaultTextShape*/textShape, /*Number*/width, /*Number*/height, /*Boolean*/fixHeight) {
var loc = {}, align = textShape.align;
switch (align) {
case 'end':
loc.x = textShape.x - width;
break;
case 'middle':
loc.x = textShape.x - width / 2;
break;
default:
loc.x = textShape.x;
break;
}
var c = fixHeight ? 0.75 : 1;
loc.y = textShape.y - height*c; // **rough** approximation of the ascent...
return loc;
};
b._computeTextBoundingBox = function(/*shape.Text*/s){
// summary:
// Compute the bbox of the given shape.Text instance. Note that this method returns an
// approximation of the bbox, and should be used when the underlying renderer cannot provide precise metrics.
if(!g._base._isRendered(s)){
return {x:0, y:0, width:0, height:0};
}
var loc, textShape = s.getShape(),
font = s.getFont() || g.defaultFont,
w = s.getTextWidth(),
h = g.normalizedLength(font.size);
loc = b._computeTextLocation(textShape, w, h, true);
return {
x: loc.x,
y: loc.y,
width: w,
height: h
};
};
b._isRendered = function(/*Shape*/s){
var p = s.parent;
while(p && p.getParent){
p = p.parent;
}
return p !== null;
};
// candidate for dojo.dom
var uniqueId = 0;
b._getUniqueId = function(){
// summary:
// returns a unique string for use with any DOM element
var id;
do{
id = kernel._scopeName + "xUnique" + (++uniqueId);
}while(dom.byId(id));
return id;
};
// IE10
var touchActionProp = has("pointer-events") ? "touchAction" : has("MSPointer") ? "msTouchAction" : null;
b._fixMsTouchAction = touchActionProp ? function(/*dojox/gfx/shape.Surface*/surface){
surface.rawNode.style[touchActionProp] = "none";
} : function() {};
/*=====
g.Stroke = {
// summary:
// A stroke defines stylistic properties that are used when drawing a path.
// color: String
// The color of the stroke, default value 'black'.
color: "black",
// style: String
// The style of the stroke, one of 'solid', ... . Default value 'solid'.
style: "solid",
// width: Number
// The width of a stroke, default value 1.
width: 1,
// cap: String
// The endcap style of the path. One of 'butt', 'round', ... . Default value 'butt'.
cap: "butt",
// join: Number
// The join style to use when combining path segments. Default value 4.
join: 4
};
g.Fill = {
// summary:
// Defines how to fill a shape. Four types of fills can be used: solid, linear gradient, radial gradient and pattern.
// See dojox/gfx.LinearGradient, dojox/gfx.RadialGradient and dojox/gfx.Pattern respectively for more information about the properties supported by each type.
// type: String?
// The type of fill. One of 'linear', 'radial', 'pattern' or undefined. If not specified, a solid fill is assumed.
type:"",
// color: String|dojo/Color?
// The color of a solid fill type.
color:null,
};
g.LinearGradient = {
// summary:
// An object defining the default stylistic properties used for Linear Gradient fills.
// Linear gradients are drawn along a virtual line, which results in appearance of a rotated pattern in a given direction/orientation.
// type: String
// Specifies this object is a Linear Gradient, value 'linear'
type: "linear",
// x1: Number
// The X coordinate of the start of the virtual line along which the gradient is drawn, default value 0.
x1: 0,
// y1: Number
// The Y coordinate of the start of the virtual line along which the gradient is drawn, default value 0.
y1: 0,
// x2: Number
// The X coordinate of the end of the virtual line along which the gradient is drawn, default value 100.
x2: 100,
// y2: Number
// The Y coordinate of the end of the virtual line along which the gradient is drawn, default value 100.
y2: 100,
// colors: Array
// An array of colors at given offsets (from the start of the line). The start of the line is
// defined at offest 0 with the end of the line at offset 1.
// Default value, [{ offset: 0, color: 'black'},{offset: 1, color: 'white'}], is a gradient from black to white.
colors: []
};
g.RadialGradient = {
// summary:
// Specifies the properties for RadialGradients using in fills patterns.
// type: String
// Specifies this is a RadialGradient, value 'radial'
type: "radial",
// cx: Number
// The X coordinate of the center of the radial gradient, default value 0.
cx: 0,
// cy: Number
// The Y coordinate of the center of the radial gradient, default value 0.
cy: 0,
// r: Number
// The radius to the end of the radial gradient, default value 100.
r: 100,
// colors: Array
// An array of colors at given offsets (from the center of the radial gradient).
// The center is defined at offest 0 with the outer edge of the gradient at offset 1.
// Default value, [{ offset: 0, color: 'black'},{offset: 1, color: 'white'}], is a gradient from black to white.
colors: []
};
g.Pattern = {
// summary:
// An object specifying the default properties for a Pattern using in fill operations.
// type: String
// Specifies this object is a Pattern, value 'pattern'.
type: "pattern",
// x: Number
// The X coordinate of the position of the pattern, default value is 0.
x: 0,
// y: Number
// The Y coordinate of the position of the pattern, default value is 0.
y: 0,
// width: Number
// The width of the pattern image, default value is 0.
width: 0,
// height: Number
// The height of the pattern image, default value is 0.
height: 0,
// src: String
// A url specifying the image to use for the pattern.
src: ""
};
g.Text = {
// summary:
// A keyword argument object defining both the text to be rendered in a VectorText shape,
// and specifying position, alignment, and fitting.
// text: String
// The text to be rendered.
// x: Number?
// The left coordinate for the text's bounding box.
// y: Number?
// The top coordinate for the text's bounding box.
// width: Number?
// The width of the text's bounding box.
// height: Number?
// The height of the text's bounding box.
// align: String?
// The alignment of the text, as defined in SVG. Can be "start", "end" or "middle".
// fitting: Number?
// How the text is to be fitted to the bounding box. Can be 0 (no fitting), 1 (fitting based on
// passed width of the bounding box and the size of the font), or 2 (fit text to the bounding box,
// and ignore any size parameters).
// leading: Number?
// The leading to be used between lines in the text.
// decoration: String?
// Any text decoration to be used.
};
g.Font = {
// summary:
// An object specifying the properties for a Font used in text operations.
// type: String
// Specifies this object is a Font, value 'font'.
type: "font",
// style: String
// The font style, one of 'normal', 'bold', default value 'normal'.
style: "normal",
// variant: String
// The font variant, one of 'normal', ... , default value 'normal'.
variant: "normal",
// weight: String
// The font weight, one of 'normal', ..., default value 'normal'.
weight: "normal",
// size: String
// The font size (including units), default value '10pt'.
size: "10pt",
// family: String
// The font family, one of 'serif', 'sanserif', ..., default value 'serif'.
family: "serif"
};
=====*/
lang.mixin(g, {
// summary:
// defines constants, prototypes, and utility functions for the core Graphics API
// default shapes, which are used to fill in missing parameters
defaultPath: {
// summary:
// Defines the default Path prototype object.
// type: String
// Specifies this object is a Path, default value 'path'.
type: "path",
// path: String
// The path commands. See W32C SVG 1.0 specification.
// Defaults to empty string value.
path: ""
},
defaultPolyline: {
// summary:
// Defines the default PolyLine prototype.
// type: String
// Specifies this object is a PolyLine, default value 'polyline'.
type: "polyline",
// points: Array
// An array of point objects [{x:0,y:0},...] defining the default polyline's line segments. Value is an empty array [].
points: []
},
defaultRect: {
// summary:
// Defines the default Rect prototype.
// type: String
// Specifies this default object is a type of Rect. Value is 'rect'
type: "rect",
// x: Number
// The X coordinate of the default rectangles position, value 0.
x: 0,
// y: Number
// The Y coordinate of the default rectangle's position, value 0.
y: 0,
// width: Number
// The width of the default rectangle, value 100.
width: 100,
// height: Number
// The height of the default rectangle, value 100.
height: 100,
// r: Number
// The corner radius for the default rectangle, value 0.
r: 0
},
defaultEllipse: {
// summary:
// Defines the default Ellipse prototype.
// type: String
// Specifies that this object is a type of Ellipse, value is 'ellipse'
type: "ellipse",
// cx: Number
// The X coordinate of the center of the ellipse, default value 0.
cx: 0,
// cy: Number
// The Y coordinate of the center of the ellipse, default value 0.
cy: 0,
// rx: Number
// The radius of the ellipse in the X direction, default value 200.
rx: 200,
// ry: Number
// The radius of the ellipse in the Y direction, default value 200.
ry: 100
},
defaultCircle: {
// summary:
// An object defining the default Circle prototype.
// type: String
// Specifies this object is a circle, value 'circle'
type: "circle",
// cx: Number
// The X coordinate of the center of the circle, default value 0.
cx: 0,
// cy: Number
// The Y coordinate of the center of the circle, default value 0.
cy: 0,
// r: Number
// The radius, default value 100.
r: 100
},
defaultLine: {
// summary:
// An object defining the default Line prototype.
// type: String
// Specifies this is a Line, value 'line'
type: "line",
// x1: Number
// The X coordinate of the start of the line, default value 0.
x1: 0,
// y1: Number
// The Y coordinate of the start of the line, default value 0.
y1: 0,
// x2: Number
// The X coordinate of the end of the line, default value 100.
x2: 100,
// y2: Number
// The Y coordinate of the end of the line, default value 100.
y2: 100
},
defaultImage: {
// summary:
// Defines the default Image prototype.
// type: String
// Specifies this object is an image, value 'image'.
type: "image",
// x: Number
// The X coordinate of the image's position, default value 0.
x: 0,
// y: Number
// The Y coordinate of the image's position, default value 0.
y: 0,
// width: Number
// The width of the image, default value 0.
width: 0,
// height: Number
// The height of the image, default value 0.
height: 0,
// src: String
// The src url of the image, defaults to empty string.
src: ""
},
defaultText: {
// summary:
// Defines the default Text prototype.
// type: String
// Specifies this is a Text shape, value 'text'.
type: "text",
// x: Number
// The X coordinate of the text position, default value 0.
x: 0,
// y: Number
// The Y coordinate of the text position, default value 0.
y: 0,
// text: String
// The text to be displayed, default value empty string.
text: "",
// align: String
// The horizontal text alignment, one of 'start', 'end', 'center'. Default value 'start'.
align: "start",
// decoration: String
// The text decoration , one of 'none', ... . Default value 'none'.
decoration: "none",
// rotated: Boolean
// Whether the text is rotated, boolean default value false.
rotated: false,
// kerning: Boolean
// Whether kerning is used on the text, boolean default value true.
kerning: true
},
defaultTextPath: {
// summary:
// Defines the default TextPath prototype.
// type: String
// Specifies this is a TextPath, value 'textpath'.
type: "textpath",
// text: String
// The text to be displayed, default value empty string.
text: "",
// align: String
// The horizontal text alignment, one of 'start', 'end', 'center'. Default value 'start'.
align: "start",
// decoration: String
// The text decoration , one of 'none', ... . Default value 'none'.
decoration: "none",
// rotated: Boolean
// Whether the text is rotated, boolean default value false.
rotated: false,
// kerning: Boolean
// Whether kerning is used on the text, boolean default value true.
kerning: true
},
// default stylistic attributes
defaultStroke: {
// summary:
// A stroke defines stylistic properties that are used when drawing a path.
// This object defines the default Stroke prototype.
// type: String
// Specifies this object is a type of Stroke, value 'stroke'.
type: "stroke",
// color: String
// The color of the stroke, default value 'black'.
color: "black",
// style: String
// The style of the stroke, one of 'solid', ... . Default value 'solid'.
style: "solid",
// width: Number
// The width of a stroke, default value 1.
width: 1,
// cap: String
// The endcap style of the path. One of 'butt', 'round', ... . Default value 'butt'.
cap: "butt",
// join: Number
// The join style to use when combining path segments. Default value 4.
join: 4
},
defaultLinearGradient: {
// summary:
// An object defining the default stylistic properties used for Linear Gradient fills.
// Linear gradients are drawn along a virtual line, which results in appearance of a rotated pattern in a given direction/orientation.
// type: String
// Specifies this object is a Linear Gradient, value 'linear'
type: "linear",
// x1: Number
// The X coordinate of the start of the virtual line along which the gradient is drawn, default value 0.
x1: 0,
// y1: Number
// The Y coordinate of the start of the virtual line along which the gradient is drawn, default value 0.
y1: 0,
// x2: Number
// The X coordinate of the end of the virtual line along which the gradient is drawn, default value 100.
x2: 100,
// y2: Number
// The Y coordinate of the end of the virtual line along which the gradient is drawn, default value 100.
y2: 100,
// colors: Array
// An array of colors at given offsets (from the start of the line). The start of the line is
// defined at offest 0 with the end of the line at offset 1.
// Default value, [{ offset: 0, color: 'black'},{offset: 1, color: 'white'}], is a gradient from black to white.
colors: [
{ offset: 0, color: "black" }, { offset: 1, color: "white" }
]
},
defaultRadialGradient: {
// summary:
// An object specifying the default properties for RadialGradients using in fills patterns.
// type: String
// Specifies this is a RadialGradient, value 'radial'
type: "radial",
// cx: Number
// The X coordinate of the center of the radial gradient, default value 0.
cx: 0,
// cy: Number
// The Y coordinate of the center of the radial gradient, default value 0.
cy: 0,
// r: Number
// The radius to the end of the radial gradient, default value 100.
r: 100,
// colors: Array
// An array of colors at given offsets (from the center of the radial gradient).
// The center is defined at offest 0 with the outer edge of the gradient at offset 1.
// Default value, [{ offset: 0, color: 'black'},{offset: 1, color: 'white'}], is a gradient from black to white.
colors: [
{ offset: 0, color: "black" }, { offset: 1, color: "white" }
]
},
defaultPattern: {
// summary:
// An object specifying the default properties for a Pattern using in fill operations.
// type: String
// Specifies this object is a Pattern, value 'pattern'.
type: "pattern",
// x: Number
// The X coordinate of the position of the pattern, default value is 0.
x: 0,
// y: Number
// The Y coordinate of the position of the pattern, default value is 0.
y: 0,
// width: Number
// The width of the pattern image, default value is 0.
width: 0,
// height: Number
// The height of the pattern image, default value is 0.
height: 0,
// src: String
// A url specifying the image to use for the pattern.
src: ""
},
defaultFont: {
// summary:
// An object specifying the default properties for a Font used in text operations.
// type: String
// Specifies this object is a Font, value 'font'.
type: "font",
// style: String
// The font style, one of 'normal', 'bold', default value 'normal'.
style: "normal",
// variant: String
// The font variant, one of 'normal', ... , default value 'normal'.
variant: "normal",
// weight: String
// The font weight, one of 'normal', ..., default value 'normal'.
weight: "normal",
// size: String
// The font size (including units), default value '10pt'.
size: "10pt",
// family: String
// The font family, one of 'serif', 'sanserif', ..., default value 'serif'.
family: "serif"
},
getDefault: (function(){
// summary:
// Returns a function used to access default memoized prototype objects (see them defined above).
var typeCtorCache = {};
// a memoized delegate()
return function(/*String*/ type){
var t = typeCtorCache[type];
if(t){
return new t();
}
t = typeCtorCache[type] = new Function();
t.prototype = g[ "default" + type ];
return new t();
}
})(),
normalizeColor: function(/*dojo/Color|Array|string|Object*/ color){
// summary:
// converts any legal color representation to normalized
// dojo/Color object
// color:
// A color representation.
return (color instanceof Color) ? color : new Color(color); // dojo/Color
},
normalizeParameters: function(existed, update){
// summary:
// updates an existing object with properties from an 'update'
// object
// existed: Object
// the target object to be updated
// update: Object
// the 'update' object, whose properties will be used to update
// the existed object
var x;
if(update){
var empty = {};
for(x in existed){
if(x in update && !(x in empty)){
existed[x] = update[x];
}
}
}
return existed; // Object
},
makeParameters: function(defaults, update){
// summary:
// copies the original object, and all copied properties from the
// 'update' object
// defaults: Object
// the object to be cloned before updating
// update: Object
// the object, which properties are to be cloned during updating
// returns: Object
// new object with new and default properties
var i = null;
if(!update){
// return dojo.clone(defaults);
return lang.delegate(defaults);
}
var result = {};
for(i in defaults){
if(!(i in result)){
result[i] = lang.clone((i in update) ? update[i] : defaults[i]);
}
}
return result; // Object
},
formatNumber: function(x, addSpace){
// summary:
// converts a number to a string using a fixed notation
// x: Number
// number to be converted
// addSpace: Boolean
// whether to add a space before a positive number
// returns: String
// the formatted value
var val = x.toString();
if(val.indexOf("e") >= 0){
val = x.toFixed(4);
}else{
var point = val.indexOf(".");
if(point >= 0 && val.length - point > 5){
val = x.toFixed(4);
}
}
if(x < 0){
return val; // String
}
return addSpace ? " " + val : val; // String
},
// font operations
makeFontString: function(font){
// summary:
// converts a font object to a CSS font string
// font: Object
// font object (see dojox/gfx.defaultFont)
return font.style + " " + font.variant + " " + font.weight + " " + font.size + " " + font.family; // Object
},
splitFontString: function(str){
// summary:
// converts a CSS font string to a font object
// description:
// Converts a CSS font string to a gfx font object. The CSS font
// string components should follow the W3C specified order
// (see http://www.w3.org/TR/CSS2/fonts.html#font-shorthand):
// style, variant, weight, size, optional line height (will be
// ignored), and family. Note that the Font.size attribute is limited to numeric CSS length.
// str: String
// a CSS font string.
// returns: Object
// object in dojox/gfx.defaultFont format
var font = g.getDefault("Font");
var t = str.split(/\s+/);
do{
if(t.length < 5){ break; }
font.style = t[0];
font.variant = t[1];
font.weight = t[2];
var i = t[3].indexOf("/");
font.size = i < 0 ? t[3] : t[3].substring(0, i);
var j = 4;
if(i < 0){
if(t[4] == "/"){
j = 6;
}else if(t[4].charAt(0) == "/"){
j = 5;
}
}
if(j < t.length){
font.family = t.slice(j).join(" ");
}
}while(false);
return font; // Object
},
// length operations
// cm_in_pt: Number
// points per centimeter (constant)
cm_in_pt: 72 / 2.54,
// mm_in_pt: Number
// points per millimeter (constant)
mm_in_pt: 7.2 / 2.54,
px_in_pt: function(){
// summary:
// returns the current number of pixels per point.
return g._base._getCachedFontMeasurements()["12pt"] / 12; // Number
},
pt2px: function(len){
// summary:
// converts points to pixels
// len: Number
// a value in points
return len * g.px_in_pt(); // Number
},
px2pt: function(len){
// summary:
// converts pixels to points
// len: Number
// a value in pixels
return len / g.px_in_pt(); // Number
},
normalizedLength: function(len) {
// summary:
// converts any length value to pixels
// len: String
// a length, e.g., '12pc'
// returns: Number
// pixels
if(len.length === 0){ return 0; }
if(len.length > 2){
var px_in_pt = g.px_in_pt();
var val = parseFloat(len);
switch(len.slice(-2)){
case "px": return val;
case "pt": return val * px_in_pt;
case "in": return val * 72 * px_in_pt;
case "pc": return val * 12 * px_in_pt;
case "mm": return val * g.mm_in_pt * px_in_pt;
case "cm": return val * g.cm_in_pt * px_in_pt;
}
}
return parseFloat(len); // Number
},
// pathVmlRegExp: RegExp
// a constant regular expression used to split a SVG/VML path into primitive components
// tags:
// private
pathVmlRegExp: /([A-Za-z]+)|(\d+(\.\d+)?)|(\.\d+)|(-\d+(\.\d+)?)|(-\.\d+)/g,
// pathVmlRegExp: RegExp
// a constant regular expression used to split a SVG/VML path into primitive components
// tags:
// private
pathSvgRegExp: /([A-DF-Za-df-z])|([-+]?\d*[.]?\d+(?:[eE][-+]?\d+)?)/g,
equalSources: function(a, b){
// summary:
// compares event sources, returns true if they are equal
// a: Object
// first event source
// b: Object
// event source to compare against a
// returns: Boolean
// true, if objects are truthy and the same
return a && b && a === b;
},
switchTo: function(/*String|Object*/ renderer){
// summary:
// switch the graphics implementation to the specified renderer.
// renderer:
// Either the string name of a renderer (eg. 'canvas', 'svg, ...) or the renderer
// object to switch to.
var ns = typeof renderer == "string" ? g[renderer] : renderer;
if(ns){
// If more options are added, update the docblock at the end of shape.js!
arr.forEach(["Group", "Rect", "Ellipse", "Circle", "Line",
"Polyline", "Image", "Text", "Path", "TextPath",
"Surface", "createSurface", "fixTarget"], function(name){
g[name] = ns[name];
});
if(typeof renderer == "string"){
g.renderer = renderer;
}else{
arr.some(["svg","vml","canvas","canvasWithEvents","silverlight"], function(r){
return (g.renderer = g[r] && g[r].Surface === g.Surface ? r : null);
});
}
}
}
});
/*=====
g.createSurface = function(parentNode, width, height){
// summary:
// creates a surface
// parentNode: Node
// a parent node
// width: String|Number
// width of surface, e.g., "100px" or 100
// height: String|Number
// height of surface, e.g., "100px" or 100
// returns: dojox/gfx.Surface
// newly created surface
};
g.fixTarget = function(){
// tags:
// private
};
=====*/
return g; // defaults object api
});
},
'dojox/gfx/renderer':function(){
define(["./_base","dojo/_base/lang", "dojo/_base/sniff", "dojo/_base/window", "dojo/_base/config"],
function(g, lang, has, win, config){
//>> noBuildResolver
var currentRenderer = null;
has.add("vml", function(global, document, element){
element.innerHTML = "<v:shape adj=\"1\"/>";
var supported = ("adj" in element.firstChild);
element.innerHTML = "";
return supported;
});
return {
// summary:
// This module is an AMD loader plugin that loads the appropriate graphics renderer
// implementation based on detected environment and current configuration settings.
load: function(id, require, load){
// tags:
// private
if(currentRenderer && id != "force"){
load(currentRenderer);
return;
}
var renderer = config.forceGfxRenderer,
renderers = !renderer && (lang.isString(config.gfxRenderer) ?
config.gfxRenderer : "svg,vml,canvas,silverlight").split(","),
silverlightObject, silverlightFlag;
while(!renderer && renderers.length){
switch(renderers.shift()){
case "svg":
// the next test is from https://github.com/phiggins42/has.js
if("SVGAngle" in win.global){
renderer = "svg";
}
break;
case "vml":
if(has("vml")){
renderer = "vml";
}
break;
case "silverlight":
try{
if(has("ie")){
silverlightObject = new ActiveXObject("AgControl.AgControl");
if(silverlightObject && silverlightObject.IsVersionSupported("1.0")){
silverlightFlag = true;
}
}else{
if(navigator.plugins["Silverlight Plug-In"]){
silverlightFlag = true;
}
}
}catch(e){
silverlightFlag = false;
}finally{
silverlightObject = null;
}
if(silverlightFlag){
renderer = "silverlight";
}
break;
case "canvas":
if(win.global.CanvasRenderingContext2D){
renderer = "canvas";
}
break;
}
}
if (renderer === 'canvas' && config.canvasEvents !== false) {
renderer = "canvasWithEvents";
}
if(config.isDebug){
console.log("gfx renderer = " + renderer);
}
function loadRenderer(){
require(["dojox/gfx/" + renderer], function(module){
g.renderer = renderer;
// memorize the renderer module
currentRenderer = module;
// now load it
load(module);
});
}
if(renderer == "svg" && typeof window.svgweb != "undefined"){
window.svgweb.addOnLoad(loadRenderer);
}else{
loadRenderer();
}
}
};
});
},
'dojox/gfx/shape':function(){
define(["./_base", "dojo/_base/lang", "dojo/_base/declare", "dojo/_base/kernel", "dojo/_base/sniff",
"dojo/on", "dojo/_base/array", "dojo/dom-construct", "dojo/_base/Color", "./matrix" ],
function(g, lang, declare, kernel, has, on, arr, domConstruct, Color, matrixLib){
var shape = g.shape = {
// summary:
// This module contains the core graphics Shape API.
// Different graphics renderer implementation modules (svg, canvas, vml, silverlight, etc.) extend this
// basic api to provide renderer-specific implementations for each shape.
};
shape.Shape = declare("dojox.gfx.shape.Shape", null, {
// summary:
// a Shape object, which knows how to apply
// graphical attributes and transformations
constructor: function(){
// rawNode: Node
// underlying graphics-renderer-specific implementation object (if applicable)
this.rawNode = null;
// shape: Object
// an abstract shape object
// (see dojox/gfx.defaultPath,
// dojox/gfx.defaultPolyline,
// dojox/gfx.defaultRect,
// dojox/gfx.defaultEllipse,
// dojox/gfx.defaultCircle,
// dojox/gfx.defaultLine,
// or dojox/gfx.defaultImage)
this.shape = null;
// matrix: dojox/gfx/matrix.Matrix2D
// a transformation matrix
this.matrix = null;
// fillStyle: dojox/gfx.Fill
// a fill object
// (see dojox/gfx.defaultLinearGradient,
// dojox/gfx.defaultRadialGradient,
// dojox/gfx.defaultPattern,
// or dojo/Color)
this.fillStyle = null;
// strokeStyle: dojox/gfx.Stroke
// a stroke object
// (see dojox/gfx.defaultStroke)
this.strokeStyle = null;
// bbox: dojox/gfx.Rectangle
// a bounding box of this shape
// (see dojox/gfx.defaultRect)
this.bbox = null;
// virtual group structure
// parent: Object
// a parent or null
// (see dojox/gfx/shape.Surface,
// or dojox/gfx.Group)
this.parent = null;
// parentMatrix: dojox/gfx/matrix.Matrix2D
// a transformation matrix inherited from the parent
this.parentMatrix = null;
if(has("gfxRegistry")){
var uid = shape.register(this);
this.getUID = function(){
return uid;
}
}
},
destroy: function(){
// summary:
// Releases all internal resources owned by this shape. Once this method has been called,
// the instance is considered destroyed and should not be used anymore.
if(has("gfxRegistry")){
shape.dispose(this);
}
if(this.rawNode && "__gfxObject__" in this.rawNode){
this.rawNode.__gfxObject__ = null;
}
this.rawNode = null;
},
// trivial getters
getNode: function(){
// summary:
// Different graphics rendering subsystems implement shapes in different ways. This
// method provides access to the underlying graphics subsystem object. Clients calling this
// method and using the return value must be careful not to try sharing or using the underlying node
// in a general way across renderer implementation.
// Returns the underlying graphics Node, or null if no underlying graphics node is used by this shape.
return this.rawNode; // Node
},
getShape: function(){
// summary:
// returns the current Shape object or null
// (see dojox/gfx.defaultPath,
// dojox/gfx.defaultPolyline,
// dojox/gfx.defaultRect,
// dojox/gfx.defaultEllipse,
// dojox/gfx.defaultCircle,
// dojox/gfx.defaultLine,
// or dojox/gfx.defaultImage)
return this.shape; // Object
},
getTransform: function(){
// summary:
// Returns the current transformation matrix applied to this Shape or null
return this.matrix; // dojox/gfx/matrix.Matrix2D
},
getFill: function(){
// summary:
// Returns the current fill object or null
// (see dojox/gfx.defaultLinearGradient,
// dojox/gfx.defaultRadialGradient,
// dojox/gfx.defaultPattern,
// or dojo/Color)
return this.fillStyle; // Object
},
getStroke: function(){
// summary:
// Returns the current stroke object or null
// (see dojox/gfx.defaultStroke)
return this.strokeStyle; // Object
},
getParent: function(){
// summary:
// Returns the parent Shape, Group or null if this Shape is unparented.
// (see dojox/gfx/shape.Surface,
// or dojox/gfx.Group)
return this.parent; // Object
},
getBoundingBox: function(){
// summary:
// Returns the bounding box Rectangle for this shape or null if a BoundingBox cannot be
// calculated for the shape on the current renderer or for shapes with no geometric area (points).
// A bounding box is a rectangular geometric region
// defining the X and Y extent of the shape.
// (see dojox/gfx.defaultRect)
// Note that this method returns a direct reference to the attribute of this instance. Therefore you should
// not modify its value directly but clone it instead.
return this.bbox; // dojox/gfx.Rectangle
},
getTransformedBoundingBox: function(){
// summary:
// returns an array of four points or null
// four points represent four corners of the untransformed bounding box
var b = this.getBoundingBox();
if(!b){
return null; // null
}
var m = this._getRealMatrix(),
gm = matrixLib;
return [ // Array
gm.multiplyPoint(m, b.x, b.y),
gm.multiplyPoint(m, b.x + b.width, b.y),
gm.multiplyPoint(m, b.x + b.width, b.y + b.height),
gm.multiplyPoint(m, b.x, b.y + b.height)
];
},
getEventSource: function(){
// summary:
// returns a Node, which is used as
// a source of events for this shape
// COULD BE RE-IMPLEMENTED BY THE RENDERER!
return this.rawNode; // Node
},
// empty settings
setClip: function(clip){
// summary:
// sets the clipping area of this shape.
// description:
// The clipping area defines the shape area that will be effectively visible. Everything that
// would be drawn outside of the clipping area will not be rendered.
// The possible clipping area types are rectangle, ellipse, polyline and path, but all are not
// supported by all the renderers. vml only supports rectangle clipping, while the gfx silverlight renderer does not
// support path clipping.
// The clip parameter defines the clipping area geometry, and should be an object with the following properties:
//
// - {x:Number, y:Number, width:Number, height:Number} for rectangular clip
// - {cx:Number, cy:Number, rx:Number, ry:Number} for ellipse clip
// - {points:Array} for polyline clip
// - {d:String} for a path clip.
//
// The clip geometry coordinates are expressed in the coordinate system used to draw the shape. In other
// words, the clipping area is defined in the shape parent coordinate system and the shape transform is automatically applied.
// example:
// The following example shows how to clip a gfx image with all the possible clip geometry: a rectangle,
// an ellipse, a circle (using the ellipse geometry), a polyline and a path:
//
// | surface.createImage({src:img, width:200,height:200}).setClip({x:10,y:10,width:50,height:50});
// | surface.createImage({src:img, x:100,y:50,width:200,height:200}).setClip({cx:200,cy:100,rx:20,ry:30});
// | surface.createImage({src:img, x:0,y:350,width:200,height:200}).setClip({cx:100,cy:425,rx:60,ry:60});
// | surface.createImage({src:img, x:300,y:0,width:200,height:200}).setClip({points:[350,0,450,50,380,130,300,110]});
// | surface.createImage({src:img, x:300,y:350,width:200,height:200}).setClip({d:"M 350,350 C314,414 317,557 373,450.0000 z"});
// clip: Object
// an object that defines the clipping geometry, or null to remove clip.
// COULD BE RE-IMPLEMENTED BY THE RENDERER!
this.clip = clip;
},
getClip: function(){
return this.clip;
},
setShape: function(shape){
// summary:
// sets a shape object
// (the default implementation simply ignores it)
// shape: Object
// a shape object
// (see dojox/gfx.defaultPath,
// dojox/gfx.defaultPolyline,
// dojox/gfx.defaultRect,
// dojox/gfx.defaultEllipse,
// dojox/gfx.defaultCircle,
// dojox/gfx.defaultLine,
// or dojox/gfx.defaultImage)
// COULD BE RE-IMPLEMENTED BY THE RENDERER!
this.shape = g.makeParameters(this.shape, shape);
this.bbox = null;
return this; // self
},
setFill: function(fill){
// summary:
// sets a fill object
// (the default implementation simply ignores it)
// fill: Object
// a fill object
// (see dojox/gfx.defaultLinearGradient,
// dojox/gfx.defaultRadialGradient,
// dojox/gfx.defaultPattern,
// or dojo/_base/Color)
// COULD BE RE-IMPLEMENTED BY THE RENDERER!
if(!fill){
// don't fill
this.fillStyle = null;
return this; // self
}
var f = null;
if(typeof(fill) == "object" && "type" in fill){
// gradient or pattern
switch(fill.type){
case "linear":
f = g.makeParameters(g.defaultLinearGradient, fill);
break;
case "radial":
f = g.makeParameters(g.defaultRadialGradient, fill);
break;
case "pattern":
f = g.makeParameters(g.defaultPattern, fill);
break;
}
}else{
// color object
f = g.normalizeColor(fill);
}
this.fillStyle = f;
return this; // self
},
setStroke: function(stroke){
// summary:
// sets a stroke object
// (the default implementation simply ignores it)
// stroke: Object
// a stroke object
// (see dojox/gfx.defaultStroke)
// COULD BE RE-IMPLEMENTED BY THE RENDERER!
if(!stroke){
// don't stroke
this.strokeStyle = null;
return this; // self
}
// normalize the stroke
if(typeof stroke == "string" || lang.isArray(stroke) || stroke instanceof Color){
stroke = {color: stroke};
}
var s = this.strokeStyle = g.makeParameters(g.defaultStroke, stroke);
s.color = g.normalizeColor(s.color);
return this; // self
},
setTransform: function(matrix){
// summary:
// sets a transformation matrix
// matrix: dojox/gfx/matrix.Matrix2D
// a matrix or a matrix-like object
// (see an argument of dojox/gfx/matrix.Matrix2D
// constructor for a list of acceptable arguments)
// COULD BE RE-IMPLEMENTED BY THE RENDERER!
this.matrix = matrixLib.clone(matrix ? matrixLib.normalize(matrix) : matrixLib.identity);
return this._applyTransform(); // self
},
_applyTransform: function(){
// summary:
// physically sets a matrix
// COULD BE RE-IMPLEMENTED BY THE RENDERER!
return this; // self
},
// z-index
moveToFront: function(){
// summary:
// moves a shape to front of its parent's list of shapes
var p = this.getParent();
if(p){
p._moveChildToFront(this);
this._moveToFront(); // execute renderer-specific action
}
return this; // self
},
moveToBack: function(){
// summary:
// moves a shape to back of its parent's list of shapes
var p = this.getParent();
if(p){
p._moveChildToBack(this);
this._moveToBack(); // execute renderer-specific action
}
return this;
},
_moveToFront: function(){
// summary:
// renderer-specific hook, see dojox/gfx/shape.Shape.moveToFront()
// COULD BE RE-IMPLEMENTED BY THE RENDERER!
},
_moveToBack: function(){
// summary:
// renderer-specific hook, see dojox/gfx/shape.Shape.moveToFront()
// COULD BE RE-IMPLEMENTED BY THE RENDERER!
},
// apply left & right transformation
applyRightTransform: function(matrix){
// summary:
// multiplies the existing matrix with an argument on right side
// (this.matrix * matrix)
// matrix: dojox/gfx/matrix.Matrix2D
// a matrix or a matrix-like object
// (see an argument of dojox/gfx/matrix.Matrix2D
// constructor for a list of acceptable arguments)
return matrix ? this.setTransform([this.matrix, matrix]) : this; // self
},
applyLeftTransform: function(matrix){
// summary:
// multiplies the existing matrix with an argument on left side
// (matrix * this.matrix)
// matrix: dojox/gfx/matrix.Matrix2D
// a matrix or a matrix-like object
// (see an argument of dojox/gfx/matrix.Matrix2D
// constructor for a list of acceptable arguments)
return matrix ? this.setTransform([matrix, this.matrix]) : this; // self
},
applyTransform: function(matrix){
// summary:
// a shortcut for dojox/gfx/shape.Shape.applyRightTransform
// matrix: dojox/gfx/matrix.Matrix2D
// a matrix or a matrix-like object
// (see an argument of dojox/gfx/matrix.Matrix2D
// constructor for a list of acceptable arguments)
return matrix ? this.setTransform([this.matrix, matrix]) : this; // self
},
// virtual group methods
removeShape: function(silently){
// summary:
// removes the shape from its parent's list of shapes
// silently: Boolean
// if true, do not redraw a picture yet
if(this.parent){
this.parent.remove(this, silently);
}
return this; // self
},
_setParent: function(parent, matrix){
// summary:
// sets a parent
// parent: Object
// a parent or null
// (see dojox/gfx/shape.Surface,
// or dojox/gfx.Group)
// matrix: dojox/gfx/matrix.Matrix2D
// a 2D matrix or a matrix-like object
this.parent = parent;
return this._updateParentMatrix(matrix); // self
},
_updateParentMatrix: function(matrix){
// summary:
// updates the parent matrix with new matrix
// matrix: dojox/gfx/Matrix2D
// a 2D matrix or a matrix-like object
this.parentMatrix = matrix ? matrixLib.clone(matrix) : null;
return this._applyTransform(); // self
},
_getRealMatrix: function(){
// summary:
// returns the cumulative ('real') transformation matrix
// by combining the shape's matrix with its parent's matrix
var m = this.matrix;
var p = this.parent;
while(p){
if(p.matrix){
m = matrixLib.multiply(p.matrix, m);
}
p = p.parent;
}
return m; // dojox/gfx/matrix.Matrix2D
}
});
shape._eventsProcessing = {
on: function(type, listener){
// summary:
// Connects an event to this shape.
return on(this.getEventSource(), type, shape.fixCallback(this, g.fixTarget, listener));
},
connect: function(name, object, method){
// summary:
// connects a handler to an event on this shape
// COULD BE RE-IMPLEMENTED BY THE RENDERER!
// redirect to fixCallback to normalize events and add the gfxTarget to the event. The latter
// is done by dojox/gfx.fixTarget which is defined by each renderer
if(name.substring(0, 2) == "on"){
name = name.substring(2);
}
return this.on(name, method ? lang.hitch(object, method) : object);
},
disconnect: function(token){
// summary:
// connects a handler by token from an event on this shape
// COULD BE RE-IMPLEMENTED BY THE RENDERER!
return token.remove();
}
};
shape.fixCallback = function(gfxElement, fixFunction, scope, method){
// summary:
// Wraps the callback to allow for tests and event normalization
// before it gets invoked. This is where 'fixTarget' is invoked.
// tags:
// private
// gfxElement: Object
// The GFX object that triggers the action (ex.:
// dojox/gfx.Surface and dojox/gfx/shape.Shape). A new event property
// 'gfxTarget' is added to the event to reference this object.
// for easy manipulation of GFX objects by the event handlers.
// fixFunction: Function
// The function that implements the logic to set the 'gfxTarget'
// property to the event. It should be 'dojox/gfx.fixTarget' for
// most of the cases
// scope: Object
// Optional. The scope to be used when invoking 'method'. If
// omitted, a global scope is used.
// method: Function|String
// The original callback to be invoked.
if(!method){
method = scope;
scope = null;
}
if(lang.isString(method)){
scope = scope || kernel.global;
if(!scope[method]){ throw(['dojox.gfx.shape.fixCallback: scope["', method, '"] is null (scope="', scope, '")'].join('')); }
return function(e){
return fixFunction(e,gfxElement) ? scope[method].apply(scope, arguments || []) : undefined; }; // Function
}
return !scope
? function(e){
return fixFunction(e,gfxElement) ? method.apply(scope, arguments) : undefined; }
: function(e){
return fixFunction(e,gfxElement) ? method.apply(scope, arguments || []) : undefined; }; // Function
};
lang.extend(shape.Shape, shape._eventsProcessing);
shape.Container = {
// summary:
// a container of shapes, which can be used
// as a foundation for renderer-specific groups, or as a way
// to logically group shapes (e.g, to propagate matricies)
_init: function() {
// children: Array
// a list of children
this.children = [];
this._batch = 0;
},
// group management
openBatch: function() {
// summary:
// starts a new batch, subsequent new child shapes will be held in
// the batch instead of appending to the container directly.
// description:
// Because the canvas renderer has no DOM hierarchy, the canvas implementation differs
// such that it suspends the repaint requests for this container until the current batch is closed by a call to closeBatch().
return this;
},
closeBatch: function() {
// summary:
// submits the current batch, append all pending child shapes to DOM
// description:
// On canvas, this method flushes the pending redraws queue.
return this;
},
add: function(shape){
// summary:
// adds a shape to the list
// shape: dojox/gfx/shape.Shape
// the shape to add to the list
var oldParent = shape.getParent();
if(oldParent){
oldParent.remove(shape, true);
}
this.children.push(shape);
return shape._setParent(this, this._getRealMatrix()); // self
},
remove: function(shape, silently){
// summary:
// removes a shape from the list
// shape: dojox/gfx/shape.Shape
// the shape to remove
// silently: Boolean
// if true, do not redraw a picture yet
for(var i = 0; i < this.children.length; ++i){
if(this.children[i] == shape){
if(silently){
// skip for now
}else{
shape.parent = null;
shape.parentMatrix = null;
}
this.children.splice(i, 1);
break;
}
}
return this; // self
},
clear: function(/*Boolean?*/ destroy){
// summary:
// removes all shapes from a group/surface.
// destroy: Boolean
// Indicates whether the children should be destroyed. Optional.
var shape;
for(var i = 0; i < this.children.length;++i){
shape = this.children[i];
shape.parent = null;
shape.parentMatrix = null;
if(destroy){
shape.destroy();
}
}
this.children = [];
return this; // self
},
getBoundingBox: function(){
// summary:
// Returns the bounding box Rectangle for this shape.
if(this.children){
// if this is a composite shape, then sum up all the children
var result = null;
arr.forEach(this.children, function(shape){
var bb = shape.getBoundingBox();
if(bb){
var ct = shape.getTransform();
if(ct){
bb = matrixLib.multiplyRectangle(ct, bb);
}
if(result){
// merge two bbox
result.x = Math.min(result.x, bb.x);
result.y = Math.min(result.y, bb.y);
result.endX = Math.max(result.endX, bb.x + bb.width);
result.endY = Math.max(result.endY, bb.y + bb.height);
}else{
// first bbox
result = {
x: bb.x,
y: bb.y,
endX: bb.x + bb.width,
endY: bb.y + bb.height
};
}
}
});
if(result){
result.width = result.endX - result.x;
result.height = result.endY - result.y;
}
return result; // dojox/gfx.Rectangle
}
// unknown/empty bounding box, subclass shall override this impl
return null;
},
// moving child nodes
_moveChildToFront: function(shape){
// summary:
// moves a shape to front of the list of shapes
// shape: dojox/gfx/shape.Shape
// one of the child shapes to move to the front
for(var i = 0; i < this.children.length; ++i){
if(this.children[i] == shape){
this.children.splice(i, 1);
this.children.push(shape);
break;
}
}
return this; // self
},
_moveChildToBack: function(shape){
// summary:
// moves a shape to back of the list of shapes
// shape: dojox/gfx/shape.Shape
// one of the child shapes to move to the front
for(var i = 0; i < this.children.length; ++i){
if(this.children[i] == shape){
this.children.splice(i, 1);
this.children.unshift(shape);
break;
}
}
return this; // self
}
};
shape.Surface = declare("dojox.gfx.shape.Surface", null, {
// summary:
// a surface object to be used for drawings
constructor: function(){
// underlying node
this.rawNode = null;
// the parent node
this._parent = null;
// the list of DOM nodes to be deleted in the case of destruction
this._nodes = [];
// the list of events to be detached in the case of destruction
this._events = [];
},
destroy: function(){
// summary:
// destroy all relevant external resources and release all
// external references to make this object garbage-collectible
arr.forEach(this._nodes, domConstruct.destroy);
this._nodes = [];
arr.forEach(this._events, function(h){ if(h){ h.remove(); } });
this._events = [];
this.rawNode = null; // recycle it in _nodes, if it needs to be recycled
if(has("ie")){
while(this._parent.lastChild){
domConstruct.destroy(this._parent.lastChild);
}
}else{
this._parent.innerHTML = "";
}
this._parent = null;
},
getEventSource: function(){
// summary:
// returns a node, which can be used to attach event listeners
return this.rawNode; // Node
},
_getRealMatrix: function(){
// summary:
// always returns the identity matrix
return null; // dojox/gfx/Matrix2D
},
/*=====
setDimensions: function(width, height){
// summary:
// sets the width and height of the rawNode
// width: String
// width of surface, e.g., "100px"
// height: String
// height of surface, e.g., "100px"
return this; // self
},
getDimensions: function(){
// summary:
// gets current width and height in pixels
// returns: Object
// object with properties "width" and "height"
},
=====*/
isLoaded: true,
onLoad: function(/*dojox/gfx/shape.Surface*/ surface){
// summary:
// local event, fired once when the surface is created
// asynchronously, used only when isLoaded is false, required
// only for Silverlight.
},
whenLoaded: function(/*Object|Null*/ context, /*Function|String*/ method){
var f = lang.hitch(context, method);
if(this.isLoaded){
f(this);
}else{
on.once(this, "load", function(surface){
f(surface);
});
}
}
});
lang.extend(shape.Surface, shape._eventsProcessing);
/*=====
g.Point = declare("dojox/gfx.Point", null, {
// summary:
// 2D point for drawings - {x, y}
// description:
// Do not use this object directly!
// Use the naked object instead: {x: 1, y: 2}.
});
g.Rectangle = declare("dojox.gfx.Rectangle", null, {
// summary:
// rectangle - {x, y, width, height}
// description:
// Do not use this object directly!
// Use the naked object instead: {x: 1, y: 2, width: 100, height: 200}.
});
=====*/
shape.Rect = declare("dojox.gfx.shape.Rect", shape.Shape, {
// summary:
// a generic rectangle
constructor: function(rawNode){
// rawNode: Node
// The underlying graphics system object (typically a DOM Node)
this.shape = g.getDefault("Rect");
this.rawNode = rawNode;
},
getBoundingBox: function(){
// summary:
// returns the bounding box (its shape in this case)
return this.shape; // dojox/gfx.Rectangle
}
});
shape.Ellipse = declare("dojox.gfx.shape.Ellipse", shape.Shape, {
// summary:
// a generic ellipse
constructor: function(rawNode){
// rawNode: Node
// a DOM Node
this.shape = g.getDefault("Ellipse");
this.rawNode = rawNode;
},
getBoundingBox: function(){
// summary:
// returns the bounding box
if(!this.bbox){
var shape = this.shape;
this.bbox = {x: shape.cx - shape.rx, y: shape.cy - shape.ry,
width: 2 * shape.rx, height: 2 * shape.ry};
}
return this.bbox; // dojox/gfx.Rectangle
}
});
shape.Circle = declare("dojox.gfx.shape.Circle", shape.Shape, {
// summary:
// a generic circle
constructor: function(rawNode){
// rawNode: Node
// a DOM Node
this.shape = g.getDefault("Circle");
this.rawNode = rawNode;
},
getBoundingBox: function(){
// summary:
// returns the bounding box
if(!this.bbox){
var shape = this.shape;
this.bbox = {x: shape.cx - shape.r, y: shape.cy - shape.r,
width: 2 * shape.r, height: 2 * shape.r};
}
return this.bbox; // dojox/gfx.Rectangle
}
});
shape.Line = declare("dojox.gfx.shape.Line", shape.Shape, {
// summary:
// a generic line (do not instantiate it directly)
constructor: function(rawNode){
// rawNode: Node
// a DOM Node
this.shape = g.getDefault("Line");
this.rawNode = rawNode;
},
getBoundingBox: function(){
// summary:
// returns the bounding box
if(!this.bbox){
var shape = this.shape;
this.bbox = {
x: Math.min(shape.x1, shape.x2),
y: Math.min(shape.y1, shape.y2),
width: Math.abs(shape.x2 - shape.x1),
height: Math.abs(shape.y2 - shape.y1)
};
}
return this.bbox; // dojox/gfx.Rectangle
}
});
shape.Polyline = declare("dojox.gfx.shape.Polyline", shape.Shape, {
// summary:
// a generic polyline/polygon (do not instantiate it directly)
constructor: function(rawNode){
// rawNode: Node
// a DOM Node
this.shape = g.getDefault("Polyline");
this.rawNode = rawNode;
},
setShape: function(points, closed){
// summary:
// sets a polyline/polygon shape object
// points: Object|Array
// a polyline/polygon shape object, or an array of points
// closed: Boolean
// close the polyline to make a polygon
if(points && points instanceof Array){
this.inherited(arguments, [{points: points}]);
if(closed && this.shape.points.length){
this.shape.points.push(this.shape.points[0]);
}
}else{
this.inherited(arguments, [points]);
}
return this; // self
},
_normalizePoints: function(){
// summary:
// normalize points to array of {x:number, y:number}
var p = this.shape.points, l = p && p.length;
if(l && typeof p[0] == "number"){
var points = [];
for(var i = 0; i < l; i += 2){
points.push({x: p[i], y: p[i + 1]});
}
this.shape.points = points;
}
},
getBoundingBox: function(){
// summary:
// returns the bounding box
if(!this.bbox && this.shape.points.length){
var p = this.shape.points;
var l = p.length;
var t = p[0];
var bbox = {l: t.x, t: t.y, r: t.x, b: t.y};
for(var i = 1; i < l; ++i){
t = p[i];
if(bbox.l > t.x) bbox.l = t.x;
if(bbox.r < t.x) bbox.r = t.x;
if(bbox.t > t.y) bbox.t = t.y;
if(bbox.b < t.y) bbox.b = t.y;
}
this.bbox = {
x: bbox.l,
y: bbox.t,
width: bbox.r - bbox.l,
height: bbox.b - bbox.t
};
}
return this.bbox; // dojox/gfx.Rectangle
}
});
shape.Image = declare("dojox.gfx.shape.Image", shape.Shape, {
// summary:
// a generic image (do not instantiate it directly)
constructor: function(rawNode){
// rawNode: Node
// a DOM Node
this.shape = g.getDefault("Image");
this.rawNode = rawNode;
},
getBoundingBox: function(){
// summary:
// returns the bounding box (its shape in this case)
return this.shape; // dojox/gfx.Rectangle
},
setStroke: function(){
// summary:
// ignore setting a stroke style
return this; // self
},
setFill: function(){
// summary:
// ignore setting a fill style
return this; // self
}
});
shape.Text = declare(shape.Shape, {
// summary:
// a generic text (do not instantiate it directly)
constructor: function(rawNode){
// rawNode: Node
// a DOM Node
this.fontStyle = null;
this.shape = g.getDefault("Text");
this.rawNode = rawNode;
},
getFont: function(){
// summary:
// returns the current font object or null
return this.fontStyle; // Object
},
setFont: function(newFont){
// summary:
// sets a font for text
// newFont: Object
// a font object (see dojox/gfx.defaultFont) or a font string
this.fontStyle = typeof newFont == "string" ? g.splitFontString(newFont) :
g.makeParameters(g.defaultFont, newFont);
this._setFont();
return this; // self
},
getBoundingBox: function(){
var bbox = null, s = this.getShape();
if(s.text){
bbox = g._base._computeTextBoundingBox(this);
}
return bbox;
}
});
shape.Creator = {
// summary:
// shape creators
createShape: function(shape){
// summary:
// creates a shape object based on its type; it is meant to be used
// by group-like objects
// shape: Object
// a shape descriptor object
// returns: dojox/gfx/shape.Shape | Null
// a fully instantiated surface-specific Shape object
switch(shape.type){
case g.defaultPath.type: return this.createPath(shape);
case g.defaultRect.type: return this.createRect(shape);
case g.defaultCircle.type: return this.createCircle(shape);
case g.defaultEllipse.type: return this.createEllipse(shape);
case g.defaultLine.type: return this.createLine(shape);
case g.defaultPolyline.type: return this.createPolyline(shape);
case g.defaultImage.type: return this.createImage(shape);
case g.defaultText.type: return this.createText(shape);
case g.defaultTextPath.type: return this.createTextPath(shape);
}
return null;
},
createGroup: function(){
// summary:
// creates a group shape
return this.createObject(g.Group); // dojox/gfx/Group
},
createRect: function(rect){
// summary:
// creates a rectangle shape
// rect: Object
// a path object (see dojox/gfx.defaultRect)
return this.createObject(g.Rect, rect); // dojox/gfx/shape.Rect
},
createEllipse: function(ellipse){
// summary:
// creates an ellipse shape
// ellipse: Object
// an ellipse object (see dojox/gfx.defaultEllipse)
return this.createObject(g.Ellipse, ellipse); // dojox/gfx/shape.Ellipse
},
createCircle: function(circle){
// summary:
// creates a circle shape
// circle: Object
// a circle object (see dojox/gfx.defaultCircle)
return this.createObject(g.Circle, circle); // dojox/gfx/shape.Circle
},
createLine: function(line){
// summary:
// creates a line shape
// line: Object
// a line object (see dojox/gfx.defaultLine)
return this.createObject(g.Line, line); // dojox/gfx/shape.Line
},
createPolyline: function(points){
// summary:
// creates a polyline/polygon shape
// points: Object
// a points object (see dojox/gfx.defaultPolyline)
// or an Array of points
return this.createObject(g.Polyline, points); // dojox/gfx/shape.Polyline
},
createImage: function(image){
// summary:
// creates a image shape
// image: Object
// an image object (see dojox/gfx.defaultImage)
return this.createObject(g.Image, image); // dojox/gfx/shape.Image
},
createText: function(text){
// summary:
// creates a text shape
// text: Object
// a text object (see dojox/gfx.defaultText)
return this.createObject(g.Text, text); // dojox/gfx/shape.Text
},
createPath: function(path){
// summary:
// creates a path shape
// path: Object
// a path object (see dojox/gfx.defaultPath)
return this.createObject(g.Path, path); // dojox/gfx/shape.Path
},
createTextPath: function(text){
// summary:
// creates a text shape
// text: Object
// a textpath object (see dojox/gfx.defaultTextPath)
return this.createObject(g.TextPath, {}).setText(text); // dojox/gfx/shape.TextPath
},
createObject: function(shapeType, rawShape){
// summary:
// creates an instance of the passed shapeType class
// shapeType: Function
// a class constructor to create an instance of
// rawShape: Object
// properties to be passed in to the classes 'setShape' method
// SHOULD BE RE-IMPLEMENTED BY THE RENDERER!
return null; // dojox/gfx/shape.Shape
}
};
/*=====
lang.extend(shape.Surface, shape.Container);
lang.extend(shape.Surface, shape.Creator);
g.Group = declare(shape.Shape, {
// summary:
// a group shape, which can be used
// to logically group shapes (e.g, to propagate matricies)
});
lang.extend(g.Group, shape.Container);
lang.extend(g.Group, shape.Creator);
g.Rect = shape.Rect;
g.Circle = shape.Circle;
g.Ellipse = shape.Ellipse;
g.Line = shape.Line;
g.Polyline = shape.Polyline;
g.Text = shape.Text;
g.Surface = shape.Surface;
=====*/
return shape;
});
},
'dojox/gfx/matrix':function(){
define(["./_base","dojo/_base/lang"],
function(g, lang){
var m = g.matrix = {};
// candidates for dojox.math:
var _degToRadCache = {};
m._degToRad = function(degree){
return _degToRadCache[degree] || (_degToRadCache[degree] = (Math.PI * degree / 180));
};
m._radToDeg = function(radian){ return radian / Math.PI * 180; };
m.Matrix2D = function(arg){
// summary:
// a 2D matrix object
// description:
// Normalizes a 2D matrix-like object. If arrays is passed,
// all objects of the array are normalized and multiplied sequentially.
// arg: Object
// a 2D matrix-like object, a number, or an array of such objects
if(arg){
if(typeof arg == "number"){
this.xx = this.yy = arg;
}else if(arg instanceof Array){
if(arg.length > 0){
var matrix = m.normalize(arg[0]);
// combine matrices
for(var i = 1; i < arg.length; ++i){
var l = matrix, r = m.normalize(arg[i]);
matrix = new m.Matrix2D();
matrix.xx = l.xx * r.xx + l.xy * r.yx;
matrix.xy = l.xx * r.xy + l.xy * r.yy;
matrix.yx = l.yx * r.xx + l.yy * r.yx;
matrix.yy = l.yx * r.xy + l.yy * r.yy;
matrix.dx = l.xx * r.dx + l.xy * r.dy + l.dx;
matrix.dy = l.yx * r.dx + l.yy * r.dy + l.dy;
}
lang.mixin(this, matrix);
}
}else{
lang.mixin(this, arg);
}
}
};
// the default (identity) matrix, which is used to fill in missing values
lang.extend(m.Matrix2D, {xx: 1, xy: 0, yx: 0, yy: 1, dx: 0, dy: 0});
lang.mixin(m, {
// summary:
// class constants, and methods of dojox/gfx/matrix
// matrix constants
// identity: dojox/gfx/matrix.Matrix2D
// an identity matrix constant: identity * (x, y) == (x, y)
identity: new m.Matrix2D(),
// flipX: dojox/gfx/matrix.Matrix2D
// a matrix, which reflects points at x = 0 line: flipX * (x, y) == (-x, y)
flipX: new m.Matrix2D({xx: -1}),
// flipY: dojox/gfx/matrix.Matrix2D
// a matrix, which reflects points at y = 0 line: flipY * (x, y) == (x, -y)
flipY: new m.Matrix2D({yy: -1}),
// flipXY: dojox/gfx/matrix.Matrix2D
// a matrix, which reflects points at the origin of coordinates: flipXY * (x, y) == (-x, -y)
flipXY: new m.Matrix2D({xx: -1, yy: -1}),
// matrix creators
translate: function(a, b){
// summary:
// forms a translation matrix
// description:
// The resulting matrix is used to translate (move) points by specified offsets.
// a: Number|dojox/gfx.Point
// an x coordinate value, or a point-like object, which specifies offsets for both dimensions
// b: Number?
// a y coordinate value
// returns: dojox/gfx/matrix.Matrix2D
if(arguments.length > 1){
return new m.Matrix2D({dx: a, dy: b}); // dojox/gfx/matrix.Matrix2D
}
// branch
return new m.Matrix2D({dx: a.x, dy: a.y}); // dojox/gfx/matrix.Matrix2D
},
scale: function(a, b){
// summary:
// forms a scaling matrix
// description:
// The resulting matrix is used to scale (magnify) points by specified offsets.
// a: Number|dojox/gfx.Point
// a scaling factor used for the x coordinate, or
// a uniform scaling factor used for the both coordinates, or
// a point-like object, which specifies scale factors for both dimensions
// b: Number?
// a scaling factor used for the y coordinate
// returns: dojox/gfx/matrix.Matrix2D
if(arguments.length > 1){
return new m.Matrix2D({xx: a, yy: b}); // dojox/gfx/matrix.Matrix2D
}
if(typeof a == "number"){
return new m.Matrix2D({xx: a, yy: a}); // dojox/gfx/matrix.Matrix2D
}
return new m.Matrix2D({xx: a.x, yy: a.y}); // dojox/gfx/matrix.Matrix2D
},
rotate: function(angle){
// summary:
// forms a rotating matrix
// description:
// The resulting matrix is used to rotate points
// around the origin of coordinates (0, 0) by specified angle.
// angle: Number
// an angle of rotation in radians (>0 for CW)
// returns: dojox/gfx/matrix.Matrix2D
var c = Math.cos(angle);
var s = Math.sin(angle);
return new m.Matrix2D({xx: c, xy: -s, yx: s, yy: c}); // dojox/gfx/matrix.Matrix2D
},
rotateg: function(degree){
// summary:
// forms a rotating matrix
// description:
// The resulting matrix is used to rotate points
// around the origin of coordinates (0, 0) by specified degree.
// See dojox/gfx/matrix.rotate() for comparison.
// degree: Number
// an angle of rotation in degrees (>0 for CW)
// returns: dojox/gfx/matrix.Matrix2D
return m.rotate(m._degToRad(degree)); // dojox/gfx/matrix.Matrix2D
},
skewX: function(angle) {
// summary:
// forms an x skewing matrix
// description:
// The resulting matrix is used to skew points in the x dimension
// around the origin of coordinates (0, 0) by specified angle.
// angle: Number
// a skewing angle in radians
// returns: dojox/gfx/matrix.Matrix2D
return new m.Matrix2D({xy: Math.tan(angle)}); // dojox/gfx/matrix.Matrix2D
},
skewXg: function(degree){
// summary:
// forms an x skewing matrix
// description:
// The resulting matrix is used to skew points in the x dimension
// around the origin of coordinates (0, 0) by specified degree.
// See dojox/gfx/matrix.skewX() for comparison.
// degree: Number
// a skewing angle in degrees
// returns: dojox/gfx/matrix.Matrix2D
return m.skewX(m._degToRad(degree)); // dojox/gfx/matrix.Matrix2D
},
skewY: function(angle){
// summary:
// forms a y skewing matrix
// description:
// The resulting matrix is used to skew points in the y dimension
// around the origin of coordinates (0, 0) by specified angle.
// angle: Number
// a skewing angle in radians
// returns: dojox/gfx/matrix.Matrix2D
return new m.Matrix2D({yx: Math.tan(angle)}); // dojox/gfx/matrix.Matrix2D
},
skewYg: function(degree){
// summary:
// forms a y skewing matrix
// description:
// The resulting matrix is used to skew points in the y dimension
// around the origin of coordinates (0, 0) by specified degree.
// See dojox/gfx/matrix.skewY() for comparison.
// degree: Number
// a skewing angle in degrees
// returns: dojox/gfx/matrix.Matrix2D
return m.skewY(m._degToRad(degree)); // dojox/gfx/matrix.Matrix2D
},
reflect: function(a, b){
// summary:
// forms a reflection matrix
// description:
// The resulting matrix is used to reflect points around a vector,
// which goes through the origin.
// a: dojox/gfx.Point|Number
// a point-like object, which specifies a vector of reflection, or an X value
// b: Number?
// a Y value
// returns: dojox/gfx/matrix.Matrix2D
if(arguments.length == 1){
b = a.y;
a = a.x;
}
// make a unit vector
var a2 = a * a, b2 = b * b, n2 = a2 + b2, xy = 2 * a * b / n2;
return new m.Matrix2D({xx: 2 * a2 / n2 - 1, xy: xy, yx: xy, yy: 2 * b2 / n2 - 1}); // dojox/gfx/matrix.Matrix2D
},
project: function(a, b){
// summary:
// forms an orthogonal projection matrix
// description:
// The resulting matrix is used to project points orthogonally on a vector,
// which goes through the origin.
// a: dojox/gfx.Point|Number
// a point-like object, which specifies a vector of projection, or
// an x coordinate value
// b: Number?
// a y coordinate value
// returns: dojox/gfx/matrix.Matrix2D
if(arguments.length == 1){
b = a.y;
a = a.x;
}
// make a unit vector
var a2 = a * a, b2 = b * b, n2 = a2 + b2, xy = a * b / n2;
return new m.Matrix2D({xx: a2 / n2, xy: xy, yx: xy, yy: b2 / n2}); // dojox/gfx/matrix.Matrix2D
},
// ensure matrix 2D conformance
normalize: function(matrix){
// summary:
// converts an object to a matrix, if necessary
// description:
// Converts any 2D matrix-like object or an array of
// such objects to a valid dojox/gfx/matrix.Matrix2D object.
// matrix: Object
// an object, which is converted to a matrix, if necessary
// returns: dojox/gfx/matrix.Matrix2D
return (matrix instanceof m.Matrix2D) ? matrix : new m.Matrix2D(matrix); // dojox/gfx/matrix.Matrix2D
},
// common operations
isIdentity: function(matrix){
// summary:
// returns whether the specified matrix is the identity.
// matrix: dojox/gfx/matrix.Matrix2D
// a 2D matrix object to be tested
// returns: Boolean
return matrix.xx == 1 && matrix.xy == 0 && matrix.yx == 0 && matrix.yy == 1 && matrix.dx == 0 && matrix.dy == 0; // Boolean
},
clone: function(matrix){
// summary:
// creates a copy of a 2D matrix
// matrix: dojox/gfx/matrix.Matrix2D
// a 2D matrix-like object to be cloned
// returns: dojox/gfx/matrix.Matrix2D
var obj = new m.Matrix2D();
for(var i in matrix){
if(typeof(matrix[i]) == "number" && typeof(obj[i]) == "number" && obj[i] != matrix[i]) obj[i] = matrix[i];
}
return obj; // dojox/gfx/matrix.Matrix2D
},
invert: function(matrix){
// summary:
// inverts a 2D matrix
// matrix: dojox/gfx/matrix.Matrix2D
// a 2D matrix-like object to be inverted
// returns: dojox/gfx/matrix.Matrix2D
var M = m.normalize(matrix),
D = M.xx * M.yy - M.xy * M.yx;
M = new m.Matrix2D({
xx: M.yy/D, xy: -M.xy/D,
yx: -M.yx/D, yy: M.xx/D,
dx: (M.xy * M.dy - M.yy * M.dx) / D,
dy: (M.yx * M.dx - M.xx * M.dy) / D
});
return M; // dojox/gfx/matrix.Matrix2D
},
_multiplyPoint: function(matrix, x, y){
// summary:
// applies a matrix to a point
// matrix: dojox/gfx/matrix.Matrix2D
// a 2D matrix object to be applied
// x: Number
// an x coordinate of a point
// y: Number
// a y coordinate of a point
// returns: dojox/gfx.Point
return {x: matrix.xx * x + matrix.xy * y + matrix.dx, y: matrix.yx * x + matrix.yy * y + matrix.dy}; // dojox/gfx.Point
},
multiplyPoint: function(matrix, /* Number||Point */ a, /* Number? */ b){
// summary:
// applies a matrix to a point
// matrix: dojox/gfx/matrix.Matrix2D
// a 2D matrix object to be applied
// a: Number|dojox/gfx.Point
// an x coordinate of a point, or a point
// b: Number?
// a y coordinate of a point
// returns: dojox/gfx.Point
var M = m.normalize(matrix);
if(typeof a == "number" && typeof b == "number"){
return m._multiplyPoint(M, a, b); // dojox/gfx.Point
}
return m._multiplyPoint(M, a.x, a.y); // dojox/gfx.Point
},
multiplyRectangle: function(matrix, /*Rectangle*/ rect){
// summary:
// Applies a matrix to a rectangle.
// description:
// The method applies the transformation on all corners of the
// rectangle and returns the smallest rectangle enclosing the 4 transformed
// points.
// matrix: dojox/gfx/matrix.Matrix2D
// a 2D matrix object to be applied.
// rect: Rectangle
// the rectangle to transform.
// returns: dojox/gfx.Rectangle
var M = m.normalize(matrix);
rect = rect || {x:0, y:0, width:0, height:0};
if(m.isIdentity(M))
return {x: rect.x, y: rect.y, width: rect.width, height: rect.height}; // dojo/gfx.Rectangle
var p0 = m.multiplyPoint(M, rect.x, rect.y),
p1 = m.multiplyPoint(M, rect.x, rect.y + rect.height),
p2 = m.multiplyPoint(M, rect.x + rect.width, rect.y),
p3 = m.multiplyPoint(M, rect.x + rect.width, rect.y + rect.height),
minx = Math.min(p0.x, p1.x, p2.x, p3.x),
miny = Math.min(p0.y, p1.y, p2.y, p3.y),
maxx = Math.max(p0.x, p1.x, p2.x, p3.x),
maxy = Math.max(p0.y, p1.y, p2.y, p3.y);
return{ // dojo/gfx.Rectangle
x: minx,
y: miny,
width: maxx - minx,
height: maxy - miny
};
},
multiply: function(matrix){
// summary:
// combines matrices by multiplying them sequentially in the given order
// matrix: dojox/gfx/matrix.Matrix2D
// a 2D matrix-like object,
// all subsequent arguments are matrix-like objects too
var M = m.normalize(matrix);
// combine matrices
for(var i = 1; i < arguments.length; ++i){
var l = M, r = m.normalize(arguments[i]);
M = new m.Matrix2D();
M.xx = l.xx * r.xx + l.xy * r.yx;
M.xy = l.xx * r.xy + l.xy * r.yy;
M.yx = l.yx * r.xx + l.yy * r.yx;
M.yy = l.yx * r.xy + l.yy * r.yy;
M.dx = l.xx * r.dx + l.xy * r.dy + l.dx;
M.dy = l.yx * r.dx + l.yy * r.dy + l.dy;
}
return M; // dojox/gfx/matrix.Matrix2D
},
// high level operations
_sandwich: function(matrix, x, y){
// summary:
// applies a matrix at a central point
// matrix: dojox/gfx/matrix.Matrix2D
// a 2D matrix-like object, which is applied at a central point
// x: Number
// an x component of the central point
// y: Number
// a y component of the central point
return m.multiply(m.translate(x, y), matrix, m.translate(-x, -y)); // dojox/gfx/matrix.Matrix2D
},
scaleAt: function(a, b, c, d){
// summary:
// scales a picture using a specified point as a center of scaling
// description:
// Compare with dojox/gfx/matrix.scale().
// a: Number
// a scaling factor used for the x coordinate, or a uniform scaling factor used for both coordinates
// b: Number?
// a scaling factor used for the y coordinate
// c: Number|Point
// an x component of a central point, or a central point
// d: Number
// a y component of a central point
// returns: dojox/gfx/matrix.Matrix2D
switch(arguments.length){
case 4:
// a and b are scale factor components, c and d are components of a point
return m._sandwich(m.scale(a, b), c, d); // dojox/gfx/matrix.Matrix2D
case 3:
if(typeof c == "number"){
return m._sandwich(m.scale(a), b, c); // dojox/gfx/matrix.Matrix2D
}
return m._sandwich(m.scale(a, b), c.x, c.y); // dojox/gfx/matrix.Matrix2D
}
return m._sandwich(m.scale(a), b.x, b.y); // dojox/gfx/matrix.Matrix2D
},
rotateAt: function(angle, a, b){
// summary:
// rotates a picture using a specified point as a center of rotation
// description:
// Compare with dojox/gfx/matrix.rotate().
// angle: Number
// an angle of rotation in radians (>0 for CW)
// a: Number|dojox/gfx.Point
// an x component of a central point, or a central point
// b: Number?
// a y component of a central point
// returns: dojox/gfx/matrix.Matrix2D
if(arguments.length > 2){
return m._sandwich(m.rotate(angle), a, b); // dojox/gfx/matrix.Matrix2D
}
return m._sandwich(m.rotate(angle), a.x, a.y); // dojox/gfx/matrix.Matrix2D
},
rotategAt: function(degree, a, b){
// summary:
// rotates a picture using a specified point as a center of rotation
// description:
// Compare with dojox/gfx/matrix.rotateg().
// degree: Number
// an angle of rotation in degrees (>0 for CW)
// a: Number|dojox/gfx.Point
// an x component of a central point, or a central point
// b: Number?
// a y component of a central point
// returns: dojox/gfx/matrix.Matrix2D
if(arguments.length > 2){
return m._sandwich(m.rotateg(degree), a, b); // dojox/gfx/matrix.Matrix2D
}
return m._sandwich(m.rotateg(degree), a.x, a.y); // dojox/gfx/matrix.Matrix2D
},
skewXAt: function(angle, a, b){
// summary:
// skews a picture along the x axis using a specified point as a center of skewing
// description:
// Compare with dojox/gfx/matrix.skewX().
// angle: Number
// a skewing angle in radians
// a: Number|dojox/gfx.Point
// an x component of a central point, or a central point
// b: Number?
// a y component of a central point
// returns: dojox/gfx/matrix.Matrix2D
if(arguments.length > 2){
return m._sandwich(m.skewX(angle), a, b); // dojox/gfx/matrix.Matrix2D
}
return m._sandwich(m.skewX(angle), a.x, a.y); // dojox/gfx/matrix.Matrix2D
},
skewXgAt: function(degree, a, b){
// summary:
// skews a picture along the x axis using a specified point as a center of skewing
// description:
// Compare with dojox/gfx/matrix.skewXg().
// degree: Number
// a skewing angle in degrees
// a: Number|dojox/gfx.Point
// an x component of a central point, or a central point
// b: Number?
// a y component of a central point
// returns: dojox/gfx/matrix.Matrix2D
if(arguments.length > 2){
return m._sandwich(m.skewXg(degree), a, b); // dojox/gfx/matrix.Matrix2D
}
return m._sandwich(m.skewXg(degree), a.x, a.y); // dojox/gfx/matrix.Matrix2D
},
skewYAt: function(angle, a, b){
// summary:
// skews a picture along the y axis using a specified point as a center of skewing
// description:
// Compare with dojox/gfx/matrix.skewY().
// angle: Number
// a skewing angle in radians
// a: Number|dojox/gfx.Point
// an x component of a central point, or a central point
// b: Number?
// a y component of a central point
// returns: dojox/gfx/matrix.Matrix2D
if(arguments.length > 2){
return m._sandwich(m.skewY(angle), a, b); // dojox/gfx/matrix.Matrix2D
}
return m._sandwich(m.skewY(angle), a.x, a.y); // dojox/gfx/matrix.Matrix2D
},
skewYgAt: function(/* Number */ degree, /* Number||Point */ a, /* Number? */ b){
// summary:
// skews a picture along the y axis using a specified point as a center of skewing
// description:
// Compare with dojox/gfx/matrix.skewYg().
// degree: Number
// a skewing angle in degrees
// a: Number|dojox/gfx.Point
// an x component of a central point, or a central point
// b: Number?
// a y component of a central point
// returns: dojox/gfx/matrix.Matrix2D
if(arguments.length > 2){
return m._sandwich(m.skewYg(degree), a, b); // dojox/gfx/matrix.Matrix2D
}
return m._sandwich(m.skewYg(degree), a.x, a.y); // dojox/gfx/matrix.Matrix2D
}
//TODO: rect-to-rect mapping, scale-to-fit (isotropic and anisotropic versions)
});
// propagate Matrix2D up
g.Matrix2D = m.Matrix2D;
return m;
});
},
'dojox/geo/openlayers/GfxLayer':function(){
define([
"dojo/_base/declare",
"dojo/_base/connect",
"dojo/dom-style",
"dojox/gfx",
"dojox/gfx/matrix",
"./Feature",
"./Layer"
], function(declare, connect, style, gfx, matrix, Feature, Layer){
return declare("dojox.geo.openlayers.GfxLayer", Layer, {
// summary:
// A layer dedicated to render dojox.geo.openlayers.GeometryFeature
// description:
// A layer class for rendering geometries as dojox.gfx.Shape objects.
// This layer class accepts Features which encapsulates graphic objects to be added to the map.
// All objects should be added to this group.
// tags:
// private
_viewport: null,
constructor: function(name, options){
// summary:
// Constructs a new GFX layer.
var s = gfx.createSurface(this.olLayer.div, 100, 100);
this._surface = s;
var vp;
if(options && options.viewport){
vp = options.viewport;
}else{
vp = s.createGroup();
}
this.setViewport(vp);
connect.connect(this.olLayer, "onMapResize", this, "onMapResize");
this.olLayer.getDataExtent = this.getDataExtent;
},
getViewport: function(){
// summary:
// Gets the viewport
// tags:
// internal
return this._viewport;
},
setViewport: function(g){
// summary:
// Sets the viewport
// g: dojox.gfx.Group
// tags:
// internal
if(this._viewport){
this._viewport.removeShape();
}
this._viewport = g;
this._surface.add(g);
},
onMapResize: function(){
// summary:
// Called when map is resized.
// tags:
// protected
this._surfaceSize();
},
setMap: function(map){
// summary:
// Sets the map for this layer.
// tags:
// protected
this.inherited(arguments);
this._surfaceSize();
},
getDataExtent: function(){
// summary:
// Get data extent
// tags:
// private
var ret = this._surface.getDimensions();
return ret;
},
getSurface: function(){
// summary:
// Get the underlying dojox.gfx.Surface
// returns:
// The dojox.gfx.Surface this layer uses to draw its GFX rendering.
return this._surface; // dojox.gfx.Surface
},
_surfaceSize: function(){
// summary:
// Recomputes the surface size when being resized.
// tags:
// private
var s = this.olLayer.map.getSize();
this._surface.setDimensions(s.w, s.h);
},
moveTo: function(event){
// summary:
// Called when this layer is moved or zoomed.
// event:
// The event
var s = style.get(this.olLayer.map.layerContainerDiv);
var left = parseInt(s.left);
var top = parseInt(s.top);
if(event.zoomChanged || left || top){
var d = this.olLayer.div;
style.set(d, {
left: -left + "px",
top: -top + "px"
});
if(this._features == null){
return;
}
var vp = this.getViewport();
vp.setTransform(matrix.translate(left, top));
this.inherited(arguments);
}
},
added: function(){
// summary:
// Called when added to a map.
this.inherited(arguments);
this._surfaceSize();
}
});
});
},
'dojox/geo/openlayers/Collection':function(){
define([
"dojo/_base/declare",
"./Geometry"
], function(declare, Geometry){
return declare("dojox.geo.openlayers.Collection", Geometry, {
// summary:
// A collection of geometries.
// coordinates: Array
// An array of geometries.
coordinates:null,
setGeometries: function(g){
// summary:
// Sets the geometries
// g: Array
// The array of geometries.
this.coordinates = g;
},
getGeometries: function(){
// summary:
// Returns the geometries.
// returns:
// The array of geometries defining this collection.
return this.coordinates; // Array
}
});
});
},
'dojox/geo/openlayers/Geometry':function(){
define([
"dojo/_base/declare"
], function(declare){
return declare("dojox.geo.openlayers.Geometry", null, {
// summary:
// A Geometry handles description of shapes to be rendered in a GfxLayer
// using a GeometryFeature feature.
// A Geometry can be:
//
// - A point geometry of type dojox.geo.openlayers.Point. Coordinates are a an
// Object {x, y}
// - A line string geometry of type dojox.geo.openlayers.LineString. Coordinates are
// an array of {x, y} objects
// - A collection geometry of type dojox.geo.openlayers.Collection. Coordinates are an array of geometries.
// coordinates: Object|Array
// The coordinates of the geometry, Object like {x, y} or Array.
coordinates : null,
// shape: [private] dojox/gfx/shape.Shape
// The associated shape when rendered
shape: null,
constructor: function(coords){
// summary:
// Constructs a new geometry
// coords: Object
// Coordinates of the geometry. {x:``x``, y:``y``} object for a point geometry, array of {x:``x``, y:``y``}
// objects for line string geometry, array of geometries for collection geometry.
this.coordinates = coords;
}
});
});
},
'dojox/geo/openlayers/GeometryFeature':function(){
define([
"dojo/_base/declare",
"dojo/_base/array",
"dojo/_base/lang",
"dojox/gfx/matrix",
"./Point",
"./LineString",
"./Collection",
"./Feature"
], function(declare, array, lang, matrix, Point, LineString, Collection, Feature){
return declare("dojox.geo.openlayers.GeometryFeature", Feature, {
// summary:
// A Feature encapsulating a geometry.
// description:
// This Feature renders a geometry such as a Point or LineString geometry. This Feature
// is responsible for reprojecting the geometry before creating a gfx shape to display it.
// By default the shape created is a circle for a Point geometry and a polyline for a
// LineString geometry. User can change these behavior by overriding the createShape
// method to create the desired shape.
// example:
// | var geom = new dojox.geo.openlayers.Point({x:0, y:0});
// | var gf = new dojox.geo.openlayers.GeometryFeature(geom);
constructor: function(geometry){
// summary:
// Constructs a GeometryFeature for the specified geometry.
// geometry: dojox/geo/openlayers/Geometry
// The geometry to render.
this._geometry = geometry;
this._shapeProperties = {};
this._fill = null;
this._stroke = null;
},
_createCollection: function(/* dojox/geo/openlayers/Geometry */g){
// summary:
// Create collection shape and add it to the viewport.
// tags:
// private
var layer = this.getLayer();
var s = layer.getSurface();
var c = this.createShape(s, g);
var vp = layer.getViewport();
vp.add(c);
return c;
},
_getCollectionShape: function(/* dojox/geo/openlayers/Geometry */g){
// summary:
// Get the collection shape, create it if necessary
// tags:
// private
var s = g.shape;
if(s == null){
s = this._createCollection(g);
g.shape = s;
}
return s;
},
renderCollection: function(g){
// summary:
// Renders a geometry collection.
// g: dojox.geo.openlayers.Geometry?
// The geometry to render.
if(g == undefined){
g = this._geometry;
}
s = this._getCollectionShape(g);
var prop = this.getShapeProperties();
s.setShape(prop);
array.forEach(g.coordinates, function(item){
if(item instanceof Point){
this.renderPoint(item);
}else if(item instanceof LineString){
this.renderLineString(item);
}else if(item instanceof Collection){
this.renderCollection(item);
}else{
throw new Error();
}
}, this);
this._applyStyle(g);
},
render: function(g){
// summary:
// Render a geometry.
// Called by the Layer on which the feature is added.
// g: dojox/geo/openlayer/Geometry?
// The geometry to draw
if(g == undefined){
g = this._geometry;
}
if(g instanceof Point){
this.renderPoint(g);
}else if(g instanceof LineString){
this.renderLineString(g);
}else if(g instanceof Collection){
this.renderCollection(g);
}else{
throw new Error();
}
},
getShapeProperties: function(){
// summary:
// Returns the shape properties.
// returns: Object
// The shape properties.
return this._shapeProperties;
},
setShapeProperties: function(s){
// summary:
// Sets the shape properties.
// s: Object
// The shape properties to set.
this._shapeProperties = s;
return this;
},
createShape: function(s, g){
// summary:
// Called when the shape rendering the geometry has to be created.
// This default implementation creates a circle for a point geometry, a polyline for
// a LineString geometry and is recursively called when creating a collection.
// User may replace this method to produce a custom shape.
// s: dojox/gfx/Surface
// The surface on which the method create the shapes.
// g: dojox/geo/openlayers/Geometry?
// The reference geometry
// returns:
// The resulting shape.
if(!g){
g = this._geometry;
}
var shape = null;
if(g instanceof Point){
shape = s.createCircle();
}else if(g instanceof LineString){
shape = s.createPolyline();
}else if(g instanceof Collection){
var grp = s.createGroup();
array.forEach(g.coordinates, function(item){
var shp = this.createShape(s, item);
grp.add(shp);
}, this);
shape = grp;
}else{
throw new Error();
}
return shape;
},
getShape: function(){
// summary:
// Returns the shape rendering the geometry
// returns:
// The shape used to render the geometry.
var g = this._geometry;
if(!g){
return null;
}
if(g.shape){
return g.shape;
}
this.render();
return g.shape; // dojox.gfx.shape.Shape
},
_createPoint: function(/* dojox/geo/openlayer/Geometry */g){
// summary:
// Create a point shape
// tags:
// private
var layer = this.getLayer();
var s = layer.getSurface();
var c = this.createShape(s, g);
var vp = layer.getViewport();
vp.add(c);
return c;
},
_getPointShape: function(/* dojox/geo/openlayers/Geometry */g){
// summary:
// get the point geometry shape, create it if necessary
// tags:
// private
var s = g.shape;
if(s == null){
s = this._createPoint(g);
g.shape = s;
}
return s;
},
renderPoint: function(g){
// summary:
// Renders a point geometry.
// g: dojox/geo/openlayers/Point?
// The geometry to render, or the current instance geometry if not specified.
if(g == undefined){
g = this._geometry;
}
var layer = this.getLayer();
var map = layer.getDojoMap();
s = this._getPointShape(g);
var prop = lang.mixin({}, this._defaults.pointShape);
prop = lang.mixin(prop, this.getShapeProperties());
s.setShape(prop);
var from = this.getCoordinateSystem();
var p = map.transform(g.coordinates, from);
var a = this._getLocalXY(p);
var cx = a[0];
var cy = a[1];
var tr = layer.getViewport().getTransform();
if(tr){
s.setTransform(matrix.translate(cx - tr.dx, cy - tr.dy));
}
this._applyStyle(g);
},
_createLineString: function(/* dojox/geo/openlayers/Geometry */g){
// summary:
// Create polyline shape and add it to the viewport.
// tags:
// private
var layer = this.getLayer();
var s = layer._surface;
var shape = this.createShape(s, g);
var vp = layer.getViewport();
vp.add(shape);
g.shape = shape;
return shape;
},
_getLineStringShape: function(/* dojox/geo/openlayers/Geometry */g){
// summary:
// Get the line string geometry shape, create it if necessary
// tags:
// private
var s = g.shape;
if(s == null){
s = this._createLineString(g);
g.shape = s;
}
return s;
},
renderLineString: function(g){
// summary:
// Renders a line string geometry.
// g: dojox/geo/openlayers/Geometry?
// The geometry to render.
if(g == undefined){
g = this._geometry;
}
var layer = this.getLayer();
var map = layer.getDojoMap();
var lss = this._getLineStringShape(g);
var from = this.getCoordinateSystem();
var points = new Array(g.coordinates.length); // ss.getShape().points;
var tr = layer.getViewport().getTransform();
array.forEach(g.coordinates, function(c, i, array){
var p = map.transform(c, from);
var a = this._getLocalXY(p);
if(tr){
a[0] -= tr.dx;
a[1] -= tr.dy;
}
points[i] = {
x: a[0],
y: a[1]
};
}, this);
var prop = lang.mixin({}, this._defaults.lineStringShape);
prop = lang.mixin(prop, this.getShapeProperties());
prop = lang.mixin(prop, {
points: points
});
lss.setShape(prop);
this._applyStyle(g);
},
_applyStyle: function(g){
// summary:
// Apply the style on the geometry's shape.
// g: Geometry
// The geometry.
// tags:
// private
if(!g || !g.shape){
return;
}
var f = this.getFill();
var fill;
if(!f || lang.isString(f) || lang.isArray(f)){
fill = f;
}else{
fill = lang.mixin({}, this._defaults.fill);
fill = lang.mixin(fill, f);
}
var s = this.getStroke();
var stroke;
if(!s || lang.isString(s) || lang.isArray(s)){
stroke = s;
}else{
stroke = lang.mixin({}, this._defaults.stroke);
stroke = lang.mixin(stroke, s);
}
this._applyRecusiveStyle(g, stroke, fill);
},
_applyRecusiveStyle: function(g, stroke, fill){
// summary:
// Apply the style on the geometry's shape recursively.
// g: dojox.geo.openlayers.Geometry
// The geometry.
// stroke: Object
// The stroke
// fill:Object
// The fill
// tags:
// private
var shp = g.shape;
if(shp.setFill){
shp.setFill(fill);
}
if(shp.setStroke){
shp.setStroke(stroke);
}
if(g instanceof Collection){
array.forEach(g.coordinates, function(i){
this._applyRecusiveStyle(i, stroke, fill);
}, this);
}
},
setStroke: function(s){
// summary:
// Set the stroke style to be applied on the rendered shape.
// s: Object
// The stroke style
this._stroke = s;
return this;
},
getStroke: function(){
// summary:
// Returns the stroke style
// returns:
// The stroke style
return this._stroke;
},
setFill: function(f){
// summary:
// Set the fill style to be applied on the rendered shape.
// f: Object
// The fill style
this._fill = f;
return this;
},
getFill: function(){
// summary:
// Returns the fill style
// returns:
// The fill style
return this._fill;
},
remove: function(){
// summary:
// Removes the shape from the Surface.
// Called when the feature is removed from the layer.
var g = this._geometry;
var shp = g.shape;
g.shape = null;
if(shp){
shp.removeShape();
}
if(g instanceof Collection){
array.forEach(g.coordinates, function(i){
this.remove(i);
}, this);
}
},
_defaults: {
fill: null,
stroke: null,
pointShape: {
r: 30
},
lineStringShape: null
}
});
});
},
'dojox/geo/openlayers/Point':function(){
define([
"dojo/_base/declare",
"./Geometry"
], function(declare, Geometry){
return declare("dojox.geo.openlayers.Point", Geometry, {
// summary:
// A Point geometry handles description of points to be rendered in a GfxLayer
setPoint: function(p){
// summary:
// Sets the point for this geometry.
// p: Object
// The point geometry expressed as a {x, y} object.
this.coordinates = p;
},
getPoint: function(){
// summary:
// Gets the point defining this geometry.
// returns:
// The point defining this geometry.
return this.coordinates; // Object
}
});
});
},
'dojox/geo/openlayers/LineString':function(){
define([
"dojo/_base/declare",
"./Geometry"
], function(declare, Geometry){
return declare("dojox.geo.openlayers.LineString", Geometry, {
// summary:
// The `dojox.geo.openlayers.LineString` geometry. This geometry holds an array
// of coordinates.
setPoints: function(p){
// summary:
// Sets the points for this geometry.
// p: Object[]
// An array of {x, y} objects
this.coordinates = p;
},
getPoints: function(){
// summary:
// Gets the points of this geometry.
// returns:
// The points of this geometry.
return this.coordinates; // Object[]
}
});
});
},
'dojox/geo/openlayers/JsonImport':function(){
define([
"dojo/_base/declare",
"dojo/_base/xhr",
"dojo/_base/lang",
"dojo/_base/array",
"./LineString",
"./Collection",
"./GeometryFeature"
], function(declare, xhr, lang, array, LineString, Collection, GeometryFeature){
/*=====
dojox.geo.openlayers.__JsonImportArgs = {
// summary:
// The keyword arguments that can be passed in a JsonImport constructor.
// url: String
// The url pointing to the JSON file to load.
// nextFeature: function
// The function called each time a feature is read. The function is called with a GeometryFeature as argument.
// error: function
// Error callback called if something fails.
};
=====*/
return declare("dojox.geo.openlayers.JsonImport", null, {
// summary:
// Class to load JSON formated ShapeFile as output of the JSon Custom Map Converter.
// description:
// This class loads JSON formated ShapeFile produced by the JSon Custom Map Converter.
// When loading the JSON file, it calls a iterator function each time a feature is read.
// This iterator function is provided as parameter to the constructor.
//
constructor : function(params){
// summary:
// Construct a new JSON importer.
// params: dojox.geo.openlayers.__JsonImportArgs
// The parameters to initialize this JsonImport instance.
this._params = params;
},
loadData: function(){
// summary:
// Triggers the loading.
var p = this._params;
xhr.get({
url: p.url,
handleAs: "json",
sync: true,
load: lang.hitch(this, this._gotData),
error: lang.hitch(this, this._loadError)
});
},
_gotData: function(/* Object */items){
// summary:
// Called when loading is complete.
// tags:
// private
var nf = this._params.nextFeature;
if(!lang.isFunction(nf)){
return;
}
var extent = items.layerExtent;
var ulx = extent[0];
var uly = extent[1];
var lrx = ulx + extent[2];
var lry = uly + extent[3];
var extentLL = items.layerExtentLL;
var x1 = extentLL[0];
var y1 = extentLL[1];
var x2 = x1 + extentLL[2];
var y2 = y1 + extentLL[3];
var ulxLL = x1;
var ulyLL = y2;
var lrxLL = x2;
var lryLL = y1;
var features = items.features;
for( var f in features){
var o = features[f];
var s = o["shape"];
var gf = null;
if(lang.isArray(s[0])){
var a = new Array();
array.forEach(s, function(item){
var ls = this._makeGeometry(item, ulx, uly, lrx, lry, ulxLL, ulyLL, lrxLL, lryLL);
a.push(ls);
}, this);
var g = new Collection(a);
gf = new GeometryFeature(g);
nf.call(this, gf);
}else{
gf = this._makeFeature(s, ulx, uly, lrx, lry, ulxLL, ulyLL, lrxLL, lryLL);
nf.call(this, gf);
}
}
var complete = this._params.complete;
if(lang.isFunction(complete)){
complete.call(this, complete);
}
},
_makeGeometry: function(/* Array */s, /* Float */ulx, /* Float */uly, /* Float */lrx, /* Float */
lry, /* Float */ulxLL, /* Float */ulyLL, /* Float */lrxLL, /* Float */lryLL){
// summary:
// Make a geometry with the specified points.
// tags:
// private
var a = [];
var k = 0.0;
for( var i = 0; i < s.length - 1; i += 2){
var x = s[i];
var y = s[i + 1];
k = (x - ulx) / (lrx - ulx);
var px = k * (lrxLL - ulxLL) + ulxLL;
k = (y - uly) / (lry - uly);
var py = k * (lryLL - ulyLL) + ulyLL;
a.push({
x: px,
y: py
});
}
var ls = new LineString(a);
return ls; // LineString
},
_makeFeature: function(/* Array */s, /* Float */ulx, /* Float */uly, /* Float */lrx, /* Float */
lry, /* Float */ulxLL, /* Float */ulyLL, /* Float */lrxLL, /* Float */lryLL){
// summary:
// Make a GeometryFeature with the specified points.
// tags:
// private
var ls = this._makeGeometry(s, ulx, uly, lrx, lry, ulxLL, ulyLL, lrxLL, lryLL);
var gf = new GeometryFeature(ls);
return gf;
},
_loadError: function(){
// summary:
// Called when an error occurs. Calls the error function is provided in the parameters.
// tags:
// private
var f = this._params.error;
if(lang.isFunction(f)){
f.apply(this, parameters);
}
}
});
});
},
'dojox/geo/openlayers/WidgetFeature':function(){
define([
"dojo/_base/declare",
"dojo/dom-style",
"dojo/_base/lang",
"dijit/registry",
"./Feature"
], function(declare, style, lang, registry, Feature){
/*=====
dojox.geo.openlayers.__WidgetFeatureArgs = {
// summary:
// The keyword arguments that can be passed in a WidgetFeature constructor.
// You must define a least one widget retrieval parameter and the geo-localization parameters.
// createWidget: Function?
// Function for widget creation. Must return a `dijit._Widget.
// dojoType: String?
// The class of a widget to create.
// dijitId: String?
// The digitId of an existing widget.
// widget: dijit._Widget?
// An already created widget.
// width: Number?
// The width of the widget.
// height: Number?
// The height of the widget.
// longitude: Number
// The longitude, in decimal degrees where to place the widget.
// latitude: Number
// The latitude, in decimal degrees where to place the widget.
};
=====*/
return declare("dojox.geo.openlayers.WidgetFeature", Feature, {
// summary:
// Wraps a Dojo widget, provide geolocalisation of the widget and interface
// to Layer class.
// description:
// This class allows to add a widget in a `dojox.geo.openlayers.Layer`.
_widget: null,
_bbox: null,
constructor: function(params){
// summary:
// Constructs a new `dojox.geo.openlayers.WidgetFeature`
// params: dojox.geo.openlayers.__WidgetFeatureArgs
// The parameters describing the widget.
this._params = params;
},
setParameters: function(params){
// summary:
// Sets the parameters describing the widget.
// params: dojox.geo.openlayers.__WidgetFeatureArgs
// The parameters describing the widget.
this._params = params;
},
getParameters: function(){
// summary:
// Returns the parameters describing the widget.
// returns: dojox.geo.openlayers.__WidgetFeatureArgs
// The parameters describing the widget.
return this._params;
},
_getWidget: function(){
// summary:
// Creates, if necessary the widget and returns it
// tags:
// private
var params = this._params;
if((this._widget == null) && (params != null)){
var w = null;
if(typeof (params.createWidget) == "function"){
w = params.createWidget.call(this);
}else if(params.dojoType){
dojo["require"](params.dojoType);
var c = lang.getObject(params.dojoType);
w = new c(params);
}else if(params.dijitId){
w = registry.byId(params.dijitId);
}else if(params.widget){
w = params.widget;
}
if(w != null){
this._widget = w;
if(typeof (w.startup) == "function"){
w.startup();
}
var n = w.domNode;
if(n != null){
style.set(n, {
position: "absolute"
});
}
}
this._widget = w;
}
return this._widget;
},
_getWidgetWidth: function(){
// summary:
// gets the widget width
// tags:
// private
var p = this._params;
if(p.width){
return p.width;
}
var w = this._getWidget();
if(w){
return style.get(w.domNode, "width");
}
return 10;
},
_getWidgetHeight: function(){
// summary:
// gets the widget height
// tags:
// private
var p = this._params;
if(p.height){
return p.height;
}
var w = this._getWidget();
if(w){
return style.get(w.domNode, "height");
}
return 10;
},
render: function(){
// summary:
// renders the widget.
// description:
// Places the widget accordingly to longitude and latitude defined in parameters.
// This function is called when the center of the maps or zoom factor changes.
var layer = this.getLayer();
var widget = this._getWidget();
if(widget == null){
return;
}
var params = this._params;
var lon = params.longitude;
var lat = params.latitude;
var from = this.getCoordinateSystem();
var map = layer.getDojoMap();
var p = map.transformXY(lon, lat, from);
var a = this._getLocalXY(p);
var width = this._getWidgetWidth();
var height = this._getWidgetHeight();
var x = a[0] - width / 2;
var y = a[1] - height / 2;
var dom = widget.domNode;
var pa = layer.olLayer.div;
if(dom.parentNode != pa){
if(dom.parentNode){
dom.parentNode.removeChild(dom);
}
pa.appendChild(dom);
}
this._updateWidgetPosition({
x: x,
y: y,
width: width,
height: height
});
},
_updateWidgetPosition: function(box){
// summary:
// Places the widget with the computed x and y values
// tags:
// private
// var box = this._params;
var w = this._widget;
var dom = w.domNode;
style.set(dom, {
position: "absolute",
left: box.x + "px",
top: box.y + "px",
width: box.width + "px",
height: box.height + "px"
});
if(w.srcNodeRef){
style.set(w.srcNodeRef, {
position: "absolute",
left: box.x + "px",
top: box.y + "px",
width: box.width + "px",
height: box.height + "px"
});
}
if(lang.isFunction(w.resize)){
w.resize({
w: box.width,
h: box.height
});
}
},
remove: function(){
// summary:
// removes this feature.
// description:
// Remove this feature by disconnecting the widget from the dom.
var w = this._getWidget();
if(!w){
return;
}
var dom = w.domNode;
if(dom.parentNode){
dom.parentNode.removeChild(dom);
}
}
});
});
},
'dojox/gfx/svg':function(){
define(["dojo/_base/lang", "dojo/_base/sniff", "dojo/_base/window", "dojo/dom", "dojo/_base/declare", "dojo/_base/array",
"dojo/dom-geometry", "dojo/dom-attr", "dojo/_base/Color", "./_base", "./shape", "./path"],
function(lang, has, win, dom, declare, arr, domGeom, domAttr, Color, g, gs, pathLib){
var svg = g.svg = {
// summary:
// This the graphics rendering bridge for browsers compliant with W3C SVG1.0.
// This is the preferred renderer to use for interactive and accessible graphics.
};
svg.useSvgWeb = (typeof window.svgweb != "undefined");
// Need to detect iOS in order to workaround bug when
// touching nodes with text
var uagent = navigator.userAgent,
safMobile = has("ios"),
android = has("android"),
textRenderingFix = has("chrome") || (android && android>=4) ? "auto" : "optimizeLegibility";// #16099, #16461
function _createElementNS(ns, nodeType){
// summary:
// Internal helper to deal with creating elements that
// are namespaced. Mainly to get SVG markup output
// working on IE.
if(win.doc.createElementNS){
return win.doc.createElementNS(ns,nodeType);
}else{
return win.doc.createElement(nodeType);
}
}
function _setAttributeNS(node, ns, attr, value){
if(node.setAttributeNS){
return node.setAttributeNS(ns, attr, value);
}else{
return node.setAttribute(attr, value);
}
}
function _createTextNode(text){
if(svg.useSvgWeb){
return win.doc.createTextNode(text, true);
}else{
return win.doc.createTextNode(text);
}
}
function _createFragment(){
if(svg.useSvgWeb){
return win.doc.createDocumentFragment(true);
}else{
return win.doc.createDocumentFragment();
}
}
svg.xmlns = {
xlink: "http://www.w3.org/1999/xlink",
svg: "http://www.w3.org/2000/svg"
};
svg.getRef = function(name){
// summary:
// looks up a node by its external name
// name: String
// an SVG external reference
// returns:
// returns a DOM Node specified by the name argument or null
if(!name || name == "none") return null;
if(name.match(/^url\(#.+\)$/)){
return dom.byId(name.slice(5, -1)); // Node
}
// alternative representation of a reference
if(name.match(/^#dojoUnique\d+$/)){
// we assume here that a reference was generated by dojox/gfx
return dom.byId(name.slice(1)); // Node
}
return null; // Node
};
svg.dasharray = {
solid: "none",
shortdash: [4, 1],
shortdot: [1, 1],
shortdashdot: [4, 1, 1, 1],
shortdashdotdot: [4, 1, 1, 1, 1, 1],
dot: [1, 3],
dash: [4, 3],
longdash: [8, 3],
dashdot: [4, 3, 1, 3],
longdashdot: [8, 3, 1, 3],
longdashdotdot: [8, 3, 1, 3, 1, 3]
};
var clipCount = 0;
svg.Shape = declare("dojox.gfx.svg.Shape", gs.Shape, {
// summary:
// SVG-specific implementation of dojox/gfx/shape.Shape methods
destroy: function(){
if(this.fillStyle && "type" in this.fillStyle){
var fill = this.rawNode.getAttribute("fill"),
ref = svg.getRef(fill);
if(ref){
ref.parentNode.removeChild(ref);
}
}
if(this.clip){
var clipPathProp = this.rawNode.getAttribute("clip-path");
if(clipPathProp){
var clipNode = dom.byId(clipPathProp.match(/gfx_clip[\d]+/)[0]);
if(clipNode){ clipNode.parentNode.removeChild(clipNode); }
}
}
gs.Shape.prototype.destroy.apply(this, arguments);
},
setFill: function(fill){
// summary:
// sets a fill object (SVG)
// fill: Object
// a fill object
// (see dojox/gfx.defaultLinearGradient,
// dojox/gfx.defaultRadialGradient,
// dojox/gfx.defaultPattern,
// or dojo/_base/Color)
if(!fill){
// don't fill
this.fillStyle = null;
this.rawNode.setAttribute("fill", "none");
this.rawNode.setAttribute("fill-opacity", 0);
return this;
}
var f;
// FIXME: slightly magical. We're using the outer scope's "f", but setting it later
var setter = function(x){
// we assume that we're executing in the scope of the node to mutate
this.setAttribute(x, f[x].toFixed(8));
};
if(typeof(fill) == "object" && "type" in fill){
// gradient
switch(fill.type){
case "linear":
f = g.makeParameters(g.defaultLinearGradient, fill);
var gradient = this._setFillObject(f, "linearGradient");
arr.forEach(["x1", "y1", "x2", "y2"], setter, gradient);
break;
case "radial":
f = g.makeParameters(g.defaultRadialGradient, fill);
var grad = this._setFillObject(f, "radialGradient");
arr.forEach(["cx", "cy", "r"], setter, grad);
break;
case "pattern":
f = g.makeParameters(g.defaultPattern, fill);
var pattern = this._setFillObject(f, "pattern");
arr.forEach(["x", "y", "width", "height"], setter, pattern);
break;
}
this.fillStyle = f;
return this;
}
// color object
f = g.normalizeColor(fill);
this.fillStyle = f;
this.rawNode.setAttribute("fill", f.toCss());
this.rawNode.setAttribute("fill-opacity", f.a);
this.rawNode.setAttribute("fill-rule", "evenodd");
return this; // self
},
setStroke: function(stroke){
// summary:
// sets a stroke object (SVG)
// stroke: Object
// a stroke object (see dojox/gfx.defaultStroke)
var rn = this.rawNode;
if(!stroke){
// don't stroke
this.strokeStyle = null;
rn.setAttribute("stroke", "none");
rn.setAttribute("stroke-opacity", 0);
return this;
}
// normalize the stroke
if(typeof stroke == "string" || lang.isArray(stroke) || stroke instanceof Color){
stroke = { color: stroke };
}
var s = this.strokeStyle = g.makeParameters(g.defaultStroke, stroke);
s.color = g.normalizeColor(s.color);
// generate attributes
if(s){
var w = s.width < 0 ? 0 : s.width;
rn.setAttribute("stroke", s.color.toCss());
rn.setAttribute("stroke-opacity", s.color.a);
rn.setAttribute("stroke-width", w);
rn.setAttribute("stroke-linecap", s.cap);
if(typeof s.join == "number"){
rn.setAttribute("stroke-linejoin", "miter");
rn.setAttribute("stroke-miterlimit", s.join);
}else{
rn.setAttribute("stroke-linejoin", s.join);
}
var da = s.style.toLowerCase();
if(da in svg.dasharray){
da = svg.dasharray[da];
}
if(da instanceof Array){
da = lang._toArray(da);
var i;
for(i = 0; i < da.length; ++i){
da[i] *= w;
}
if(s.cap != "butt"){
for(i = 0; i < da.length; i += 2){
da[i] -= w;
if(da[i] < 1){ da[i] = 1; }
}
for(i = 1; i < da.length; i += 2){
da[i] += w;
}
}
da = da.join(",");
}
rn.setAttribute("stroke-dasharray", da);
rn.setAttribute("dojoGfxStrokeStyle", s.style);
}
return this; // self
},
_getParentSurface: function(){
var surface = this.parent;
for(; surface && !(surface instanceof g.Surface); surface = surface.parent);
return surface;
},
_setFillObject: function(f, nodeType){
var svgns = svg.xmlns.svg;
this.fillStyle = f;
var surface = this._getParentSurface(),
defs = surface.defNode,
fill = this.rawNode.getAttribute("fill"),
ref = svg.getRef(fill);
if(ref){
fill = ref;
if(fill.tagName.toLowerCase() != nodeType.toLowerCase()){
var id = fill.id;
fill.parentNode.removeChild(fill);
fill = _createElementNS(svgns, nodeType);
fill.setAttribute("id", id);
defs.appendChild(fill);
}else{
while(fill.childNodes.length){
fill.removeChild(fill.lastChild);
}
}
}else{
fill = _createElementNS(svgns, nodeType);
fill.setAttribute("id", g._base._getUniqueId());
defs.appendChild(fill);
}
if(nodeType == "pattern"){
fill.setAttribute("patternUnits", "userSpaceOnUse");
var img = _createElementNS(svgns, "image");
img.setAttribute("x", 0);
img.setAttribute("y", 0);
img.setAttribute("width", (f.width < 0 ? 0 : f.width).toFixed(8));
img.setAttribute("height", (f.height < 0 ? 0 : f.height).toFixed(8));
_setAttributeNS(img, svg.xmlns.xlink, "xlink:href", f.src);
fill.appendChild(img);
}else{
fill.setAttribute("gradientUnits", "userSpaceOnUse");
for(var i = 0; i < f.colors.length; ++i){
var c = f.colors[i], t = _createElementNS(svgns, "stop"),
cc = c.color = g.normalizeColor(c.color);
t.setAttribute("offset", c.offset.toFixed(8));
t.setAttribute("stop-color", cc.toCss());
t.setAttribute("stop-opacity", cc.a);
fill.appendChild(t);
}
}
this.rawNode.setAttribute("fill", "url(#" + fill.getAttribute("id") +")");
this.rawNode.removeAttribute("fill-opacity");
this.rawNode.setAttribute("fill-rule", "evenodd");
return fill;
},
_applyTransform: function() {
var matrix = this.matrix;
if(matrix){
var tm = this.matrix;
this.rawNode.setAttribute("transform", "matrix(" +
tm.xx.toFixed(8) + "," + tm.yx.toFixed(8) + "," +
tm.xy.toFixed(8) + "," + tm.yy.toFixed(8) + "," +
tm.dx.toFixed(8) + "," + tm.dy.toFixed(8) + ")");
}else{
this.rawNode.removeAttribute("transform");
}
return this;
},
setRawNode: function(rawNode){
// summary:
// assigns and clears the underlying node that will represent this
// shape. Once set, transforms, gradients, etc, can be applied.
// (no fill & stroke by default)
var r = this.rawNode = rawNode;
if(this.shape.type!="image"){
r.setAttribute("fill", "none");
}
r.setAttribute("fill-opacity", 0);
r.setAttribute("stroke", "none");
r.setAttribute("stroke-opacity", 0);
r.setAttribute("stroke-width", 1);
r.setAttribute("stroke-linecap", "butt");
r.setAttribute("stroke-linejoin", "miter");
r.setAttribute("stroke-miterlimit", 4);
// Bind GFX object with SVG node for ease of retrieval - that is to
// save code/performance to keep this association elsewhere
r.__gfxObject__ = this;
},
setShape: function(newShape){
// summary:
// sets a shape object (SVG)
// newShape: Object
// a shape object
// (see dojox/gfx.defaultPath,
// dojox/gfx.defaultPolyline,
// dojox/gfx.defaultRect,
// dojox/gfx.defaultEllipse,
// dojox/gfx.defaultCircle,
// dojox/gfx.defaultLine,
// or dojox/gfx.defaultImage)
this.shape = g.makeParameters(this.shape, newShape);
for(var i in this.shape){
if(i != "type"){
var v = this.shape[i];
if(i === "width" || i === "height"){
v = v < 0 ? 0 : v;
}
this.rawNode.setAttribute(i, v);
}
}
this.bbox = null;
return this; // self
},
// move family
_moveToFront: function(){
// summary:
// moves a shape to front of its parent's list of shapes (SVG)
this.rawNode.parentNode.appendChild(this.rawNode);
return this; // self
},
_moveToBack: function(){
// summary:
// moves a shape to back of its parent's list of shapes (SVG)
this.rawNode.parentNode.insertBefore(this.rawNode, this.rawNode.parentNode.firstChild);
return this; // self
},
setClip: function(clip){
// summary:
// sets the clipping area of this shape.
// description:
// This method overrides the dojox/gfx/shape.Shape.setClip() method.
// clip: Object
// an object that defines the clipping geometry, or null to remove clip.
this.inherited(arguments);
var clipType = clip ? "width" in clip ? "rect" :
"cx" in clip ? "ellipse" :
"points" in clip ? "polyline" : "d" in clip ? "path" : null : null;
if(clip && !clipType){
return this;
}
if(clipType === "polyline"){
clip = lang.clone(clip);
clip.points = clip.points.join(",");
}
var clipNode, clipShape,
clipPathProp = domAttr.get(this.rawNode, "clip-path");
if(clipPathProp){
clipNode = dom.byId(clipPathProp.match(/gfx_clip[\d]+/)[0]);
if(clipNode){ // may be null if not in the DOM anymore
clipNode.removeChild(clipNode.childNodes[0]);
}
}
if(clip){
if(clipNode){
clipShape = _createElementNS(svg.xmlns.svg, clipType);
clipNode.appendChild(clipShape);
}else{
var idIndex = ++clipCount;
var clipId = "gfx_clip" + idIndex;
var clipUrl = "url(#" + clipId + ")";
this.rawNode.setAttribute("clip-path", clipUrl);
clipNode = _createElementNS(svg.xmlns.svg, "clipPath");
clipShape = _createElementNS(svg.xmlns.svg, clipType);
clipNode.appendChild(clipShape);
this.rawNode.parentNode.insertBefore(clipNode, this.rawNode);
domAttr.set(clipNode, "id", clipId);
}
domAttr.set(clipShape, clip);
}else{
//remove clip-path
this.rawNode.removeAttribute("clip-path");
if(clipNode){
clipNode.parentNode.removeChild(clipNode);
}
}
return this;
},
_removeClipNode: function(){
var clipNode, clipPathProp = domAttr.get(this.rawNode, "clip-path");
if(clipPathProp){
clipNode = dom.byId(clipPathProp.match(/gfx_clip[\d]+/)[0]);
if(clipNode){
clipNode.parentNode.removeChild(clipNode);
}
}
return clipNode;
}
});
svg.Group = declare("dojox.gfx.svg.Group", svg.Shape, {
// summary:
// a group shape (SVG), which can be used
// to logically group shapes (e.g, to propagate matricies)
constructor: function(){
gs.Container._init.call(this);
},
setRawNode: function(rawNode){
// summary:
// sets a raw SVG node to be used by this shape
// rawNode: Node
// an SVG node
this.rawNode = rawNode;
// Bind GFX object with SVG node for ease of retrieval - that is to
// save code/performance to keep this association elsewhere
this.rawNode.__gfxObject__ = this;
},
destroy: function(){
// summary:
// Releases all internal resources owned by this shape. Once this method has been called,
// the instance is considered disposed and should not be used anymore.
this.clear(true);
// avoid this.inherited
svg.Shape.prototype.destroy.apply(this, arguments);
}
});
svg.Group.nodeType = "g";
svg.Rect = declare("dojox.gfx.svg.Rect", [svg.Shape, gs.Rect], {
// summary:
// a rectangle shape (SVG)
setShape: function(newShape){
// summary:
// sets a rectangle shape object (SVG)
// newShape: Object
// a rectangle shape object
this.shape = g.makeParameters(this.shape, newShape);
this.bbox = null;
for(var i in this.shape){
if(i != "type" && i != "r"){
var v = this.shape[i];
if(i === "width" || i === "height"){
v = v < 0 ? 0 : v;
}
this.rawNode.setAttribute(i, v);
}
}
if(this.shape.r != null){
this.rawNode.setAttribute("ry", this.shape.r);
this.rawNode.setAttribute("rx", this.shape.r);
}
return this; // self
}
});
svg.Rect.nodeType = "rect";
svg.Ellipse = declare("dojox.gfx.svg.Ellipse", [svg.Shape, gs.Ellipse], {});
svg.Ellipse.nodeType = "ellipse";
svg.Circle = declare("dojox.gfx.svg.Circle", [svg.Shape, gs.Circle], {});
svg.Circle.nodeType = "circle";
svg.Line = declare("dojox.gfx.svg.Line", [svg.Shape, gs.Line], {});
svg.Line.nodeType = "line";
svg.Polyline = declare("dojox.gfx.svg.Polyline", [svg.Shape, gs.Polyline], {
// summary:
// a polyline/polygon shape (SVG)
setShape: function(points, closed){
// summary:
// sets a polyline/polygon shape object (SVG)
// points: Object|Array
// a polyline/polygon shape object, or an array of points
if(points && points instanceof Array){
this.shape = g.makeParameters(this.shape, { points: points });
if(closed && this.shape.points.length){
this.shape.points.push(this.shape.points[0]);
}
}else{
this.shape = g.makeParameters(this.shape, points);
}
this.bbox = null;
this._normalizePoints();
var attr = [], p = this.shape.points;
for(var i = 0; i < p.length; ++i){
attr.push(p[i].x.toFixed(8), p[i].y.toFixed(8));
}
this.rawNode.setAttribute("points", attr.join(" "));
return this; // self
}
});
svg.Polyline.nodeType = "polyline";
svg.Image = declare("dojox.gfx.svg.Image", [svg.Shape, gs.Image], {
// summary:
// an image (SVG)
setShape: function(newShape){
// summary:
// sets an image shape object (SVG)
// newShape: Object
// an image shape object
this.shape = g.makeParameters(this.shape, newShape);
this.bbox = null;
var rawNode = this.rawNode;
for(var i in this.shape){
if(i != "type" && i != "src"){
var v = this.shape[i];
if(i === "width" || i === "height"){
v = v < 0 ? 0 : v;
}
rawNode.setAttribute(i, v);
}
}
rawNode.setAttribute("preserveAspectRatio", "none");
_setAttributeNS(rawNode, svg.xmlns.xlink, "xlink:href", this.shape.src);
// Bind GFX object with SVG node for ease of retrieval - that is to
// save code/performance to keep this association elsewhere
rawNode.__gfxObject__ = this;
return this; // self
}
});
svg.Image.nodeType = "image";
svg.Text = declare("dojox.gfx.svg.Text", [svg.Shape, gs.Text], {
// summary:
// an anchored text (SVG)
setShape: function(newShape){
// summary:
// sets a text shape object (SVG)
// newShape: Object
// a text shape object
this.shape = g.makeParameters(this.shape, newShape);
this.bbox = null;
var r = this.rawNode, s = this.shape;
r.setAttribute("x", s.x);
r.setAttribute("y", s.y);
r.setAttribute("text-anchor", s.align);
r.setAttribute("text-decoration", s.decoration);
r.setAttribute("rotate", s.rotated ? 90 : 0);
r.setAttribute("kerning", s.kerning ? "auto" : 0);
r.setAttribute("text-rendering", textRenderingFix);
// update the text content
if(r.firstChild){
r.firstChild.nodeValue = s.text;
}else{
r.appendChild(_createTextNode(s.text));
}
return this; // self
},
getTextWidth: function(){
// summary:
// get the text width in pixels
var rawNode = this.rawNode,
oldParent = rawNode.parentNode,
_measurementNode = rawNode.cloneNode(true);
_measurementNode.style.visibility = "hidden";
// solution to the "orphan issue" in FF
var _width = 0, _text = _measurementNode.firstChild.nodeValue;
oldParent.appendChild(_measurementNode);
// solution to the "orphan issue" in Opera
// (nodeValue == "" hangs firefox)
if(_text!=""){
while(!_width){
//Yang: work around svgweb bug 417 -- http://code.google.com/p/svgweb/issues/detail?id=417
if (_measurementNode.getBBox)
_width = parseInt(_measurementNode.getBBox().width);
else
_width = 68;
}
}
oldParent.removeChild(_measurementNode);
return _width;
},
getBoundingBox: function(){
var s = this.getShape(), bbox = null;
if(s.text){
// try/catch the FF native getBBox error.
try {
bbox = this.rawNode.getBBox();
} catch (e) {
// under FF when the node is orphan (all other browsers return a 0ed bbox.
bbox = {x:0, y:0, width:0, height:0};
}
}
return bbox;
}
});
svg.Text.nodeType = "text";
svg.Path = declare("dojox.gfx.svg.Path", [svg.Shape, pathLib.Path], {
// summary:
// a path shape (SVG)
_updateWithSegment: function(segment){
// summary:
// updates the bounding box of path with new segment
// segment: Object
// a segment
this.inherited(arguments);
if(typeof(this.shape.path) == "string"){
this.rawNode.setAttribute("d", this.shape.path);
}
},
setShape: function(newShape){
// summary:
// forms a path using a shape (SVG)
// newShape: Object
// an SVG path string or a path object (see dojox/gfx.defaultPath)
this.inherited(arguments);
if(this.shape.path){
this.rawNode.setAttribute("d", this.shape.path);
}else{
this.rawNode.removeAttribute("d");
}
return this; // self
}
});
svg.Path.nodeType = "path";
svg.TextPath = declare("dojox.gfx.svg.TextPath", [svg.Shape, pathLib.TextPath], {
// summary:
// a textpath shape (SVG)
_updateWithSegment: function(segment){
// summary:
// updates the bounding box of path with new segment
// segment: Object
// a segment
this.inherited(arguments);
this._setTextPath();
},
setShape: function(newShape){
// summary:
// forms a path using a shape (SVG)
// newShape: Object
// an SVG path string or a path object (see dojox/gfx.defaultPath)
this.inherited(arguments);
this._setTextPath();
return this; // self
},
_setTextPath: function(){
if(typeof this.shape.path != "string"){ return; }
var r = this.rawNode;
if(!r.firstChild){
var tp = _createElementNS(svg.xmlns.svg, "textPath"),
tx = _createTextNode("");
tp.appendChild(tx);
r.appendChild(tp);
}
var ref = r.firstChild.getAttributeNS(svg.xmlns.xlink, "href"),
path = ref && svg.getRef(ref);
if(!path){
var surface = this._getParentSurface();
if(surface){
var defs = surface.defNode;
path = _createElementNS(svg.xmlns.svg, "path");
var id = g._base._getUniqueId();
path.setAttribute("id", id);
defs.appendChild(path);
_setAttributeNS(r.firstChild, svg.xmlns.xlink, "xlink:href", "#" + id);
}
}
if(path){
path.setAttribute("d", this.shape.path);
}
},
_setText: function(){
var r = this.rawNode;
if(!r.firstChild){
var tp = _createElementNS(svg.xmlns.svg, "textPath"),
tx = _createTextNode("");
tp.appendChild(tx);
r.appendChild(tp);
}
r = r.firstChild;
var t = this.text;
r.setAttribute("alignment-baseline", "middle");
switch(t.align){
case "middle":
r.setAttribute("text-anchor", "middle");
r.setAttribute("startOffset", "50%");
break;
case "end":
r.setAttribute("text-anchor", "end");
r.setAttribute("startOffset", "100%");
break;
default:
r.setAttribute("text-anchor", "start");
r.setAttribute("startOffset", "0%");
break;
}
//r.parentNode.setAttribute("alignment-baseline", "central");
//r.setAttribute("dominant-baseline", "central");
r.setAttribute("baseline-shift", "0.5ex");
r.setAttribute("text-decoration", t.decoration);
r.setAttribute("rotate", t.rotated ? 90 : 0);
r.setAttribute("kerning", t.kerning ? "auto" : 0);
r.firstChild.data = t.text;
}
});
svg.TextPath.nodeType = "text";
// Fix for setDimension bug:
// http://bugs.dojotoolkit.org/ticket/16100
// (https://code.google.com/p/chromium/issues/detail?id=162628)
var hasSvgSetAttributeBug = (function(){ var matches = /WebKit\/(\d*)/.exec(uagent); return matches ? matches[1] : 0})() > 534;
svg.Surface = declare("dojox.gfx.svg.Surface", gs.Surface, {
// summary:
// a surface object to be used for drawings (SVG)
constructor: function(){
gs.Container._init.call(this);
},
destroy: function(){
// no need to call svg.Container.clear to remove the children raw
// nodes since the surface raw node will be removed. So, only dispose at gfx level
gs.Container.clear.call(this, true);
this.defNode = null; // release the external reference
this.inherited(arguments);
},
setDimensions: function(width, height){
// summary:
// sets the width and height of the rawNode
// width: String
// width of surface, e.g., "100px"
// height: String
// height of surface, e.g., "100px"
if(!this.rawNode){ return this; }
var w = width < 0 ? 0 : width,
h = height < 0 ? 0 : height;
this.rawNode.setAttribute("width", w);
this.rawNode.setAttribute("height", h);
if(hasSvgSetAttributeBug){
this.rawNode.style.width = w;
this.rawNode.style.height = h;
}
return this; // self
},
getDimensions: function(){
// summary:
// returns an object with properties "width" and "height"
var t = this.rawNode ? {
width: g.normalizedLength(this.rawNode.getAttribute("width")),
height: g.normalizedLength(this.rawNode.getAttribute("height"))} : null;
return t; // Object
}
});
svg.createSurface = function(parentNode, width, height){
// summary:
// creates a surface (SVG)
// parentNode: Node
// a parent node
// width: String|Number
// width of surface, e.g., "100px" or 100
// height: String|Number
// height of surface, e.g., "100px" or 100
// returns: dojox/gfx/shape.Surface
// newly created surface
var s = new svg.Surface();
s.rawNode = _createElementNS(svg.xmlns.svg, "svg");
s.rawNode.setAttribute("overflow", "hidden");
if(width){
s.rawNode.setAttribute("width", width < 0 ? 0 : width);
}
if(height){
s.rawNode.setAttribute("height", height < 0 ? 0 : height);
}
var defNode = _createElementNS(svg.xmlns.svg, "defs");
s.rawNode.appendChild(defNode);
s.defNode = defNode;
s._parent = dom.byId(parentNode);
s._parent.appendChild(s.rawNode);
g._base._fixMsTouchAction(s);
return s; // dojox/gfx.Surface
};
// Extenders
var Font = {
_setFont: function(){
// summary:
// sets a font object (SVG)
var f = this.fontStyle;
// next line doesn't work in Firefox 2 or Opera 9
//this.rawNode.setAttribute("font", dojox.gfx.makeFontString(this.fontStyle));
this.rawNode.setAttribute("font-style", f.style);
this.rawNode.setAttribute("font-variant", f.variant);
this.rawNode.setAttribute("font-weight", f.weight);
this.rawNode.setAttribute("font-size", f.size);
this.rawNode.setAttribute("font-family", f.family);
}
};
var C = gs.Container;
var Container = svg.Container = {
openBatch: function() {
// summary:
// starts a new batch, subsequent new child shapes will be held in
// the batch instead of appending to the container directly
if(!this._batch){
this.fragment = _createFragment();
}
++this._batch;
return this;
},
closeBatch: function() {
// summary:
// submits the current batch, append all pending child shapes to DOM
this._batch = this._batch > 0 ? --this._batch : 0;
if (this.fragment && !this._batch) {
this.rawNode.appendChild(this.fragment);
delete this.fragment;
}
return this;
},
add: function(shape){
// summary:
// adds a shape to a group/surface
// shape: dojox/gfx/shape.Shape
// an VML shape object
if(this != shape.getParent()){
if (this.fragment) {
this.fragment.appendChild(shape.rawNode);
} else {
this.rawNode.appendChild(shape.rawNode);
}
C.add.apply(this, arguments);
// update clipnode with new parent
shape.setClip(shape.clip);
}
return this; // self
},
remove: function(shape, silently){
// summary:
// remove a shape from a group/surface
// shape: dojox/gfx/shape.Shape
// an VML shape object
// silently: Boolean?
// if true, regenerate a picture
if(this == shape.getParent()){
if(this.rawNode == shape.rawNode.parentNode){
this.rawNode.removeChild(shape.rawNode);
}
if(this.fragment && this.fragment == shape.rawNode.parentNode){
this.fragment.removeChild(shape.rawNode);
}
// remove clip node from parent
shape._removeClipNode();
C.remove.apply(this, arguments);
}
return this; // self
},
clear: function(){
// summary:
// removes all shapes from a group/surface
var r = this.rawNode;
while(r.lastChild){
r.removeChild(r.lastChild);
}
var defNode = this.defNode;
if(defNode){
while(defNode.lastChild){
defNode.removeChild(defNode.lastChild);
}
r.appendChild(defNode);
}
return C.clear.apply(this, arguments);
},
getBoundingBox: C.getBoundingBox,
_moveChildToFront: C._moveChildToFront,
_moveChildToBack: C._moveChildToBack
};
var Creator = svg.Creator = {
// summary:
// SVG shape creators
createObject: function(shapeType, rawShape){
// summary:
// creates an instance of the passed shapeType class
// shapeType: Function
// a class constructor to create an instance of
// rawShape: Object
// properties to be passed in to the classes "setShape" method
if(!this.rawNode){ return null; }
var shape = new shapeType(),
node = _createElementNS(svg.xmlns.svg, shapeType.nodeType);
shape.setRawNode(node);
shape.setShape(rawShape);
// rawNode.appendChild() will be done inside this.add(shape) below
this.add(shape);
return shape; // dojox/gfx/shape.Shape
}
};
lang.extend(svg.Text, Font);
lang.extend(svg.TextPath, Font);
lang.extend(svg.Group, Container);
lang.extend(svg.Group, gs.Creator);
lang.extend(svg.Group, Creator);
lang.extend(svg.Surface, Container);
lang.extend(svg.Surface, gs.Creator);
lang.extend(svg.Surface, Creator);
// Mouse/Touch event
svg.fixTarget = function(event, gfxElement) {
// summary:
// Adds the gfxElement to event.gfxTarget if none exists. This new
// property will carry the GFX element associated with this event.
// event: Object
// The current input event (MouseEvent or TouchEvent)
// gfxElement: Object
// The GFX target element
if (!event.gfxTarget) {
if (safMobile && event.target.wholeText) {
// Workaround iOS bug when touching text nodes
event.gfxTarget = event.target.parentElement.__gfxObject__;
} else {
event.gfxTarget = event.target.__gfxObject__;
}
}
return true;
};
// some specific override for svgweb + flash
if(svg.useSvgWeb){
// override createSurface()
svg.createSurface = function(parentNode, width, height){
var s = new svg.Surface();
width = width < 0 ? 0 : width;
height = height < 0 ? 0 : height;
// ensure width / height
if(!width || !height){
var pos = domGeom.position(parentNode);
width = width || pos.w;
height = height || pos.h;
}
// ensure id
parentNode = dom.byId(parentNode);
var id = parentNode.id ? parentNode.id+'_svgweb' : g._base._getUniqueId();
// create dynamic svg root
var mockSvg = _createElementNS(svg.xmlns.svg, 'svg');
mockSvg.id = id;
mockSvg.setAttribute('width', width);
mockSvg.setAttribute('height', height);
svgweb.appendChild(mockSvg, parentNode);
// notice: any call to the raw node before flash init will fail.
mockSvg.addEventListener('SVGLoad', function(){
// become loaded
s.rawNode = this;
s.isLoaded = true;
// init defs
var defNode = _createElementNS(svg.xmlns.svg, "defs");
s.rawNode.appendChild(defNode);
s.defNode = defNode;
// notify application
if (s.onLoad)
s.onLoad(s);
}, false);
// flash not loaded yet
s.isLoaded = false;
return s;
};
// override Surface.destroy()
svg.Surface.extend({
destroy: function(){
var mockSvg = this.rawNode;
svgweb.removeChild(mockSvg, mockSvg.parentNode);
}
});
// override connect() & disconnect() for Shape & Surface event processing
var _eventsProcessing = {
connect: function(name, object, method){
// connect events using the mock addEventListener() provided by svgweb
if (name.substring(0, 2)==='on') { name = name.substring(2); }
if (arguments.length == 2) {
method = object;
} else {
method = lang.hitch(object, method);
}
this.getEventSource().addEventListener(name, method, false);
return [this, name, method];
},
disconnect: function(token){
// disconnect events using the mock removeEventListener() provided by svgweb
this.getEventSource().removeEventListener(token[1], token[2], false);
delete token[0];
}
};
lang.extend(svg.Shape, _eventsProcessing);
lang.extend(svg.Surface, _eventsProcessing);
}
return svg;
});
},
'dojox/gfx/path':function(){
define(["./_base", "dojo/_base/lang","dojo/_base/declare", "./matrix", "./shape"],
function(g, lang, declare, matrix, shapeLib){
// module:
// dojox/gfx/path
var Path = declare("dojox.gfx.path.Path", shapeLib.Shape, {
// summary:
// a generalized path shape
constructor: function(rawNode){
// summary:
// a path constructor
// rawNode: Node
// a DOM node to be used by this path object
this.shape = lang.clone(g.defaultPath);
this.segments = [];
this.tbbox = null;
this.absolute = true;
this.last = {};
this.rawNode = rawNode;
this.segmented = false;
},
// mode manipulations
setAbsoluteMode: function(mode){
// summary:
// sets an absolute or relative mode for path points
// mode: Boolean
// true/false or "absolute"/"relative" to specify the mode
this._confirmSegmented();
this.absolute = typeof mode == "string" ? (mode == "absolute") : mode;
return this; // self
},
getAbsoluteMode: function(){
// summary:
// returns a current value of the absolute mode
this._confirmSegmented();
return this.absolute; // Boolean
},
getBoundingBox: function(){
// summary:
// returns the bounding box {x, y, width, height} or null
this._confirmSegmented();
return (this.bbox && ("l" in this.bbox)) ? {x: this.bbox.l, y: this.bbox.t, width: this.bbox.r - this.bbox.l, height: this.bbox.b - this.bbox.t} : null; // dojox/gfx.Rectangle
},
_getRealBBox: function(){
// summary:
// returns an array of four points or null
// four points represent four corners of the untransformed bounding box
this._confirmSegmented();
if(this.tbbox){
return this.tbbox; // Array
}
var bbox = this.bbox, matrix = this._getRealMatrix();
this.bbox = null;
for(var i = 0, len = this.segments.length; i < len; ++i){
this._updateWithSegment(this.segments[i], matrix);
}
var t = this.bbox;
this.bbox = bbox;
this.tbbox = t ? [
{x: t.l, y: t.t},
{x: t.r, y: t.t},
{x: t.r, y: t.b},
{x: t.l, y: t.b}
] : null;
return this.tbbox; // Array
},
getLastPosition: function(){
// summary:
// returns the last point in the path, or null
this._confirmSegmented();
return "x" in this.last ? this.last : null; // Object
},
_applyTransform: function(){
this.tbbox = null;
return this.inherited(arguments);
},
// segment interpretation
_updateBBox: function(x, y, m){
// summary:
// updates the bounding box of path with new point
// x: Number
// an x coordinate
// y: Number
// a y coordinate
if(m){
var t = matrix.multiplyPoint(m, x, y);
x = t.x;
y = t.y;
}
// we use {l, b, r, t} representation of a bbox
if(this.bbox && ("l" in this.bbox)){
if(this.bbox.l > x) this.bbox.l = x;
if(this.bbox.r < x) this.bbox.r = x;
if(this.bbox.t > y) this.bbox.t = y;
if(this.bbox.b < y) this.bbox.b = y;
}else{
this.bbox = {l: x, b: y, r: x, t: y};
}
},
_updateWithSegment: function(segment, matrix){
// summary:
// updates the bounding box of path with new segment
// segment: Object
// a segment
var n = segment.args, l = n.length, i;
// update internal variables: bbox, absolute, last
switch(segment.action){
case "M":
case "L":
case "C":
case "S":
case "Q":
case "T":
for(i = 0; i < l; i += 2){
this._updateBBox(n[i], n[i + 1], matrix);
}
this.last.x = n[l - 2];
this.last.y = n[l - 1];
this.absolute = true;
break;
case "H":
for(i = 0; i < l; ++i){
this._updateBBox(n[i], this.last.y, matrix);
}
this.last.x = n[l - 1];
this.absolute = true;
break;
case "V":
for(i = 0; i < l; ++i){
this._updateBBox(this.last.x, n[i], matrix);
}
this.last.y = n[l - 1];
this.absolute = true;
break;
case "m":
var start = 0;
if(!("x" in this.last)){
this._updateBBox(this.last.x = n[0], this.last.y = n[1], matrix);
start = 2;
}
for(i = start; i < l; i += 2){
this._updateBBox(this.last.x += n[i], this.last.y += n[i + 1], matrix);
}
this.absolute = false;
break;
case "l":
case "t":
for(i = 0; i < l; i += 2){
this._updateBBox(this.last.x += n[i], this.last.y += n[i + 1], matrix);
}
this.absolute = false;
break;
case "h":
for(i = 0; i < l; ++i){
this._updateBBox(this.last.x += n[i], this.last.y, matrix);
}
this.absolute = false;
break;
case "v":
for(i = 0; i < l; ++i){
this._updateBBox(this.last.x, this.last.y += n[i], matrix);
}
this.absolute = false;
break;
case "c":
for(i = 0; i < l; i += 6){
this._updateBBox(this.last.x + n[i], this.last.y + n[i + 1], matrix);
this._updateBBox(this.last.x + n[i + 2], this.last.y + n[i + 3], matrix);
this._updateBBox(this.last.x += n[i + 4], this.last.y += n[i + 5], matrix);
}
this.absolute = false;
break;
case "s":
case "q":
for(i = 0; i < l; i += 4){
this._updateBBox(this.last.x + n[i], this.last.y + n[i + 1], matrix);
this._updateBBox(this.last.x += n[i + 2], this.last.y += n[i + 3], matrix);
}
this.absolute = false;
break;
case "A":
for(i = 0; i < l; i += 7){
this._updateBBox(n[i + 5], n[i + 6], matrix);
}
this.last.x = n[l - 2];
this.last.y = n[l - 1];
this.absolute = true;
break;
case "a":
for(i = 0; i < l; i += 7){
this._updateBBox(this.last.x += n[i + 5], this.last.y += n[i + 6], matrix);
}
this.absolute = false;
break;
}
// add an SVG path segment
var path = [segment.action];
for(i = 0; i < l; ++i){
path.push(g.formatNumber(n[i], true));
}
if(typeof this.shape.path == "string"){
this.shape.path += path.join("");
}else{
for(i = 0, l = path.length; i < l; ++i){
this.shape.path.push(path[i]);
}
}
},
// a dictionary, which maps segment type codes to a number of their arguments
_validSegments: {m: 2, l: 2, h: 1, v: 1, c: 6, s: 4, q: 4, t: 2, a: 7, z: 0},
_pushSegment: function(action, args){
// summary:
// adds a segment
// action: String
// valid SVG code for a segment's type
// args: Array
// a list of parameters for this segment
this.tbbox = null;
var group = this._validSegments[action.toLowerCase()], segment;
if(typeof group == "number"){
if(group){
if(args.length >= group){
segment = {action: action, args: args.slice(0, args.length - args.length % group)};
this.segments.push(segment);
this._updateWithSegment(segment);
}
}else{
segment = {action: action, args: []};
this.segments.push(segment);
this._updateWithSegment(segment);
}
}
},
_collectArgs: function(array, args){
// summary:
// converts an array of arguments to plain numeric values
// array: Array
// an output argument (array of numbers)
// args: Array
// an input argument (can be values of Boolean, Number, dojox/gfx.Point, or an embedded array of them)
for(var i = 0; i < args.length; ++i){
var t = args[i];
if(typeof t == "boolean"){
array.push(t ? 1 : 0);
}else if(typeof t == "number"){
array.push(t);
}else if(t instanceof Array){
this._collectArgs(array, t);
}else if("x" in t && "y" in t){
array.push(t.x, t.y);
}
}
},
// segments
moveTo: function(){
// summary:
// forms a move segment
this._confirmSegmented();
var args = [];
this._collectArgs(args, arguments);
this._pushSegment(this.absolute ? "M" : "m", args);
return this; // self
},
lineTo: function(){
// summary:
// forms a line segment
this._confirmSegmented();
var args = [];
this._collectArgs(args, arguments);
this._pushSegment(this.absolute ? "L" : "l", args);
return this; // self
},
hLineTo: function(){
// summary:
// forms a horizontal line segment
this._confirmSegmented();
var args = [];
this._collectArgs(args, arguments);
this._pushSegment(this.absolute ? "H" : "h", args);
return this; // self
},
vLineTo: function(){
// summary:
// forms a vertical line segment
this._confirmSegmented();
var args = [];
this._collectArgs(args, arguments);
this._pushSegment(this.absolute ? "V" : "v", args);
return this; // self
},
curveTo: function(){
// summary:
// forms a curve segment
this._confirmSegmented();
var args = [];
this._collectArgs(args, arguments);
this._pushSegment(this.absolute ? "C" : "c", args);
return this; // self
},
smoothCurveTo: function(){
// summary:
// forms a smooth curve segment
this._confirmSegmented();
var args = [];
this._collectArgs(args, arguments);
this._pushSegment(this.absolute ? "S" : "s", args);
return this; // self
},
qCurveTo: function(){
// summary:
// forms a quadratic curve segment
this._confirmSegmented();
var args = [];
this._collectArgs(args, arguments);
this._pushSegment(this.absolute ? "Q" : "q", args);
return this; // self
},
qSmoothCurveTo: function(){
// summary:
// forms a quadratic smooth curve segment
this._confirmSegmented();
var args = [];
this._collectArgs(args, arguments);
this._pushSegment(this.absolute ? "T" : "t", args);
return this; // self
},
arcTo: function(){
// summary:
// forms an elliptic arc segment
this._confirmSegmented();
var args = [];
this._collectArgs(args, arguments);
this._pushSegment(this.absolute ? "A" : "a", args);
return this; // self
},
closePath: function(){
// summary:
// closes a path
this._confirmSegmented();
this._pushSegment("Z", []);
return this; // self
},
_confirmSegmented: function() {
if (!this.segmented) {
var path = this.shape.path;
// switch to non-updating version of path building
this.shape.path = [];
this._setPath(path);
// switch back to the string path
this.shape.path = this.shape.path.join("");
// become segmented
this.segmented = true;
}
},
// setShape
_setPath: function(path){
// summary:
// forms a path using an SVG path string
// path: String
// an SVG path string
var p = lang.isArray(path) ? path : path.match(g.pathSvgRegExp);
this.segments = [];
this.absolute = true;
this.bbox = {};
this.last = {};
if(!p) return;
// create segments
var action = "", // current action
args = [], // current arguments
l = p.length;
for(var i = 0; i < l; ++i){
var t = p[i], x = parseFloat(t);
if(isNaN(x)){
if(action){
this._pushSegment(action, args);
}
args = [];
action = t;
}else{
args.push(x);
}
}
this._pushSegment(action, args);
},
setShape: function(newShape){
// summary:
// forms a path using a shape
// newShape: Object
// an SVG path string or a path object (see dojox/gfx.defaultPath)
this.inherited(arguments, [typeof newShape == "string" ? {path: newShape} : newShape]);
this.segmented = false;
this.segments = [];
if(!g.lazyPathSegmentation){
this._confirmSegmented();
}
return this; // self
},
// useful constant for descendants
_2PI: Math.PI * 2
});
var TextPath = declare("dojox.gfx.path.TextPath", Path, {
// summary:
// a generalized TextPath shape
constructor: function(rawNode){
// summary:
// a TextPath shape constructor
// rawNode: Node
// a DOM node to be used by this TextPath object
if(!("text" in this)){
this.text = lang.clone(g.defaultTextPath);
}
if(!("fontStyle" in this)){
this.fontStyle = lang.clone(g.defaultFont);
}
},
getText: function(){
// summary:
// returns the current text object or null
return this.text; // Object
},
setText: function(newText){
// summary:
// sets a text to be drawn along the path
this.text = g.makeParameters(this.text,
typeof newText == "string" ? {text: newText} : newText);
this._setText();
return this; // self
},
getFont: function(){
// summary:
// returns the current font object or null
return this.fontStyle; // Object
},
setFont: function(newFont){
// summary:
// sets a font for text
this.fontStyle = typeof newFont == "string" ?
g.splitFontString(newFont) :
g.makeParameters(g.defaultFont, newFont);
this._setFont();
return this; // self
}
});
/*=====
g.Path = Path;
g.TextPath = TextPath;
=====*/
return g.path = {
// summary:
// This module contains the core graphics Path API.
// Path command format follows the W3C SVG 1.0 Path api.
Path: Path,
TextPath: TextPath
};
});
}}});
define("dojo/pmbmaps", [], 1);