Reworked overlay itself and doctest.

This commit is contained in:
Severin Opel 2019-12-12 19:02:58 +01:00
parent 32e913c629
commit 7f2fc93fa3
2 changed files with 427 additions and 202 deletions

View File

@ -17,6 +17,8 @@
<script src="../../../dist/iwmlib.js"></script>
<script src="../../../dist/iwmlib.pixi.js"></script>
<link rel="shortcut icon" type="image/x-icon" href="../../../assets/icons/map.png">
<style>
.inline-showcase {
@ -109,17 +111,22 @@
let exampleOverlayJSON = {
icon: '../../../assets/icons/place.png',
iconColor: '0x000000',
iconColor: "0x35aaea",
iconAnchor: { x: 0.5, y: 1 },
size: 5,
scale: 0.2,
color: '0xFF00FF',
fillAlpha: 0,
disabledColor: 0x000000,
disabledIconColor: 0xCCCCCC,
disabledScale: 0.5,
color: '0x3FA7EE',
items: [
{
name: 'Abidjan',
name: 'Custom Icon',
fontWeight: "bold",
icon: '../../../assets/icons//beenhere.png',
icon: '../../../assets/icons/beenhere.png',
iconColor: 0x00ff00,
iconAlpha: 0.5,
size: 0,
labelVerticalAlignment: "underneath",
label: 'Abidjan',
location: {
@ -127,17 +134,19 @@
y: -4.006472
},
information:
'... der größte städtische Ballungsraum der Elfenbeinküste.'
'Here a custom icon is used. It overrides the icon setting in the global section.'
},
{
name: 'Berlin',
label: "enabled",
disabledLabel: "disabled",
location: {
x: 52.52543,
y: 13.385291
},
information:
'... ist die Bundeshauptstadt der Bundesrepublik Deutschland.'
'... ist die Bundeshauptstadt der Bundesrepublik Deutschland.',
enabled: false
},
{
name: 'Canberra',
@ -157,7 +166,7 @@
y: 18.416962
},
information:
'... ist eine Hafenstadt an der Südwestküste Südafrikas auf einer Halbinsel, die vom beeindruckenden Tafelberg dominiert wird.'
`This item adjusts it's size according to the map.`
},
{
name: 'Moskau',
@ -191,7 +200,8 @@
},
{
name: 'Tokio',
type: "factory",
label: "factory",
location: {
x: 35.696278,
y: 139.731366
@ -221,6 +231,7 @@
function texturesLoaded(textures) {
/** When all textures are loaded .... */
setupMap(textures)
@ -232,6 +243,27 @@
let cleaner = null
const vanishingTime = 1000
// Factories must return a geographics object.
Overlay.createFactory("factory", (item) => {
// This is applied to every item in the overlay that has
// the type factory'
let geographics = new GeoPoint(item.location)
geographics.drawHandler.add((graphics) => {
graphics.beginFill(item.color, item.fillAlpha)
graphics.drawRect(0, 0, 10, 10)
})
let text = new PIXI.Text(item.name, {fontSize: 5})
geographics.graphics.addChild(text)
return geographics
})
/**
*
* The actual PIXI elements are created when the overlay.create() is called.

View File

@ -1,5 +1,5 @@
import { GeoLayer } from './geolayer.js'
import { GeoPoint, GeoMultiShape } from './geographics.js'
import { GeoPoint, GeoMultiShape, GeoGraphics } from './geographics.js'
import GeoJson from './geojson.js'
import Popup from '../popup.js'
@ -11,46 +11,83 @@ import Popup from '../popup.js'
*
* It's highly configurable and adaptable to a variety of scenarios.
*
*/
export default class Overlay {
/**
*Creates an instance of Overlay.
* @param {*} [{
* name = "unnamed", {string}
* connector = false,
* connectorType = "line",
* location = null,
* label = false,
* labelType = null,
* labelLocation = null,
* labelAlignment = "center",
* labelVerticalAlign = "underneath",
* labelTarget = null,
* shape = "geometry", {string} - Defines the shape to be used: geometry, circle, rectangle
* geometry = null,
* geometryType = "point",
* geometryFallback = "circle",
* informationPopup = "infocard",
* @export
* @class Overlay
*
* }={}]
* @memberof Overlay
*
* @param {object} options
* @param {object} options.name Name of the item.
* @param {object} options.borderColor
* @param {object} options.borderThickness
* @param {object} options.enabled Determines if enabled, disabled when false.
* @param {object} options.labelScale
* @param {object} options.location
* @param {object} options.label
* @param {object} options.labelType
* @param {object} options.labelLocation
* @param {object} options.labelAlignment
* @param {object} options.labelVerticalAlignment
* @param {object} options.labelSpacing
* @param {object} options.labelTarget
* @param {object} options.geometry
* @param {object} options.information
* @param {object} options.informationPath
* @param {object} options.informationType
* @param {object} options.icon
* @param {object} options.iconAlpha
* @param {object} options.iconAnchor
* @param {object} options.iconColor
* @param {object} options.iconScale
* @param {object} options.iconOffset
* @param {object} options.items
* @param {object} options.color Color of te point.
* @param {object} options.fillAlpha FillAlpha of the point.
* @param {object} options.size Size of the point.
* @param {object} options.scale Determines the scale of the graphics.
* @param {object} options.rescale Rescales the graphics relative to the map, that they keep their original scale. Only works for the entire overlay atm. Therefore must be set in the global param eters and not inside the children.
* @param {object} options.popoverOffset
* @param {object} options.zoomVisibility
* @param {object} options.labelMultiLineAlign
* @param {object} options.labelBreakWords
* @param {object} options.labelDropShadow
* @param {object} options.labelDropShadowAlpha
* @param {object} options.labelDropShadowAngle
* @param {object} options.labelDropShadowBlur
* @param {object} options.labelDropShadowColor
* @param {object} options.labelDropShadowDistance
* @param {object} options.fontColor
* @param {object} options.fontFamily
* @param {object} options.fontSize
* @param {object} options.fontStyle
* @param {object} options.fontWeight
* @param {object} options.labelStroke
* @param {object} options.labelStrokeThickness
* @param {object} options.wordWrap
* @param {object} options.wordWrapWidth
* @param {object} options.labelFill
* @param {object} options.labelFillGradientType
* @param {object} options.labelFillGradientStops
* @param {object} options.fontVariant
* @param {object} options.labelLeading
* @param {object} options.letterSpacing
* @param {object} options.labelLineHeight
* @param {object} options.labelLineJoin
* @param {object} options.labelMiterLimit
* @param {object} options.labelPadding
* @param {object} options.labelTrim
* @param {object} options.textBaseline
* @param {object} options.labelWhiteSpace
*/
constructor(opts = {}) {
export default class Overlay {
constructor(options = {}) {
let defaultTextStyle = new PIXI.TextStyle()
Object.assign(
this,
{
let defaultOptions = {
type: 'auto',
name: 'unnamed',
borderColor: 0x000000,
borderThickness: 5,
disabledAlpha: 1,
disabledColor: 0xaa1111,
disabledBorderColor: 0x000000,
enabled: true,
labelScale: 1,
location: null,
@ -58,7 +95,7 @@ export default class Overlay {
labelType: null,
labelLocation: null,
labelAlignment: 'center',
labelVerticalAlign: 'underneath',
labelVerticalAlignment: 'underneath',
labelSpacing: 10,
labelTarget: null,
geometry: null,
@ -114,15 +151,76 @@ export default class Overlay {
labelTrim: defaultTextStyle.trim,
textBaseline: defaultTextStyle.textBaseline,
labelWhiteSpace: defaultTextStyle.whiteSpace
},
opts
)
}
defaultOptions = this.addDisabled(defaultOptions)
console.log('DISABLED VERTICALA.', defaultOptions.disabledLabelVerticalAlignment)
options = this.addDisabled(options)
options = Object.assign({}, defaultOptions, options)
Object.assign(this, options)
}
/**
* Some parameters shall not have a disabled option.
* These are defined here.
*
* @readonly
* @memberof Overlay
*/
get excludedDisableParameters() {
return ['items', 'rescale', 'name', 'type', 'enabled']
}
/**
* Copies the normal properties to the disabled version of the property,
* while conserving already set disabled properties.
*
* @param {*} options
* @returns {object} - Returns the modified options object.
* @memberof Overlay
*/
addDisabled(options) {
for (let [key, value] of Object.entries(options)) {
if (this.excludedDisableParameters.indexOf(key) == -1) {
let disabledProperty = this.toDisabledPropertyString(key)
if (options[disabledProperty] == undefined) {
options[disabledProperty] = value
}
}
}
return options
}
/**
* Textures need to be loaded by the app. Texture parameters return all parameters that need to be evaluated for textures.
* @readonly
* @member {array}
* @memberof Overlay
*/
get textureParameters() {
return ['icon']
const textureParameters = ['icon']
textureParameters.forEach(textureParameter => {
textureParameters.push(this.toDisabledPropertyString(textureParameter))
})
return textureParameters
}
/**
* The required textures are saved inside the single items.
* Their texture string gets replaced by a texture object
* containing the path and the texture.
*
* @param {*} parameter
* @param {*} key
* @param {*} path
* @memberof Overlay
*/
setTexture(parameter, key, path) {
let obj = (this[parameter] = {})
obj._key = key
@ -150,6 +248,14 @@ export default class Overlay {
})
}
/**
* Recursively calls a function on child items.
*
* @param {*} parameter
* @param {*} func
* @param {*} [obj=null]
* @memberof Overlay
*/
apply(parameter, func, obj = null) {
if (obj == null) return
if (Array.isArray(obj)) {
@ -187,13 +293,21 @@ export default class Overlay {
adjustItems = null,
cleanupItems = null
} = {}) {
const name = this.name[0].toUpperCase() + this.name.slice(1).toLowerCase() + ' Overlay'
console.log(this)
const name = this.name
? this.name[0].toUpperCase() + this.name.slice(1).toLowerCase() + ' Overlay'
: 'Unnamed Overlay'
let geoLayer = new GeoLayer(new PIXI.Container(), { name })
geoLayer.visibility = this.zoomVisibility
if (this.rescale) geoLayer.rescale = this.rescale
this.items.forEach(item => {
if (!excludeItems(item)) {
//Copies all values to a disabled state.
item = this.addDisabled(item)
if (adjustItems) {
adjustItems(item)
}
@ -208,11 +322,60 @@ export default class Overlay {
})
return geoLayer
}
/**
* Used to pick a property or disabled property using an enabled parameter.
*
* @param {*} item
* @param {*} property
* @param {boolean} [enabled=true]
* @returns {any} - Returns the picked item property.
* @memberof Overlay
*/
pickItemProperty(item, property, enabled = true) {
return enabled ? this.getItemProperty(item, property) : this.getDisabledItemProperty(item, property)
}
toDisabledPropertyString(propertyName) {
const prefix = 'disabled'
return prefix + propertyName[0].toUpperCase() + propertyName.slice(1)
}
/**
* Get's the disabled version of the property as long as it is not excluded.
*
* @param {*} item
* @param {*} property
* @returns {any} - Returns the picked item property.
* @memberof Overlay
*/
getDisabledItemProperty(item, property) {
if (this.excludedDisableParameters.indexOf(property) === -1) {
property = this.toDisabledPropertyString(property)
}
const propertyValue = this.getItemProperty(item, property)
return propertyValue
}
/**
* Tries to get the infromation from an overlay item.
* If the item does not contain the property, the overlay definition will be used.
* When the overlay definition is not set, the default value is used.
*
* @param {OverlayItem} item - Item to get the informations from.
* @param {string} property - Name of the property.
* @returns {any} - Returns the picked item property.
* @memberof Overlay
*/
getItemProperty(item, property) {
let propertyValue = null
const propertyExistsOnItem = item[property] !== undefined
const propertyExistsOnOverlay = this[property] !== undefined
if (property == 'disabledLabelVerticalAlignment') {
console.log(this)
console.log(this['disabledLabelVerticalAlignment'], propertyExistsOnItem, propertyExistsOnOverlay)
}
if (propertyExistsOnItem) propertyValue = item[property]
else if (propertyExistsOnOverlay) propertyValue = this[property]
else {
@ -229,6 +392,15 @@ export default class Overlay {
else return false
}
/**
* An overlay can have a reference to another file.
* That single overlays are more easy to maintain.
*
* @param {*} item
* @param {*} property
* @returns {any} - Returns the reference as object or the property.
* @memberof Overlay
*/
_resolveReference(item, property) {
if (this._isReference(property)) {
let referencedProperty = property['@property']
@ -281,18 +453,30 @@ export default class Overlay {
})
}
/**
* Creates a geographic for each item.
* By default it uses the regular routine but you may
* specify a factory for the defined type.
*
* @param {*} item
* @param {*} [informationCallback=null]
* @returns {GeoGraphics} - Returns the created geographics.
* @memberof Overlay
*/
createItem(item, informationCallback = null) {
let geographics
let type = this.getItemProperty(item, 'type')
/**
* Use a factory to draw the items, if a type is specified.
*/
if (this.type != 'auto') {
let geographicsFactory = Overlay.requestFactory(this.type)
if (type != 'auto') {
let geographicsFactory = Overlay.requestFactory(type)
if (!geographicsFactory)
console.error(
'Invalid Overlay Mode: ' +
this.type +
type +
'. Fallback to auto mode. Overlaymodes must be registeres beforehand. Valid modes are: ' +
Overlay.listFactories().join(',') +
'.'
@ -318,84 +502,100 @@ export default class Overlay {
this._drawRoutine(geographics, item, informationCallback)
}
this._drawLabel(item, geographics)
let label = this._createLabel(item, geographics)
if (label != null && geographics != null) {
console.log(geographics)
geographics.graphics.addChild(label)
}
}
return geographics
}
_drawLabel(item, geographics) {
let label = this.getItemProperty(item, 'label')
if (label) {
let textStyle = this._gatherFontStyle(item)
let text = new PIXI.Text(label, textStyle)
/**
*
* Draws a label that is shown next to the item on the map.
*
* @param {*} item
* @returns {PIXI.Text} - Returns the created label or null.
* @memberof Overlay
*/
_createLabel(item) {
let enabled = this.getItemProperty(item, 'enabled')
let labelText = this.pickItemProperty(item, 'label', enabled)
let label = null
let labelScale = this.getItemProperty(item, 'labelScale')
text.scale.set(labelScale, labelScale)
if (labelText) {
let textStyle = this._gatherFontStyle(item)
label = new PIXI.Text(labelText, textStyle)
let labelScale = this.pickItemProperty(item, 'labelScale', enabled)
label.scale.set(labelScale, labelScale)
let position = new PIXI.Point()
let align = this.getItemProperty(item, 'labelAlignment')
let align = this.pickItemProperty(item, 'labelAlignment', enabled)
if (align == 'left');
else if (align == 'center') position.set(text.position.x - text.width / 2, text.position.y)
else if (align == 'right') position.set(text.position.x - text.width, text.position.y)
else if (align == 'center') position.set(label.position.x - label.width / 2, label.position.y)
else if (align == 'right') position.set(label.position.x - label.width, label.position.y)
else this._logPropertyNotImplemented('labelAlignment', align)
let verticalAlign = this.getItemProperty(item, 'labelVerticalAlignment')
let verticalAlign = this.pickItemProperty(item, 'labelVerticalAlignment', enabled)
if (verticalAlign == 'underneath') {
let size = this.getItemProperty(item, 'size')
let scale = this.getItemProperty(item, 'scale')
let size = this.pickItemProperty(item, 'size', enabled)
let scale = this.pickItemProperty(item, 'scale', enabled)
let labelSpacing = this.getItemProperty(item, 'labelSpacing')
let labelSpacing = this.pickItemProperty(item, 'labelSpacing', enabled)
position.y += size * scale + labelSpacing
} else if (verticalAlign == 'above') {
let size = this.getItemProperty(item, 'size')
let scale = this.getItemProperty(item, 'scale')
let size = this.pickItemProperty(item, 'size', enabled)
let scale = this.pickItemProperty(item, 'scale', enabled)
let labelSpacing = this.getItemProperty(item, 'labelSpacing')
let labelSpacing = this.pickItemProperty(item, 'labelSpacing', enabled)
position.y -= size * scale + text.height + labelSpacing
position.y -= size * scale + label.height + labelSpacing
} else this._logPropertyNotImplemented('labelVerticalAlignment', verticalAlign)
text.position.set(position.x, position.y)
geographics.graphics.addChild(text)
label.position.set(position.x, position.y)
}
return label
}
_gatherFontStyle(item) {
const enabled = this.getItemProperty(item, 'enabled')
return {
align: this.getItemProperty(item, 'labelMultiLineAlign'),
breakWords: this.getItemProperty(item, 'labelBreakWords'),
dropShadow: this.getItemProperty(item, 'labelDropShadow'),
dropShadowAlpha: this.getItemProperty(item, 'labelDropShadowAlpha'),
dropShadowAngle: this.getItemProperty(item, 'labelDropShadowAngle'),
dropShadowBlur: this.getItemProperty(item, 'labelDropShadowBlur'),
dropShadowColor: this.getItemProperty(item, 'labelDropShadowColor'),
dropShadowDistance: this.getItemProperty(item, 'labelDropShadowDistance'),
fontFamily: this.getItemProperty(item, 'fontFamily'),
fontSize: this.getItemProperty(item, 'fontSize'),
fontStyle: this.getItemProperty(item, 'fontStyle'),
fontWeight: this.getItemProperty(item, 'fontWeight'),
stroke: this.getItemProperty(item, 'labelStroke'),
strokeThickness: this.getItemProperty(item, 'labelStrokeThickness'),
wordWrap: this.getItemProperty(item, 'wordWrap'),
wordWrapWidth: this.getItemProperty(item, 'wordWrapWidth'),
fill: this.getItemProperty(item, 'labelFill'),
fillGradientType: this.getItemProperty(item, 'labelFillGradientType'),
fillGradientStops: this.getItemProperty(item, 'labelFillGradientStops'),
fontVariant: this.getItemProperty(item, 'fontVariant'),
leading: this.getItemProperty(item, 'labelLeading'),
letterSpacing: this.getItemProperty(item, 'letterSpacing'),
lineHeight: this.getItemProperty(item, 'labelLineHeight'),
lineJoin: this.getItemProperty(item, 'labelLineJoin'),
miterLimit: this.getItemProperty(item, 'labelMiterLimit'),
padding: this.getItemProperty(item, 'labelPadding'),
trim: this.getItemProperty(item, 'labelTrim'),
textBaseline: this.getItemProperty(item, 'textBaseline'),
whiteSpace: this.getItemProperty(item, 'labelWhiteSpace')
align: this.pickItemProperty(item, 'labelMultiLineAlign', enabled),
breakWords: this.pickItemProperty(item, 'labelBreakWords', enabled),
dropShadow: this.pickItemProperty(item, 'labelDropShadow', enabled),
dropShadowAlpha: this.pickItemProperty(item, 'labelDropShadowAlpha', enabled),
dropShadowAngle: this.pickItemProperty(item, 'labelDropShadowAngle', enabled),
dropShadowBlur: this.pickItemProperty(item, 'labelDropShadowBlur', enabled),
dropShadowColor: this.pickItemProperty(item, 'labelDropShadowColor', enabled),
dropShadowDistance: this.pickItemProperty(item, 'labelDropShadowDistance', enabled),
fontFamily: this.pickItemProperty(item, 'fontFamily', enabled),
fontSize: this.pickItemProperty(item, 'fontSize', enabled),
fontStyle: this.pickItemProperty(item, 'fontStyle', enabled),
fontWeight: this.pickItemProperty(item, 'fontWeight', enabled),
stroke: this.pickItemProperty(item, 'labelStroke', enabled),
strokeThickness: this.pickItemProperty(item, 'labelStrokeThickness', enabled),
wordWrap: this.pickItemProperty(item, 'wordWrap', enabled),
wordWrapWidth: this.pickItemProperty(item, 'wordWrapWidth', enabled),
fill: this.pickItemProperty(item, 'labelFill', enabled),
fillGradientType: this.pickItemProperty(item, 'labelFillGradientType', enabled),
fillGradientStops: this.pickItemProperty(item, 'labelFillGradientStops', enabled),
fontVariant: this.pickItemProperty(item, 'fontVariant', enabled),
leading: this.pickItemProperty(item, 'labelLeading', enabled),
letterSpacing: this.pickItemProperty(item, 'letterSpacing', enabled),
lineHeight: this.pickItemProperty(item, 'labelLineHeight', enabled),
lineJoin: this.pickItemProperty(item, 'labelLineJoin', enabled),
miterLimit: this.pickItemProperty(item, 'labelMiterLimit', enabled),
padding: this.pickItemProperty(item, 'labelPadding', enabled),
trim: this.pickItemProperty(item, 'labelTrim', enabled),
textBaseline: this.pickItemProperty(item, 'textBaseline', enabled),
whiteSpace: this.pickItemProperty(item, 'labelWhiteSpace', enabled)
}
}
@ -440,25 +640,27 @@ export default class Overlay {
}
_createIcon(geographics, item) {
let icon = this.getItemProperty(item, 'icon')
let enabled = this.getItemProperty(item, 'enabled')
let icon = this.pickItemProperty(item, 'icon', enabled)
if (icon) {
if (icon.texture) {
let sprite = new PIXI.Sprite(icon.texture)
const iconAnchor = this.getItemProperty(item, 'iconAnchor')
const iconAnchor = this.pickItemProperty(item, 'iconAnchor', enabled)
sprite.anchor.set(iconAnchor.x, iconAnchor.y)
const iconScale = this.getItemProperty(item, 'iconScale')
const iconScale = this.pickItemProperty(item, 'iconScale', enabled)
if (iconScale) sprite.scale.set(iconScale, iconScale)
const iconOffset = this.getItemProperty(item, 'iconOffset')
const iconOffset = this.pickItemProperty(item, 'iconOffset', enabled)
if (iconOffset && iconOffset.x != null && iconOffset.y != null)
sprite.position.set(iconOffset.x, iconOffset.y)
const iconColor = this.getItemProperty(item, 'iconColor')
const iconColor = this.pickItemProperty(item, 'iconColor', enabled)
if (iconColor) sprite.tint = iconColor
const iconAlpha = this.getItemProperty(item, 'iconAlpha')
const iconAlpha = this.pickItemProperty(item, 'iconAlpha', enabled)
if (iconAlpha) sprite.alpha = iconAlpha
geographics.graphics.addChild(sprite)
@ -468,28 +670,6 @@ export default class Overlay {
_createInformation(geographics, item, callback = null) {
if (item.information) {
/**
* SO: The overlay class is quite convenient.
* But managing the information creation solely inside this
* class restricts us massively.
*
* Maybe a restructuring would be good, that we can handle
* the creation of information with a callback and can adapt
* to any occuring situation.
*
* e.g.
*
* overlay.informationHandler((geo, type, item)=>{
* switch(type){
* case "popup":
* createPopup(item.information)
* break;
*
* ....
* }
* })
*/
geographics.graphics.interactive = true
const informationType = this.getItemProperty(item, 'informationType')
@ -538,17 +718,21 @@ export default class Overlay {
_fill(geographics, item) {
const enabled = this.getItemProperty(item, 'enabled')
const color = enabled ? this.getItemProperty(item, 'color') : this.getItemProperty(item, 'disabledColor')
let alpha = enabled ? this.getItemProperty(item, 'fillAlpha') : this.getItemProperty(item, 'disabledAlpha')
const color = this.pickItemProperty(item, 'color', enabled)
const alpha = this.pickItemProperty(item, 'fillAlpha', enabled)
geographics.graphics.beginFill(color, alpha)
}
_drawPoint(item, informationCallback = null) {
const overlay = this
const enabled = this.getItemProperty(item, 'enabled')
let that = this
let geographic = new GeoPoint(item.location, {
onDraw: function() {
overlay._fill.call(overlay, this, item)
const size = overlay.getItemProperty(item, 'size') ? overlay.getItemProperty(item, 'size') : 0
const size = that.pickItemProperty(item, 'size', enabled)
this.graphics.drawCircle(0, 0, size)
overlay._drawRoutine.call(overlay, this, item, informationCallback)
}
@ -563,10 +747,19 @@ export default class Overlay {
Overlay.Modes = { auto: null }
Overlay.createFactory = function(name, geographicsFactory) {
if (Overlay.Modes.hasOwnProperty(name))
console.warn(`The mode ${name} was already implemented and was overwritten!`)
Overlay.Modes[name] = geographicsFactory
/**
* Creates a factory for a specific type.
*
* @param {string} type - Name of the factory. When overlay items match the type, the factory is applied.
* @param {function} geographicsFactory - A function that is called with every item. Can be used to draw the geographics individually.
*
* @static
* @memberof {Overlay}
*/
Overlay.createFactory = function(type, geographicsFactory) {
if (Overlay.Modes.hasOwnProperty(type))
console.warn(`The mode ${type} was already implemented and was overwritten!`)
Overlay.Modes[type] = geographicsFactory
}
Overlay.requestFactory = function(name) {