///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.ImageEngine = ImageEngine;
return ns;
//---------------------------------------------------------
function ImageEngine(options) {
var me = this;
var api = new ns.Factory(null, null, options).getApi();
var resultType = "string";
//---------------------------------------------------------
this.usingMap = function (map) {
me.map = map;
return this;
}
this.getImage = function () {
return new Promise(function (resolve, reject) {
var snap = me.map.getSnapshot();
api.getImage(snap)
.success(function (data, xhr) {
resolve(new Image(xhr));
});
});
}
//---------------------------------------------------------
function Image(xhr) {
this.blob = function (properties) {
var blob = new Blob([xhr.response], {
type: xhr.getResponseHeader("Content-Type")
});
return URL.createObjectURL(blob);
}
this.base64 = function () {
return "data:"
+ xhr.getResponseHeader("Content-Type")
+ ";base64,"
+ btoa(String.fromCharCode.apply(null, new Uint8Array(xhr.response)));
}
}
}
})(Mapzania || {})
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.Layer = Layer;
return ns;
//---------------------------------------------------------
function Layer(key, map) {
//-------------------- FLUENT -------------------------
this.usingFeature = function (id) {
return new ns.MapFeature(id, key, map);
}
// ------------------- LAYERS -------------------------
this.update = function () {
map.updateLayer(key);
return this;
}
//-------------FEATURES----------------------
this.show = function () {
map.showLayer(key);
return this;
};
this.hide = function () {
map.hideLayer(key);
return this;
};
this.addFeatureCollection = function (featureCollection) {
map.addFeatureCollection(key, featureCollection);
return this;
}
this.addFeature = function (feature) {
map.addFeature(key, feature);
return this;
}
this.clearFeatures = function () {
map.clearFeatures(key);
return this;
};
//-------------POSITION----------------------
this.sendBackwards = function () {
map.sendLayerBackwards(key);
return this;
};
this.bringForwards = function () {
map.bringLayerForwards(key);
return this;
};
this.addFeatureCollection = function (featureCollection) {
map.addFeatureCollection(key, featureCollection);
return this;
}
this.addFeature = function (feature) {
map.addFeature(key, feature);
return this;
}
this.clearFeatures = function () {
map.clearFeatures(key);
return this;
};
//---------------- FILTERS -----------------------------
//[non-documented]
this.addFilter = function (filter, index) {
map.addFilter(key, filter, index);
return this;
}
//[non-documented]
this.removeFilter = function (index) {
map.removeFilter(key, index);
return this;
}
this.clearFilters = function () {
map.clearFilters(key);
return this;
};
this.bufferGeometry = function (factor, options) {
if (!ns.Util.isObject(options))
options = {};
var filter = ns.Filters.bufferGeometry(
factor,
options.side,
options.joins,
options.ends,
options.mitreLimit,
options.srid //[non-documented]
);
map.addFilter(key, filter);
return this;
}
this.changeProperties = function (properties) {
var filter = ns.Filters.changeProperties(properties);
map.addFilter(key, filter);
return this;
}
this.clipByFeatureCollection = function (featureCollection) {
var filter = ns.Filters.clipByFeatureCollection(featureCollection);
map.addFilter(key, filter);
return this;
}
this.convertToCentroids = function () {
var filter = ns.Filters.convertToCentroids();
map.addFilter(key, filter);
return this;
}
this.filterByBoundingBox = function (bbox) {
var filter = ns.Filters.filterByBoundingBox(bbox);
map.addFilter(key, filter);
return this;
}
this.filterByFeatureCollection = function (features, options) {
if (!ns.Util.isObject(options))
options = {};
var filter = ns.Filters.filterByFeatureCollection(
features,
options.operation
);
map.addFilter(key, filter);
return this;
}
this.filterByNearest = function (point, options) {
if (!ns.Util.isObject(options))
options = {};
var filter = ns.Filters.filterByNearest(
point,
options.take,
options.includeDistance
);
map.addFilter(key, filter);
return this;
}
this.filterByText = function (statement, options) {
if (!ns.Util.isObject(options))
options = {};
var filter = ns.Filters.filterByText(
statement,
options.passthru //[non-documented]
);
map.addFilter(key, filter);
return this;
}
//[non-documented]
this.aggregate = function (param, aggregation) {
if (typeof (param) == "string")
return this.aggregateByLayer(param, aggregation);
return this.aggregateByFeatures(param, aggregation);
}
//[non-documented]
this.aggregateByFeatures = function (featuresCollection, aggregation) {
var filter = ns.Filters.aggregateByFeatures(featuresCollection, aggregation);
map.addFilter(key, filter);
return this;
}
//[non-documented]
this.aggregateByLayer = function (layersource, aggregation) {
var filter = ns.Filters.aggregateByLayer(layersource, aggregation);
map.addFilter(key, filter);
return this;
}
//[non-documented]
this.aggregateLinesByOriginAndDestination = function (gridSize, includeCount) {
var filter = ns.Filters.aggregateLinesByOriginAndDestination(gridSize, includeCount);
map.addFilter(key, filter);
return this;
}
//[non-documented]
this.changeCoordinateSystem = function (srid) {
var filter = ns.Filters.changeCoordinateSystem(srid);
map.addFilter(key, filter);
return this;
}
//[non-documented]
this.cluster = function (factor, properties) {
return this.clusterPoints(factor, properties);
}
//[non-documented]
this.clusterPoints = function (factor, properties) {
var filter = ns.Filters.clusterPoints(factor, properties);
map.addFilter(key, filter);
return this;
}
//[non-documented]
this.filterByLayer = function (layerKey, layerFilters, operation) {
var sourceKey = map.getLayer(layerKey).sourceKey;
var filter = ns.Filters.filterByLayer(sourceKey, layerFilters, operation);
map.addFilter(key, filter);
return this;
}
//[non-documented]
this.split = function (param, method) {
if (typeof (param) == "string")
return this.splitLineByLayer(param, method);
return this.splitLineByFeatures(param, method);
}
//[non-documented]
this.splitLineByFeatures = function (featureCollection, method) {
var filter = ns.Filters.splitLineByFeatures(featureCollection, method);
map.addFilter(key, filter);
return this;
}
//[non-documented]
this.splitLineByLayer = function (layerSource, method) {
var filter = ns.Filters.splitLineByLayer(layerSource, method);
map.addFilter(key, filter);
return this;
}
// ------------------ STYLING ----------------------------
this.style = function (style) {
map.setLayerStyle(key, style);
return this;
};
//[non-documented]
this.setLayerStyle = this.style;
//[non-documented]
this.addLayerStyle = function (style) {
map.addLayerStyle(key, style);
return this;
};
this.clearLayerStyles = function () {
map.clearLayerStyles(key);
return this;
};
this.clearStyle = function () {
map.clearLayerStyles(key);
return this;
};
this.styleFeature = function (id, style) {
map.setFeatureStyle(key, id, style);
return this;
};
// -------------- QUERYING -------------------------------
this.getFeatureCollection = function () {
return map.getFeatureCollection(key);
};
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.Map = Map;
return ns;
//---------------------------------------------------------
function Map(elementId, mapKey, param1, param2) {
var engine, layerManager, mouseEngine, toolbar;
ns.Util.eventify(this, "Map");
var me = this;
var factory = new ns.Factory(elementId, mapKey, param1, param2);
factory.start()
.then(function (done) {
engine = factory.getEngine();
layerManager = factory.getLayerManager();
mouseEngine = factory.getMouseEngine();
toolbar = factory.getToolbar();
engine.on("layer_changed", function (result) {
var eventName = (result.key + "_layer_changed").toLowerCase();
me.fire(eventName, result.data);
})
engine.on("view_changed", function (data) {
me.fire("view_changed", data);
})
mouseEngine.onAll(function (event) {
me.fire(event.type, event.data);
})
ns.Log.debug("Object created.", "Map");
done();
me._debug = {
engine: engine,
layerManager: layerManager,
mouseEngine: mouseEngine,
toolbar: toolbar
};
});
//------------------ INFO ----------------------------
//[non-documented]
this.getKey = function () {
return mapKey;
};
//[non-documented]
this.getSnapshot = function () {
return factory.createSnapshot();
}
//[non-documented]
this.getViewer = function () {
var view = factory.getView();
return view.getViewer();
}
//------------------ FLUENT ----------------------------
this.usingLayer = function (layerKey) {
return new ns.Layer(layerKey, this);
}
this.usingNewLayer = function (layerKey) {
this.addLayer(layerKey);
return new ns.Layer(layerKey, this);
}
//------------- MAP MANIPULATION -----------------------
this.setMouseMode = function (mode) {
mouseEngine.setMode(mode);
return this;
}
this.getMouseMode = function () {
return mouseEngine.getMode();
}
this.refresh = function () {
engine.refresh();
return this;
}
this.reset = function () {
engine.reset();
return this;
};
this.fitToBoundingBox = function (bbox, buffer) {
engine.fitToBoundingBox(bbox, buffer);
return this;
};
//this._zoomIn = function (delta) {
// engine.zoomIn(delta);
//}
//this._zoomOut = function (delta) {
// engine.zoomOut(delta);
//}
////TODO:
//this._setSchema = function (schema) {
// model.setSchema(schema);
//}
////TODO:
//this._getSchema = function () {
// return model.getSchema();
//}
this.setBackgroundColor = function (color) {
engine.setBackColor(color);
}
// ----------------- LAYERS ----------------------------
this.getLayers = function () {
return layerManager.getLayers().map(function (layer) {
return layer.info();
});
};
//[fluent-only]
this.getLayer = function (layerKey) {
return layerManager.getLayer(layerKey).info();
};
//[fluent-only]
//[non-documented params(layerJson, index)]
this.addLayer = function (layerKey, layerJson, index) {
layerManager.addLayer(layerKey, layerJson, index);
}
//[non-documented]
this.removeLayer = function (layerKey) {
layerManager.removeLayer(layerKey);
}
//[fluent-only]
this.updateLayer = function (layerKey) {
engine.updateLayer(layerKey);
}
//[fluent-only]
this.sendLayerBackwards = function (layerKey) {
layerManager.sendLayerBackwards(layerKey);
}
//[fluent-only]
this.bringLayerForwards = function (layerKey) {
layerManager.bringLayerForwards(layerKey);
}
//[non-documented]
this.replaceLayer = function (layerKey, layerJson) {
layerManager.replaceLayer(layerKey, layerJson);
}
//------------LAYER MANIPULATION------------------------
this.showLayer = function (layerKey) {
layerManager.showLayer(layerKey);
};
this.hideLayer = function (layerKey) {
layerManager.hideLayer(layerKey);
};
this.addFeatureCollection = function (layerKey, featureCollection) {
layerManager.getLayer(layerKey)
.addFeatureCollection(featureCollection);
}
this.addFeature = function (layerKey, feature) {
layerManager.getLayer(layerKey).addFeature(feature);
}
this.clearFeatures = function (layerKey) {
layerManager.getLayer(layerKey).clearFeatures();
}
////TODO:
//this.changeLayerKey = function (key, newKey) {
// layerManager.changeLayerKey(key, newKey);
//}
//--------------- FILTERS -------------------------------
this.getStateFilters = function (layerKey) {
return engine.getStateFilters(layerKey);
}
this.getFilters = function (layerKey) {
return layerManager.getLayer(layerKey).getFilters();
}
this.addFilter = function (layerKey, filter, index) {
layerManager.getLayer(layerKey).addFilter(filter, index);
}
this.removeFilter = function (layerKey, index) {
layerManager.getLayer(layerKey).removeFilter(index);
}
this.clearFilters = function (layerKey) {
layerManager.getLayer(layerKey).clearFilters();
}
// ----------------- QUERY MAP -------------------------
this.queryLayer = function (layerKey, options) {
var qe = factory.createQueryEngine();
return qe.usingMapLayer(this, layerKey, options);
}
this.getFeatureCollection = function (layerKey) {
var layer = layerManager.getLayer(layerKey);
var fe = layer.getFeatureEngine();
return fe.getFeatureCollection();
}
////TODO:*
//this.getFeature = function (layerKey, id) {
// return this.getFeatureCollection(layerKey).find(function (obj) {
// return id == obj.id;
// });
//}
this.getBoundingBox = function () {
return engine.getBoundingBox();
};
this.getInitialBoundingBox = function () {
return engine.getInitialBoundingBox();
};
// ------------FEATURE MANIPULATION -----------------------
this.hideFeature = function (layerKey, id) {
layerManager.getLayer(layerKey).hideFeature(id);
}
this.showFeature = function (layerKey, id) {
layerManager.getLayer(layerKey).showFeature(id);
}
// ---------------- STYLING -------------------------------
this.setLayerStyle = function (layerKey, style) {
var layer = layerManager.getLayer(layerKey);
layer.clearStyles();
layer.addStyle(style);
}
this.addLayerStyle = function (layerKey, style) {
layerManager.getLayer(layerKey).addStyle(style);
}
this.clearLayerStyles = function (layerKey) {
layerManager.getLayer(layerKey).clearStyles();
}
this.setFeatureStyle = function (layerKey, id, style) {
layerManager.getLayer(layerKey).setFeatureStyle(id, style);
}
this.clearFeatureStyle = function (layerKey, id) {
layerManager.getLayer(layerKey).setFeatureStyle(id);
}
// ---------------- THEMING -----------------------------
//[non-documented]
this.addTheme = function (layerKey, themeJson) {
var themer = layerManager.getLayer(layerKey).getThemer();
themer.addThemeJson(themeJson);
}
//[non-documented]
this.updateTheme = function (layerKey, index, themeJson) {
var themer = layerManager.getLayer(layerKey).getThemer();
themer.updateTheme(index, themeJson);
}
//[non-documented]
this.removeTheme = function (layerKey, index) {
var themer = layerManager.getLayer(layerKey).getThemer();
themer.removeTheme(index);
}
return this;
};
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.MapFeature = MapFeature;
return ns;
//---------------------------------------------------------
function MapFeature(id, layerKey, map) {
// ------------------ LAYERS --------------------------
this.update = function () {
map.updateLayer(layerKey);
return this;
}
// ------------- FEATURE MANIPULATION -----------------
this.show = function () {
map.showFeature(layerKey, id);
return this;
};
this.hide = function () {
map.hideFeature(layerKey, id);
return this;
};
// ------------------- STYLING ------------------------
this.style = function (style) {
map.setFeatureStyle(layerKey, id, style);
return this;
};
this.clearStyle = function () {
map.clearFeatureStyle(layerKey, id);
return this;
};
}
})(Mapzania || {});
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.Constants = ns.Constants || {};
ns.Constants.QUERYENGINE_LAYERSOURCE_NAME = "MAPZANIA_QUERYENGINE_LAYERSOURCE";
ns.QueryEngine = QueryEngine;
return ns;
//---------------------------------------------------------
function QueryEngine(options) {
var api = new ns.Factory(null, null, options).getApi();
//---------------------------------------------------------
this.usingFeatureCollection = function (featureCollection) {
var filters = [{
type: "AddFeatureCollection",
features: featureCollection
}];
sourceKey = ns.Constants.QUERYENGINE_LAYERSOURCE_NAME;
return new Query(sourceKey, filters);
}
this.usingLayerSource = function (sourceKey) {
return new Query(sourceKey);
}
this.usingMapLayer = function (map, layerKey, options) {
var defaults = {
useState: true,
useFilters: true
};
var settings = Object.assign(defaults, options);
var layer = map.getLayer(layerKey);
var sourceKey = layer.sourceKey;
var filters = [];
if (settings.useFilters)
Array.prototype.push.apply(filters, map.getFilters(layerKey));
if (settings.useState)
Array.prototype.push.apply(filters, map.getStateFilters(layerKey));
return new Query(sourceKey, filters);
}
//---------------------------------------------------------
function Query (sourceKey, filters) {
if (!filters)
filters = [];
this.bufferGeometry = function (factor, options) {
if (!ns.Util.isObject(options))
options = {};
var filter = ns.Filters.bufferGeometry(
factor,
options.side,
options.joins,
options.ends,
options.mitreLimit,
options.srid //[non-documented]
);
filters.push(filter);
return this;
}
this.changeProperties = function (properties) {
var filter = ns.Filters.changeProperties(properties);
filters.push(filter);
return this;
}
this.clipByFeatureCollection = function (featureCollection) {
var filter = ns.Filters.clipByFeatureCollection(featureCollection);
filters.push(filter);
return this;
}
this.convertToCentroids = function () {
var filter = ns.Filters.convertToCentroids();
filters.push(filter);
return this;
}
this.filterByBoundingBox = function (bbox) {
var filter = ns.Filters.filterByBoundingBox(bbox);
filters.push(filter);
return this;
}
this.filterByFeatureCollection = function (features, options) {
if (!ns.Util.isObject(options))
options = {};
var filter = ns.Filters.filterByFeatureCollection(
features,
options.operation
);
filters.push(filter);
return this;
}
this.filterByNearest = function (point, options) {
if (!ns.Util.isObject(options))
options = {};
var filter = ns.Filters.filterByNearest(point, options.take, options.includeDistance);
filters.push(filter);
return this;
}
this.filterByText = function (statement, options) {
if (!ns.Util.isObject(options))
options = {};
var filter = ns.Filters.filterByText(
statement,
options.passthru //[non-documented]
);
filters.push(filter);
return this;
}
//[non-documented]
this.changeCoordinateSystem = function (srid) {
var filter = ns.Filters.changeCoordinateSystem(srid);
filters.push(filter);
return this;
}
//[non-documented]
this.filterByLayer = function (layerKey, layerFilters, operation) {
var filter = ns.Filters.filterByLayer(layerKey, layerFilters, operation);
filters.push(filter);
return this;
}
this.apply = function () {
return new Promise(function (resolve, reject) {
api.getFeatures(sourceKey, filters)
.success(function (data, xhr) {
resolve(data);
})
});
return res;
}
}
}
})(Mapzania || {})
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.Ajax = request;
return ns;
//---------------------------------------------------------
function request(options) {
var defaults = {
type: 'GET',
url: null,
data: {},
callback: null,
headers: {
'Content-type': 'application/x-www-form-urlencoded',
'Access-Control-Allow-Origin':'*'
},
responseType: 'text',
withCredentials: false
};
var settings = ns.Util.assign({}, defaults, options || {});
return _xhr(settings);
};
//---------------------------------------------------------
function _parse(req, settings) {
var result;
if (settings.responseType !== 'text' && settings.responseType !== '') {
return [req.response, req];
}
try {
result = JSON.parse(req.responseText, settings);
} catch (e) {
result = req.responseText;
}
return [result, req];
};
function _param(obj, settings) {
if (typeof (obj) === 'string') return obj;
if (/application\/json/i.test(settings.headers['Content-type']) || Object.prototype.toString.call(obj) === '[object Array]') return JSON.stringify(obj);
var encoded = [];
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
encoded.push(encodeURIComponent(prop) + '=' + encodeURIComponent(obj[prop]));
}
}
return encoded.join('&');
};
function _xhr (settings) {
// Our default methods
var methods = {
success: function () { },
error: function () { },
always: function () { },
cancelled: function () { }
};
// Override defaults with user methods and setup chaining
var atomXHR = {
success: function (callback) {
methods.success = callback;
return atomXHR;
},
error: function (callback) {
methods.error = callback;
return atomXHR;
},
always: function (callback) {
methods.always = callback;
return atomXHR;
},
cancelled: function (callback) {
methods.cancelled = callback;
return atomXHR;
}
};
// Create our HTTP request
var request = new XMLHttpRequest();
// Setup our listener to process compeleted requests
request.onreadystatechange = function () {
// Only run if the request is complete
if (request.readyState !== 4) return;
// Parse the response text
var req = _parse(request, settings);
// Process the response
if (request.status === 0) {
// aborted request
methods.cancelled.apply(methods, req, request);
}
else if (request.status >= 200 && request.status < 300) {
// If successful
methods.success.apply(methods, req, request);
} else {
// If failed
methods.error.apply(methods, req, request);
}
// Run always
methods.always.apply(methods, req, request);
};
// Setup our HTTP request
request.open(settings.type, settings.url, true);
request.responseType = settings.responseType;
// Add headers
for (var header in settings.headers) {
if (settings.headers.hasOwnProperty(header)) {
request.setRequestHeader(header, settings.headers[header]);
}
}
// Add withCredentials
if (settings.withCredentials) {
request.withCredentials = true;
}
// Send the request
request.send(_param(settings.data, settings));
// add abort function so we can the request later.
atomXHR.abort = function () {
request.abort();
}
atomXHR.overrideMimeType = function (type) {
request.overrideMimeType(type);
};
return atomXHR;
};
})(Mapzania || {})
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.Api = Api;
return ns;
//---------------------------------------------------------
function Api(path, isCompact) {
ns.Log.debug("Object created.", "Api");
this.getMap = function (mapKey) {
return _get(path + "maps/" + mapKey);
}
this.getSources = function (mapKey) {
return _get(path + "sources");
}
this.getFeatures = function (sourceKey, filters, options) {
var params = {
filters: filters,
options: {
isCompact: false
}
};
return _post(path + "sources/" + sourceKey + "/features", params);
}
this.getImage = function (map) {
var xhr = _post(path + "maps/" + map.key + "/image", map, "arraybuffer");
//xhr.overrideMimeType("text/plain; charset=x-user-defined");
return xhr;
}
//---------------------------------------------------------
var _get = function (url) {
Mapzania.Log.debug("The following url was requested: " + url, "Api._get()");
return ns.Ajax({ url: url });
}
var _post = function (url, parameters, responseType) {
Mapzania.Log.debug("The following url was requested: " + url, "Api._post()");
var settings = {
url: url,
headers: {
"Content-type": "application/json; charset=utf-8"
},
data: JSON.stringify(parameters),
type: "POST"
};
if (responseType)
settings.responseType = responseType;
return ns.Ajax(settings);
}
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.DrawingEngine = DrawingEngine;
return ns;
//---------------------------------------------------------
function DrawingEngine(layer) {
var GJ = ns.GeoJson;
this.run = run;
//---------------------------------------------------------
function run(featureCollection, state) {
var res = GJ.empty();
featureCollection.features.forEach(function (ftr) {
var themer = layer.getThemer();
var theme = themer.getTheme(state.zoom, GJ.getId(ftr));
if (theme) {
var symbol = theme.getSymbol(ftr);
if (symbol)
ns.Util.arrayAppend(_unpack(symbol, ftr), res.features);
}
})
res.features.sort(function (a, b) {
return a.level - b.level;
});
return res;
}
function _unpack(symbol, feature) {
var features = [];
switch (symbol.type) {
case "PointSymbol":
_unpackPoint(features, symbol, feature, 0);
break;
case "CompoundPointSymbol":
_unpackCompoundPoint(features, symbol, feature, 0);
break;
case "LineSymbol":
_unpackLine(features, symbol, feature, 0);
break;
case "CompoundLineSymbol":
_unpackCompoundLine(features, symbol, feature, 0);
break;
case "FillSymbol":
_unpackFill(features, symbol, feature, 0);
break;
default:
ns.Util.logAndThrow("Invalid symbol type: " + symbol.type,
"DrawingEngine.run()");
}
return features;
}
function _unpackPoint(features, symbol, feature, level) {
var ftr = ns.Util.assign({}, feature);
var sym = ns.Util.assign({}, symbol);
if (ns.Util.isNullOrUndefined(sym.rotation))
sym.rotation = { angle: 0, originX: 0, originY: 0 };
else
sym.rotation = ns.Util.assign({}, sym.rotation);
if (ns.Util.isNullOrUndefined(sym.offset))
sym.offset = { x: 0, y: 0 };
else
sym.offset = ns.Util.assign({}, sym.offset);
if (!ns.Util.isNullOrUndefined(ftr.properties.rotation))
sym.rotation.angle += 90 - GJ.Math.radiansToDegrees(ftr.properties.rotation);
ftr.symbol = sym;
ftr.level = level;
features.push(ftr);
}
function _unpackCompoundPoint(features, symbol, feature, level) {
var pointLevel = level;
for (var i = symbol.points.length - 1; i >= 0; i--) {
_unpackPoint(features, symbol.points[i], feature, pointLevel++);
}
}
function _unpackLine(features, symbol, feature, level) {
var lineLength;
// Add line
var ftr = ns.Util.assign({}, feature);
ftr.symbol = ns.Util.assign({}, symbol);
ftr.level = level;
features.push(ftr);
function getLines(geom) {
if (geom.type == "MultiLineString")
return GJ.explode(geom);
else
return [geom];
};
if (symbol.intervalSymbol && symbol.intervalSymbol.points.length > 0 && symbol.intervalSymbolSpacing) {
var geoms = getLines(ftr.geometry);
geoms.forEach(g => {
lineLength = lineLength || GJ.getLength(g);
var spacing = symbol.intervalSymbolSpacing;
var length = lineLength - spacing;
var current = spacing;
while (current < length) {
var point = GJ.getFeatureAt(g, current);
_unpackCompoundPoint(features, symbol.intervalSymbol, point, level);
current += spacing;
}
});
}
if (symbol.tailSymbol && symbol.tailSymbol.points.length > 0) {
var geoms = getLines(ftr.geometry);
geoms.forEach(g => {
var point = GJ.getFeatureAt(g, 0);
_unpackCompoundPoint(features, symbol.tailSymbol, point, level);
});
}
if (symbol.headSymbol && symbol.headSymbol.points.length > 0) {
var geoms = getLines(ftr.geometry);
geoms.forEach(g => {
lineLength = lineLength || GJ.getLength(g);
var point = GJ.getFeatureAt(g, lineLength);
_unpackCompoundPoint(features, symbol.headSymbol, point, level);
});
}
}
function _unpackCompoundLine(features, symbol, feature, level) {
var lineLevel = level;
for (var i = symbol.lines.length - 1; i >= 0; i--) {
_unpackLine(features, symbol.lines[i], feature, lineLevel++);
}
}
function _unpackFill(features, symbol, feature, level) {
if (feature.geometry.type == "Polygon") {
unpack(features, symbol, feature, level)
}
else if (feature.geometry.type == "MultiPolygon") {
GJ.explode(feature.geometry).forEach(poly => {
var ftr = GJ.createFeature(poly, feature.properties, feature.properties.Id);
unpack(features, symbol, ftr, level)
});
}
function unpack(features, symbol, feature, level) {
//Inside fill
var ftr = ns.Util.assign({}, feature);
ftr.symbol = ns.Util.assign({}, symbol);
ftr.symbol.outline = null;
ftr.level = level;
features.push(ftr);
if (symbol.outline) {
var lines = GJ.explode(ftr.geometry);
for (var i = 0; i < lines.length; i++) {
var line = lines[i];
var lineFeature = GJ.createFeature(line, ftr.properties, ftr.id);
if (symbol.outline.type == "CompoundLineSymbol")
_unpackCompoundLine(features, symbol.outline, lineFeature, level + 1);
if (symbol.outline.type == "LineSymbol")
_unpackLine(features, symbol.outline, lineFeature, level + 1);
}
}
}
}
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.Engine = Engine;
return ns;
//---------------------------------------------------------
function Engine(factory) {
var me = this;
var view = factory.getView();
var schema = factory.getSchema();
var layerManager = factory.getLayerManager();
this.fitToBoundingBox = fitToBoundingBox;
this.getBoundingBox = getBoundingBox;
this.getInitialBoundingBox = getInitialBoundingBox;
this.updateLayer = updateLayer;
this.refresh = refresh;
this.reset = reset;
this.zoomIn = zoomIn;
this.zoomOut = zoomOut;
this.setBackColor = setBackColor;
this.getStateFilters = getStateFilters;
ns.Util.eventify(this, "Engine");
init();
//-----------------------------------------------------
function init() {
view.fitToBoundingBox(schema.getInitialBoundingBox());
view.setBackColor(schema.getBackColor());
view.setControls(factory.getControls());
view.on("changed", function (state) {
_updateAll(state);
me.fire("view_changed", {
boundingBox: [].concat(state.bounds),
zoom: state.zoom,
center: Object.assign({}, state.center)
});
})
layerManager.on("layer_added", function (data) {
view.addLayer(data.layer, data.index);
_updateLabels();
})
layerManager.on("layer_removed", function (layer) {
view.removeLayer(layer);
_updateLabels();
})
layerManager.on("layer_shown", function (layer) {
view.showLayer(layer);
_update(layer, view.getState());
//_updateLabels() - not neccessary happens in _update.
})
layerManager.on("layer_hidden", function (layer) {
view.hideLayer(layer);
_updateLabels();
})
layerManager.on("layer_replaced", function (data) {
view.replaceLayer(data.key, data.layer);
_updateLabels();
})
layerManager.on("layer_brought_forwards", function (layer) {
view.bringLayerForwards(layer);
})
layerManager.on("layer_sent_backwards", function (layer) {
view.sendLayerBackwards(layer);
})
layerManager.getLayers().forEach(function (layer) {
view.addLayer(layer);
});
//TODO: Slow this down??
_updateAll(view.getState());
ns.Log.debug("Object initialized.", "Engine");
}
function fitToBoundingBox(bbox, buffer) {
var bounds = buffer ? ns.GeoJson.buffer(bbox, buffer) : bbox;
view.fitToBoundingBox(bounds);
};
function getBoundingBox() {
return view.getState().bounds;
}
function getInitialBoundingBox() {
return schema.getInitialBoundingBox();
}
function updateLayer(layerKey) {
_update(layerManager.getLayer(layerKey), view.getState());
}
function refresh() {
_updateAll(view.getState());
}
function reset() {
view.fitToBoundingBox(schema.getInitialBoundingBox());
}
function zoomIn() {
view.zoomIn();
}
function zoomOut() {
view.zoomOut();
}
function setBackColor(color) {
view.setBackColor(color);
}
function getStateFilters(layerKey) {
var layer = layerManager.getLayer(layerKey);
var fb = factory.createFilterBuilder(layer, view.getState());
return fb.getStateFilters();
}
//---------------------------------------------------------
function _updateAll(state) {
layerManager.getLayers().forEach(function (layer) {
_update(layer, state);
})
}
function _update(layer, state) {
if (layer.getType() != "VectorLayer" || !layer.isVisible())
return;
var layerKey = layer.getKey();
var fe = layer.getFeatureEngine();
var fb = factory.createFilterBuilder(layer, state);
var filters = fb.getRequestFilters();
fe.run(filters)
.then(function (data) {
var toDraw = new ns.DrawingEngine(layer).run(data, state);
view.drawLayer(layer, toDraw);
var labels = new ns.LabelEngine(layerManager, view).run();
view.drawLabels(labels);
me.fire("layer_changed", { key: layerKey, data: data });
})
}
function _updateLabels() {
var labels = new ns.LabelEngine(layerManager, view).run();
view.drawLabels(labels);
}
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.Factory = Factory;
return ns;
//---------------------------------------------------------
function Factory(elementId, mapKey, param1, param2) {
var engine, view, mouseEngine, toolbar, schema, sources, layerManager;
var params, settings, api;
var schemaJson;
this.start = start;
this.getEngine = getEngine;
this.getView = getView;
this.getMouseEngine = getMouseEngine;
this.getToolbar = getToolbar;
this.getControls = getControls;
this.getSchema = getSchema;
this.getSources = getSources;
this.getApi = getApi;
this.getLayerManager = getLayerManager;
this.createFilterBuilder = createFilterBuilder;
this.createQueryEngine = createQueryEngine;
this.createSnapshot = createSnapshot;
init();
//---------------------------------------------------------
function init() {
params = _getParams(param1, param2);
settings = ns.Util.deepMerge(_defaults(), params.options);
api = _createApi(settings);
ns.Log.debugEnabled = settings.debug;
ns.Log.debug("Object initialized.", "Factory");
}
function start() {
var me = this;
return new Promise(function (resolve, reject) {
var calls = [
_loadSchema(mapKey),
_loadSources()
];
Promise.all(calls)
.then(function (data) {
schema = data[0];
sources = data[1];
layerManager = new ns.LayerManager(api, schema, sources);
view = new ns.Leaflet.View(elementId, settings);
mouseEngine = new ns.MouseEngine(view);
engine = new ns.Engine(me);
toolbar = new ns.Toolbar(engine, mouseEngine, view, settings.toolbar.layout);
toolbar.apply();
resolve(function () {
if (params.callback)
params.callback();
});
})
})
}
function getEngine() {
return engine;
}
function getView() {
return view;
}
function getMouseEngine() {
return mouseEngine;
}
function getToolbar() {
return toolbar;
}
function getControls() {
return ns.Util.clone(settings.controls);
}
function getSchema() {
return schema;
}
function getSources() {
return sources;
}
function getApi() {
return api;
}
function getLayerManager() {
return layerManager;
}
function createFilterBuilder(layer, state) {
return new ns.FilterBuilder(layer, state, {
thinToNearestXPixels: settings.thinToNearestXPixels
});
}
function createQueryEngine() {
return new ns.QueryEngine(api);
}
function createSnapshot() {
var vstate = view.getState();
// Size
var pb = vstate.pixelBounds;
var width = Math.abs(pb[2] - pb[0]);
var height = Math.abs(pb[3] - pb[1]);
var size = { width: width, height: height };
// Map
var map = {};
map.backColor = schema.getBackColor();
var bounds = vstate.bounds;
map.startExtent = { minX: bounds[0], minY: bounds[1], maxX: bounds[2], maxY: bounds[3] };
map.displaySRID = "GOOGLE";
var layers = layerManager.getLayers();
map.layers = [];
layers.forEach(layer => {
if (layer.isVisible()) {
var json = layer.toJSON();
if (layer.getType() == "VectorLayer") {
var fb = createFilterBuilder(layer, vstate);
json.filters = fb.getRequestFilters(true).filters;
}
map.layers.push(json);
}
});
return {
map: map,
size: size
};
}
//---------------------------------------------------------
function _createApi(settings) {
var path;
var l = window.location;
if (settings.server)
path = settings.server;
else
path = l.protocol + "//" + l.host + "/" + settings.apiRoot + "/";
return new ns.Api(path, settings.isCompact);
}
function _loadSchema(mapKey) {
if (ns.Util.isString(mapKey)) {
return new Promise(function (resolve, reject) {
api.getMap(mapKey)
.success(function (data, xhr) {
schemaJson = data;
resolve(new ns.Schema(data));
})
});
}
else {
return new Promise(function (resolve, reject) {
resolve(new ns.Schema(mapKey));
});
}
}
function _loadSources() {
return new Promise(function (resolve, reject) {
api.getSources()
.success(function (data, xhr) {
resolve(new ns.Sources(data));
})
});
}
function _getParams(param1, param2) {
var callback;
var options;
if (Mapzania.Util.isFunction(param1) && param2 != null)
throw "Map:Invalid instantation parameters";
if (Mapzania.Util.isFunction(param1)) {
callback = param1;
}
else {
options = param1;
if (param2 !== undefined)
callback = param2;
}
return {
callback: callback,
options: options || {}
}
}
function _defaults() {
return {
displaySrid: "GOOGLE",
apiRoot: "mz",
isCompact: false,
debug: false,
renderer: "CANVAS",
thinToNearestXPixels: 2,
minZoom: 0, //[non-documented] PN**
maxZoom: 21, //[non-documented] PN**
toolbar: {
layout: ns.Toolbar.Layouts.Simple
},
controls: {
info: { show: false },
legend: { show: false, collapsed: false },
scale: { show: true, imperial: false }
}
};
}
//---------------------------------------------------------
ns.createQueryEngine = this.createQueryEngine;
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.FeatureEngine = FeatureEngine;
return ns;
//---------------------------------------------------------
function FeatureEngine(api, sourceKey, tag) {
var GJ = ns.GeoJson;
var localFeatures = GJ.empty();
var loadedFeatures = GJ.empty();
var hidden = {};
var request;
ns.Util.eventify(this, "FeatureEngine [" + tag + "]");
ns.Log.debug("Object created.[key=" + sourceKey + "]", "FeatureEngine");
//----------------------AJAX------------------------------
this.run = function (stack) {
this.cancel();
return new Promise(function (resolve, reject) {
request = api.getFeatures(sourceKey, stack.filters);
request.success(function (data, xhr) {
if (stack.requiresAppending)
data.features = data.features.concat(localFeatures.features);
loadedFeatures = data;
request = null;
for (var i = data.features.length - 1; i >= 0; i--) {
var id = GJ.getId(data.features[i]);
if (id && hidden[id])
data.features.splice(i, 1);
}
resolve(data);
})
});
}
this.cancel = function () {
if (request) {
request.abort();
request = null;
}
}
//--------------------FEATURES----------------------------
this.getLocalFeatureCollection = function () {
return localFeatures;
}
this.addLocalFeatureCollection = function (featureCollection) {
GJ.heal(featureCollection);
localFeatures = featureCollection;
}
this.clearLocalFeatures = function () {
localFeatures = GJ.empty();
}
this.getLoadedFeatureCollection = function () {
return loadedFeatures;
}
this.getFeatureCollection = function () {
return GJ.merge(GJ.merge(GJ.empty(), loadedFeatures), localFeatures);
}
this.hideFeature = function (id) {
hidden[id] = true;
}
this.showFeature = function (id) {
delete hidden[id];
}
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.LayerManager = LayerManager;
return ns;
//---------------------------------------------------------
function LayerManager(api, schema, sources) {
var me = this;
var vlayers = [];
var rlayers = [];
this.getLayers = getLayers;
this.getLayer = getLayer;
this.showLayer = showLayer;
this.hideLayer = hideLayer;
this.addLayer = addLayer
this.removeLayer = removeLayer;
this.sendLayerBackwards = sendLayerBackwards;
this.bringLayerForwards = bringLayerForwards;
this.replaceLayer = replaceLayer;
this.getVectorLayers = getVectorLayers;
this.getRasterLayers = getRasterLayers;
init();
//---------------------------------------------------------
function init() {
ns.Util.eventify(me, "LayerManager");
var layers = schema.getLayers();
for (var i = 0; i < layers.length; i++) {
var layer = layers[layers.length - 1 - i];
addLayer(layer.key, layer);
}
ns.Log.debug("Object created.", "LayerManager");
}
function getLayers() {
return [].concat([].concat(vlayers), rlayers);
}
function getLayer(layerKey) {
return getLayers().find(function (m) {
return m.getKey() == layerKey;
})
}
function showLayer(layerKey) {
var layer = getLayer(layerKey);
layer.show();
me.fire("layer_shown", layer);
}
function hideLayer(layerKey) {
var layer = getLayer(layerKey);
layer.hide();
me.fire("layer_hidden", layer);
}
function addLayer(layerKey, layerJson, index) {
var layer;
if (layerJson) {
var source = sources.getSource(layerJson.sourceKey);
if (layerJson.type == "RasterLayer") {
layer = new ns.RasterLayer(layerJson, source);
if (ns.Util.isUndefined(index))
index = 0;
rlayers.splice(index, 0, layer);
} else if (layerJson.type == "VectorLayer") {
var themer = new ns.LayerThemer();
schema.getThemes(layerJson.key).forEach(function (themeJson) {
themer.addThemeJson(themeJson);
});
var featureEngine = new ns.FeatureEngine(api, source.key);
layer = new ns.VectorLayer(layerJson, featureEngine, themer, source.attribution);
if (ns.Util.isUndefined(index))
index = 0;
vlayers.splice(index, 0, layer);
}
}
else {
var defaults = {
key: layerKey,
sourceKey: layerKey + "_SRC",
filter: null,
fields: [],
visible: true
};
var json = Object.assign(defaults, layerJson);
var themer = new ns.LayerThemer();
var featureEngine = new ns.FeatureEngine(api, json.sourceKey);
var attribution = sources.hasSource(json.sourceKey) ? sources.getSource(json.sourceKey).attribution : "";
layer = new ns.VectorLayer(json, featureEngine, themer, attribution);
if (ns.Util.isUndefined(index))
index = 0;
vlayers.splice(index, 0, layer);
}
me.fire("layer_added", { layer: layer, index: index });
}
function removeLayer(layerKey) {
var layer = getLayer(layerKey);
var layers = layer.getType() == "RasterLayer" ? rlayers : vlayers;
var idx = layers.indexOf(layer);
layers.splice(idx, 1);
me.fire("layer_removed", layer);
}
function sendLayerBackwards(layerKey) {
var layer = getLayer(layerKey);
var layers = layer.getType() == "RasterLayer" ? rlayers : vlayers;
var idx = layers.indexOf(layer);
var tmp = layers[idx + 1];
layers[idx + 1] = layer;
layers[idx] = tmp;
me.fire("layer_sent_backwards", layer);
}
function bringLayerForwards(layerKey) {
var layer = getLayer(layerKey);
var layers = layer.getType() == "RasterLayer" ? rlayers : vlayers;
var idx = layers.indexOf(layer);
var tmp = layers[idx - 1];
layers[idx - 1] = layer;
layers[idx] = tmp;
me.fire("layer_brought_forwards", layer);
}
function replaceLayer(layerKey, layerJson) {
var layer;
if (layerJson.type == "RasterLayer") {
var source = sources.getSource(layerJson.sourceKey);
layer = new ns.RasterLayer(layerJson, source);
var existing = rlayers.find(m => m.getKey() == layerKey);
var idx = rlayers.indexOf(existing);
rlayers[idx] = layer;
}
if (layerJson.type == "VectorLayer") {
var themer = new ns.LayerThemer();
var featureEngine = new ns.FeatureEngine(api, layerJson.sourceKey);
var sourceJson = sources.getSource(layerJson.sourceKey);
layer = new ns.VectorLayer(layerJson, featureEngine, themer, sourceJson.attribution);
var existing = vlayers.find(m => m.getKey() == layerKey);
var idx = vlayers.indexOf(existing);
vlayers[idx] = layer;
}
me.fire("layer_replaced", { key: layerKey, layer: layer });
}
function getVectorLayers() {
return vlayers;
}
function getRasterLayers() {
return rlayers;
}
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.MouseModes = {
Pan: 1,
Query: 2,
DrawPoint: 3,
DrawLine: 4,
DrawPolygon: 5
};
ns.MouseEngine = MouseEngine;
return ns;
//---------------------------------------------------------
function MouseEngine(view) {
var GJ = ns.GeoJson;
var me = this;
ns.Util.eventify(this, "MouseEngine");
var mode = ns.MouseModes.Pan;
var drawn;
view.on("clicked", function (e) {
switch (mode) {
case ns.MouseModes.DrawPoint:
me.fire("drawing_done", e.position);
drawn = e.position;
view.drawSelector(drawn);
break;
case ns.MouseModes.DrawLine:
drawn = drawn || GJ.createLineString([]);
GJ.appendPointToLineString(drawn, e.position);
view.drawSelector(drawn);
break;
case ns.MouseModes.DrawPolygon:
drawn = drawn || GJ.createPolygon([]);
GJ.appendPointToPolygon(drawn, e.position);
view.drawSelector(drawn);
break;
}
})
view.on("double_clicked", function (e) {
switch (mode) {
case ns.MouseModes.DrawPoint:
break;
case ns.MouseModes.DrawLine:
me.fire("drawing_done", drawn);
drawn = null;
break;
case ns.MouseModes.DrawPolygon:
GJ.heal(drawn);
me.fire("drawing_done", drawn);
drawn = null;
break;
}
});
ns.Log.debug("Object created.", "MouseEngine");
//-----------------------------------------------------
this.setMode = function (val) {
mode = val;
drawn = null;
view.drawSelector(null);
view.setMouseMode(val);
this.fire("mouse_mode_set", mode);
}
this.getMode = function () {
return mode;
}
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.Schema = Schema;
return ns;
//---------------------------------------------------------
function Schema(json) {
this.getBackColor = getBackColor;
this.getInitialBoundingBox = getInitialBoundingBox;
this.getLayers = getLayers;
this.getLayer = getLayer;
this.getThemes = getThemes;
ns.Log.debug("Object created.", "Schema", json);
//-----------------------------------------------------
function getBackColor() {
return json.backColor;
}
function getInitialBoundingBox () {
var ext = json.startExtent;
return [ext.minX, ext.minY, ext.maxX, ext.maxY];
}
function getLayers () {
return json.layers;
}
function getLayer (layerKey) {
var lyr;
json.layers.forEach(function (item) {
if (item.key == layerKey)
lyr = item;
})
if (!lyr)
ns.Util.LogAndThrow("No layer exists for key=" + layerKey, "Schema.getLayer()");
return lyr;
}
function getThemes (layerKey) {
var lyr = getLayer(layerKey);
var themes = lyr.themes;
if (!themes)
ns.Util.LogAndThrow("No themes exist for layerKey=" + layerKey, "Schema.getThemes()");
return themes;
}
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.Sources = Sources;
return ns;
//---------------------------------------------------------
function Sources(json) {
var sources = {};
for (var i = 0; i < json.length; i++) {
var def = json[i];
sources[def.key] = def;
}
ns.Log.debug("Object created.", "Sources");
//-----------------------------------------------------
this.getSource = function (sourceKey) {
if (!sources[sourceKey])
ns.Util.logAndThrow("Unknown layer-source key=" + sourceKey, "Sources.getSource()");
return sources[sourceKey];
}
this.hasSource = function (sourceKey) {
return !ns.Util.isNullOrUndefined(sources[sourceKey]);
}
}
})(Mapzania || {})
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.Toolbar = Toolbar;
ns.Toolbar.Layouts = {
Simple: ["ZoomIn", "ZoomOut", "reset"],
Standard: ["ZoomIn", "ZoomOut", "Reset", "Pan", "DrawPoint", "DrawLine", "DrawPolygon"]
}
return ns;
//---------------------------------------------------------
function Toolbar(engine, mouseEngine, view, layout) {
var buttons = [];
for (var i = 0; i < layout.length; i++) {
var button = getStandardButton(layout[i]);
if (button)
buttons.push(button);
}
//-----------------------------------------------------
this.apply = function () {
for (var i = 0; i < buttons.length; i++) {
view.Toolbar.addButton(buttons[i]);
}
}
this.addStandardButton = function (key) {
var button = getStandardButton(key);
if (button)
view.Toolbar.addButton(button);
}
//-----------------------------------------------------
function getStandardButton(key) {
var images64 = {
pan: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AUdCBEo2HxrQgAAAQBJREFUOMvN0r8uRFEQBvDfZbPxJxFWQmi8A6LTi0JJKWr2AUShlii9gdB5AoVqex5gE41CR0Fkc+Nq5srJzb27qzPJycw5M/PNd2aGZpnBgj/KdpwWrtHHFnbQqUvIEnsXe/jGGm5wiwJX+MI5PiOvqII9hZ4P50HcP0I/hL5Pi08kABtB+Q2nmK2wfA12J/G9Qvy1DMqxkgSXiXnoDpYwieWyaitYdHGGaQzQToDnwn6OqnmA/MoqemFfBMCwZndxnDqncInNuB+OGHVRA6qNOywOScwqANIpDGJ82YjK700x5eNL08ZFw/vGoNjDeo3/MfqVjQNyVOPbT5brH8kPs38sh1QAZOYAAAAASUVORK5CYII=",
reset: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAsJJREFUeNp0UktIVGEUPve/j7l37h2aCSQRzEU46jg5D3QWBUnaWGKEWTmjNYobF4EERYWYD8bMVUW7XEVGtWsduIloZWoINRkR0oCLWaRCNa/76vzXuRdb+F/O/V/nfN85/3eY2tpaOGgwhAFCyKJpmNcNw/iz/y6bzVozMeHgj+d4kGU5JSvyZ5Zj22mAfWcPYq1tw8ESNiYIwhtJlH673W7T4/EAWp2iKO94gX/IMIywLx440zTtdAVknJLc0rjL5SIIAhzHAc/ze8AsS/c383/zXcViMYFHGQcA6wRRFJ9KkjQiu2VAJisA2RwmCkj3oXCo7kr/ZY+TgfXjuA5MeUSRFeB4DsKRMCQHEuBv8EPfhUtAWKwUiZIDSUgOJt5jyIYDQFFrampmy2rZcmxqaoSpmcm3eDd96kT7suJRTN9hH9y6fQui0ch0WySWLpfLsLW1VQFAqVRdbaVlqKoKvX29q23RWHepVLLSDgQDMJOe2a2uPtIfaYkuaaoG9rvZGbDFQlHA+i0An893p1Qsga7roBENHj959AnveluaQ1l6tl8BS8a19VVAiQAbBTRNgwdz8znqSFkoIAafDDYez+qaLiHZKGY6inPCAQgFw3q9v16lwRRkc3Nz1moVBDB0A5rqAwV6jg11V3SJC6IkLqD/mANA2c51n12jM33QQr5wEVVZAAYOVWoVUNIJZL6HPULlhrEbY/n/AOJd8ckz8U5Hb5R0FJtpF9c/BZdQQtb72Bss7Y2e8z3Q0Xk67TwiTbO5Ibi0ur6yWFVVNfTq5WvAIMDep2UcpVnRQGpXrw1Cajj1DP0/5HK5vQ72+rxAGALffmwIuJ/KfMmMLz5/QVY+rgDVm2bU2tYKQ8MpI9AcmEeftP9YQ3n713YFwOvdW1SYvn7PxHA7gRZHk9AKaEtoc/igy7ZCOzs7Vtw/AQYASsoRySkHkqIAAAAASUVORK5CYII=",
zoomIn: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3QcMByAZbiJcHgAAAQNJREFUOMud078uREEUx/GPP8k+wKJGY60otlFqSPYFKERIPIcKhReQKIiHoFUohNafhE2EcBsSCsUW4t9VOJIbce/G/SUnZ+bMnO+cyZzhW7N4VELd4RM8lAF0oY1bDOIi4hP/gcxhAVdohFWxhhu8Yh9N9ORBxvAR40m8IEULZ7iP+R4qRdVUI/kaS5n4EHYCslEEWMc75nPWDwIyngdIouw8TQdg9fcz/mgAbwWAJHx/HuAQffGkf2km/HHeCc0ocTt6JKsGnjpcUS92A3KEKQxjGc8Rb6NeBKlgMzZnrRXJn7jDaKcOrWMFW1iM2EgkpzhHrcz/qUV3pjhRUjWc4vILWns/DB0mlrQAAAAASUVORK5CYII=",
zoomOut: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3QcMByA1XPow/QAAAO1JREFUOMvN0z9KQ0EQx/GPfyAHiFprGl8CKbyAjUIuYCcInsNKLbyAkELJIbS1sBAFK00E0yiYJo2FRQpR8dmMEMR9kVc5MAw7O7/vzrKz/Be7wwjX4aVtJbyKfTziDWdoYeYvkFW8IkcfXQxjfYpKkbga4gdsj+WX0AnIYRHgAB/YTOyfB6SZAgyi7ZStB2DvOzH9o2AB7wWAQcT5FOACc1hMADYiXqVOaEWLx5j65YmfJ1zRLE4Ccok11LCDl8iP0CiCVNCO4nHvh/gTT6hPGqgGdnGErcgthzhHD1mZcc9iOnPclP0zGW5x/wUrDzmigt2kAgAAAABJRU5ErkJggg==",
drawPoint: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAALVWlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNC4yLjItYzA2MyA1My4zNTI2MjQsIDIwMDgvMDcvMzAtMTg6MTI6MTggICAgICAgICI+CiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICB4bWxuczpwaG90b3Nob3A9Imh0dHA6Ly9ucy5hZG9iZS5jb20vcGhvdG9zaG9wLzEuMC8iCiAgICB4bWxuczpJcHRjNHhtcENvcmU9Imh0dHA6Ly9pcHRjLm9yZy9zdGQvSXB0YzR4bXBDb3JlLzEuMC94bWxucy8iCiAgICB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iCiAgICB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIKICAgIHhtbG5zOnN0RXZ0PSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VFdmVudCMiCiAgICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgICB4bWxuczp4bXBSaWdodHM9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9yaWdodHMvIgogICBwaG90b3Nob3A6QXV0aG9yc1Bvc2l0aW9uPSJBcnQgRGlyZWN0b3IiCiAgIHBob3Rvc2hvcDpDcmVkaXQ9Ind3dy5nZW50bGVmYWNlLmNvbSIKICAgcGhvdG9zaG9wOkRhdGVDcmVhdGVkPSIyMDEwLTAxLTAxIgogICBJcHRjNHhtcENvcmU6SW50ZWxsZWN0dWFsR2VucmU9InBpY3RvZ3JhbSIKICAgeG1wOk1ldGFkYXRhRGF0ZT0iMjAxMC0wMS0wM1QyMTozMzoxNCswMTowMCIKICAgeG1wTU06T3JpZ2luYWxEb2N1bWVudElEPSJ4bXAuZGlkOjI3NUZGRjNDODFGN0RFMTE5RUFCOTBENzA3OEFGOTRBIgogICB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjI3NUZGRjNDODFGN0RFMTE5RUFCOTBENzA3OEFGOTRBIgogICB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjVFODI0QzM3QTdGOERFMTE4MjFDRTRCMkM3RTM2RDcwIj4KICAgPElwdGM0eG1wQ29yZTpDcmVhdG9yQ29udGFjdEluZm8KICAgIElwdGM0eG1wQ29yZTpDaUFkckNpdHk9IlByYWd1ZSIKICAgIElwdGM0eG1wQ29yZTpDaUFkclBjb2RlPSIxNjAwMCIKICAgIElwdGM0eG1wQ29yZTpDaUFkckN0cnk9IkN6ZWNoIFJlcHVibGljIgogICAgSXB0YzR4bXBDb3JlOkNpRW1haWxXb3JrPSJrYUBnZW50bGVmYWNlLmNvbSIKICAgIElwdGM0eG1wQ29yZTpDaVVybFdvcms9Ind3dy5nZW50bGVmYWNlLmNvbSIvPgogICA8eG1wTU06SGlzdG9yeT4KICAgIDxyZGY6U2VxPgogICAgIDxyZGY6bGkKICAgICAgc3RFdnQ6YWN0aW9uPSJzYXZlZCIKICAgICAgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDoyNzVGRkYzQzgxRjdERTExOUVBQjkwRDcwNzhBRjk0QSIKICAgICAgc3RFdnQ6d2hlbj0iMjAxMC0wMS0wMlQxMDoyODo1MSswMTowMCIKICAgICAgc3RFdnQ6Y2hhbmdlZD0iL21ldGFkYXRhIi8+CiAgICAgPHJkZjpsaQogICAgICBzdEV2dDphY3Rpb249InNhdmVkIgogICAgICBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOkQzMjgxQTAzREJGN0RFMTFBOTAwODNFMEExMjUzQkZEIgogICAgICBzdEV2dDp3aGVuPSIyMDEwLTAxLTAyVDIxOjExOjI5KzAxOjAwIgogICAgICBzdEV2dDpjaGFuZ2VkPSIvbWV0YWRhdGEiLz4KICAgICA8cmRmOmxpCiAgICAgIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiCiAgICAgIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6NUU4MjRDMzdBN0Y4REUxMTgyMUNFNEIyQzdFMzZENzAiCiAgICAgIHN0RXZ0OndoZW49IjIwMTAtMDEtMDNUMjE6MzM6MTQrMDE6MDAiCiAgICAgIHN0RXZ0OmNoYW5nZWQ9Ii9tZXRhZGF0YSIvPgogICAgPC9yZGY6U2VxPgogICA8L3htcE1NOkhpc3Rvcnk+CiAgIDxkYzp0aXRsZT4KICAgIDxyZGY6QWx0PgogICAgIDxyZGY6bGkgeG1sOmxhbmc9IngtZGVmYXVsdCI+Z2VudGxlZmFjZS5jb20gZnJlZSBpY29uIHNldDwvcmRmOmxpPgogICAgPC9yZGY6QWx0PgogICA8L2RjOnRpdGxlPgogICA8ZGM6c3ViamVjdD4KICAgIDxyZGY6QmFnPgogICAgIDxyZGY6bGk+aWNvbjwvcmRmOmxpPgogICAgIDxyZGY6bGk+cGljdG9ncmFtPC9yZGY6bGk+CiAgICA8L3JkZjpCYWc+CiAgIDwvZGM6c3ViamVjdD4KICAgPGRjOmRlc2NyaXB0aW9uPgogICAgPHJkZjpBbHQ+CiAgICAgPHJkZjpsaSB4bWw6bGFuZz0ieC1kZWZhdWx0Ij5UaGlzIGlzIHRoZSBpY29uIGZyb20gR2VudGxlZmFjZS5jb20gZnJlZSBpY29ucyBzZXQuIDwvcmRmOmxpPgogICAgPC9yZGY6QWx0PgogICA8L2RjOmRlc2NyaXB0aW9uPgogICA8ZGM6Y3JlYXRvcj4KICAgIDxyZGY6U2VxPgogICAgIDxyZGY6bGk+QWxleGFuZGVyIEtpc2VsZXY8L3JkZjpsaT4KICAgIDwvcmRmOlNlcT4KICAgPC9kYzpjcmVhdG9yPgogICA8ZGM6cmlnaHRzPgogICAgPHJkZjpBbHQ+CiAgICAgPHJkZjpsaSB4bWw6bGFuZz0ieC1kZWZhdWx0Ij5DcmVhdGl2ZSBDb21tb25zIEF0dHJpYnV0aW9uIE5vbi1Db21tZXJjaWFsIE5vIERlcml2YXRpdmVzPC9yZGY6bGk+CiAgICA8L3JkZjpBbHQ+CiAgIDwvZGM6cmlnaHRzPgogICA8eG1wUmlnaHRzOlVzYWdlVGVybXM+CiAgICA8cmRmOkFsdD4KICAgICA8cmRmOmxpIHhtbDpsYW5nPSJ4LWRlZmF1bHQiPkNyZWF0aXZlIENvbW1vbnMgQXR0cmlidXRpb24gTm9uLUNvbW1lcmNpYWwgTm8gRGVyaXZhdGl2ZXM8L3JkZjpsaT4KICAgIDwvcmRmOkFsdD4KICAgPC94bXBSaWdodHM6VXNhZ2VUZXJtcz4KICA8L3JkZjpEZXNjcmlwdGlvbj4KIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+Cjw/eHBhY2tldCBlbmQ9InIiPz5bWF99AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAOlJREFUeNpiYEACRkZG/EDcz0ACYELm/P//n+Hfv38F+vr684k1gBFdQEdH5z+UueDKlSuJJLkABP7+/QvDCZqamvMpMQBsiKqq6nySDPjz5w8KBhmipKQ0n1wXwF0iJyc3nywXILtEWlp6PrkuAGNgFCtISkrqI6tnwWYAFjDh9evXhaR64QEQf4CyA0gNxAvAVGkApCdA+Qq8vLz2RCVNbm7u+Tw8PPxQtjwQ/wdhLi6u/QzkAHZ29vlA/B+E2djY5Ek2gJWVVZ+FheU/FNejyzMTMgAYdS+B4SEAxC+AuAMo9BFZHiDAAJ7Ov8IjdSagAAAAAElFTkSuQmCC",
drawLine: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gMNDBE6zeV2NAAAACFJREFUOMtjYBgFgwf8h2KS1bNgkSAJoBvASIILRsHwAQCzZgYEcc0fWAAAAABJRU5ErkJggg==",
drawPolygon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsSAAALEgHS3X78AAAAB3RJTUUH4AUdCBYskFA5nAAAAR1JREFUOMud088rxEEYBvDP/nCSKBvlRw5brnKSlIuUnJaLg+TmL1DyF7hIuePgSjm4aA8uu+TkP9Bq5bJyUdriwMGrvq3dxT41zTsz7zzzvM/M8IU0sjpAOvo8NjGqQ4yghBsstMmbwWpyIpWIJ3GGHC5RDsIa+lGIzVXM4q3ZCSUs4QAfeMF7xK94wHK7Uq4wEfE+dhJrOTy1MhEG46Q6hlHEXBD2YAp3jQTZhBdrQbKNbvQF0V7UncNjM4IBHIXDRVygggy2cBiqFsO8H8gnpNejdvEmTjEW45UwdaORIBVKMpgPmVVM4xzrMVeOVsdxXG1LXIeqCm7DzG8MYRfj7QiyQVBr2PyvP/KMk79+pma+3MfT7hi96Pot6RObiTqWSxKYQgAAAABJRU5ErkJggg=="
};
var standardButtons = {
Pan: {
key: "Pan",
title: "Pan",
html: "",
fn: function () {
mouseEngine.setMode(ns.MouseModes.Pan);
}
},
Reset: {
key: "Reset",
title: "Reset",
html: "",
fn: function () {
mouseEngine.setMode(ns.MouseModes.Pan);
engine.reset();
}
},
ZoomIn: {
key: "ZoomIn",
title: "Zoom In",
html: "",
fn: function () {
//mouseEngine.setMode(ns.MouseModes.Pan);
engine.zoomIn();
}
},
ZoomOut: {
key: "ZoomOut",
title: "Zoom Out",
html: "",
fn: function () {
//mouseEngine.setMode(ns.MouseModes.Pan);
engine.zoomOut();
}
},
DrawPoint: {
key: "DrawPoint",
title: "Draw Point",
html: "",
fn: function () {
mouseEngine.setMode(ns.MouseModes.DrawPoint);
}
},
DrawLine: {
key: "DrawLine",
title: "Draw Line",
html: "",
fn: function () {
mouseEngine.setMode(ns.MouseModes.DrawLine);
}
},
DrawPolygon: {
key: "DrawPolygon",
title: "Draw Polygon",
html: "",
fn: function () {
mouseEngine.setMode(ns.MouseModes.DrawPolygon);
}
},
};
return standardButtons[key];
}
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.FilterBuilder = FilterBuilder;
return ns;
//---------------------------------------------------------
function FilterBuilder(layer, state, options) {
this.getRequestFilters = function (alwaysIncludeLocalFeatures) {
return _buildFilterStack(layer.getFilters(), alwaysIncludeLocalFeatures);
}
this.getStateFilters = function () {
return _buildFilterStack();
}
this.getResponseFilters = function (layer) {
var filters = [];
//_addLocalFeatures
if (layer.clientFeatures
&& layer.clientFeatures.features
&& layer.clientFeatures.features.length > 0
&& layer.requestFilters.length === 0) {
filters.push(function (features) {
var res = Mapzania.GeoJson.fromFeatureCollection(layer.clientFeatures);
Mapzania.Projection.projectFeatureArray(res, "LATLONG", "GOOGLE");
//TODO: Replace based on ids
[].push.apply(features, res);
});
}
//removeHidden
filters.push(function (features) {
for (var i = features.length - 1; i >= 0; i--) {
if (layer.hidden.indexOf(features[i].id) > -1)
features.splice(i, 1);
}
});
//filters.push(function (features) {
// for (var i = features.length - 1; i >= 0; i--) {
// if (layer.hidden.indexOf(features[i].id) > -1)
// features.splice(i, 1);
// }
//});
//add custom
for (var i = 0; i < layer.responseFilters.length; i++) {
filters.push(layer.requestFilters[i]);
}
return filters;
}
//---------------------------------------------------------
function _buildFilterStack(userFilters, alwaysIncludeLocalFeatures) {
var filters = [];
var requiresAppending = true;
_addLocalFeatures(filters, alwaysIncludeLocalFeatures);
if (filters.length > 0)
requiresAppending = false;
_addFilterByText(filters);
_addFilterByBoundingBox(filters);
_addChangeProperties(layer, filters);
_addLabelVisibilityClause(filters);
if (userFilters)
filters = filters.concat(userFilters);
//TODO: ChangePrecision
if (!layer.tiled)
_addSimplifyGeometry(filters);
return {
filters: filters,
requiresAppending: requiresAppending
}
}
function _addLocalFeatures(filters, alwaysIncludeLocalFeatures) {
var featureCollection = layer.getFeatureEngine().getLocalFeatureCollection();
if (alwaysIncludeLocalFeatures ||
(featureCollection.features.length > 0 &&
layer.getFilters().length !== 0
)
)
filters.push({ type: "AddFeatureCollection", features: featureCollection })
}
function _addFilterByText(filters) {
var layerText = layer.getFilterText();
var themer = layer.getThemer();
var themeText = themer.getFilterText(state.zoom);
if (layerText && themeText)
text = "(" + themeText + ") AND (" + layerText + ")";
else
if (themeText)
text = themeText;
else
text = layerText;
if (text) {
var filter = ns.Filters.filterByText(text, false);
filters.push(filter);
}
}
function _addFilterByBoundingBox(filters) {
var filter = ns.Filters.filterByBoundingBox(state.bounds);
filters.push(filter);
}
function _addChangeProperties(layer, filters) {
var fields = [];
var layerFields = layer.getFields();
if (layerFields)
layerFields.forEach(function (cur) {
if (!cur.expression)
fields.push(cur.key);
});
var fieldsStr = null;
if (fields.length > 0)
fieldsStr = fields.join(",");
if (fieldsStr)
filters.push(ns.Filters.changeProperties(fieldsStr));
}
function _addLabelVisibilityClause(filters) {
//TODO:labelVisibilityClause
}
function _addSimplifyGeometry(filters) {
var bb = state.bounds;
var pb = state.pixelBounds;
var pW = Math.abs(pb[3] - pb[1])
var pH = Math.abs(pb[2] - pb[0])
var bW = Math.abs(bb[3] - bb[1])
var bH = Math.abs(bb[2] - bb[0])
var thinX = bW / pW;
var thinY = bH / pH;
var thinFactor = options.thinToNearestXPixels * Math.min(thinX, thinY);
var filter = ns.Filters.simplifyGeometry(thinFactor);
filters.push(filter);
}
}
})(Mapzania || {})
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.Filters = {
bufferGeometry: bufferGeometry,
changeProperties: changeProperties,
clipByFeatureCollection: clipByFeatureCollection,
convertToCentroids: convertToCentroids,
filterByBoundingBox: filterByBoundingBox,
filterByFeatureCollection: filterByFeatureCollection,
filterByNearest: filterByNearest,
filterByText: filterByText,
//[non-documented]
addAreaProperty: addAreaProperty,
addLengthProperty: addLengthProperty,
aggregateByFeatures: aggregateByFeatures,
aggregateByLayer: aggregateByLayer,
aggregateLinesByOriginAndDestination: aggregateLinesByOriginAndDestination,
changeCoordinateSystem: changeCoordinateSystem,
changeGeometryAccuracy: changeGeometryAccuracy,
clusterPoints: clusterPoints,
filterByLayer: filterByLayer,
simplifyGeometry: simplifyGeometry,
splitLineByFeatures: splitLineByFeatures,
splitLineByLayer: splitLineByLayer
};
return ns;
//---------------------------------------------------------
function bufferGeometry(factor, side, joins, ends, mitreLimit, srid) {
return {
type: "BufferGeometry",
factor: factor,
side: side,
joins: joins,
ends: ends,
mitreLimt: mitreLimit,
srid: srid
};
}
function changeProperties(properties) {
//http://stackoverflow.com/questions/26195975/regex-to-match-only-commas-but-not-inside-multiple-parentheses
var props = properties;
if (typeof (properties) == "string")
props = properties.split(/,(?![^()]*(?:\([^()]*\))?\))/);
return {
type: "ChangeProperties",
properties: props
};
};
function clipByFeatureCollection(features) {
return {
type: "ClipByFeatureCollection",
features: features
};
};
function convertToCentroids() {
return {
type: "ConvertToCentroids"
};
}
function filterByBoundingBox(bbox) {
return {
type: "FilterByBoundingBox",
minX: bbox[0],
minY: bbox[1],
maxX: bbox[2],
maxY: bbox[3]
};
};
function filterByFeatureCollection(features, operation) {
return {
type: "FilterByFeatureCollection",
features: features,
operation: operation || "intersects"
};
};
function filterByNearest(point, take, includeDistance) {
var n = 1;
if (take)
n = take;
return {
type: "FilterByNearest",
x: point.coordinates[0],
y: point.coordinates[1],
take: n,
includeDistance: includeDistance
};
};
function filterByText(statement, passthru) {
if (!passthru)
passthru = false;
return {
type: "FilterByText",
statement: statement,
passthru: passthru
};
};
//[non-documented]
function filterByLayer(sourceKey, layerFilters, operation) {
var filters = [];
if (layerFilters)
filters = layerFilters;
return {
type: "FilterByLayer",
sourceKey: sourceKey,
operation: operation || "intersects",
filters: filters
};
}
//[non-documented]
function changeCoordinateSystem(srid) {
return {
type: "ChangeCoordinateSystem",
srid: srid
};
};
//[non-documented]
function changeGeometryAccuracy(figures) {
return {
type: "ChangeGeometryAccuracy",
figures: figures
};
};
//[non-documented]
function simplifyGeometry(factor) {
return {
type: "SimplifyGeometry",
factor: factor
};
};
//[non-documented]
function addAreaProperty() {
return {
type: "AddAreaProperty"
};
};
//[non-documented]
function addLengthProperty() {
return {
type: "AddLengthProperty"
};
};
//[non-documented]
function aggregateByFeatures(featuresCollection, aggregation) {
return {
type: "AggregateByPolygons",
features: featuresCollection,
aggregation: aggregation
};
}
//[non-documented]
function aggregateByLayer(layersource, aggregation) {
return {
type: "AggregateByPolygons",
layerSource: layersource,
aggregation: aggregation
};
}
//[non-documented]
function aggregateLinesByOriginAndDestination(gridSize, includeCount) {
if (!includeCount)
includeCount = true;
return {
type: "AggregateLinesByOriginAndDestination",
gridSize: gridSize,
includeCount: includeCount
};
}
//[non-documented]
function clusterPoints(factor, properties) {
if (typeof (properties) == "string")
properties = properties.split(/,(?![^()]*(?:\([^()]*\))?\))/);
return {
type: "ClusterPoints",
factor: factor,
properties: properties
};
}
//[non-documented]
function splitLineByFeatures(featureCollection, method) {
return {
type: "SplitLineByPolygons",
features: featureCollection,
method: method
};
}
//[non-documented]
function splitLineByLayer(layerSource, method) {
return {
type: "SplitLineByPolygons",
layerSource: layerSource,
method: method
};
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
var GJ = ns.GeoJson = ns.GeoJson || {};
GJ.buffer = buffer;
buffer.implemented = {
BoundingBox: doBoundingBox
};
return ns;
//---------------------------------------------------------
function buffer(geometry, ratio) {
var type = GJ.getType(geometry);
var func = buffer.implemented[type];
if (!func)
GJ.Exceptions.notImplemented(type, "buffer");
return func(geometry, ratio);
}
//---------------------------------------------------------
function doBoundingBox(geometry, ratio) {
var centroid = GJ.getCentroid(geometry);
var x = centroid.coordinates[0];
var y = centroid.coordinates[1];
var width = Math.abs(geometry[0] - geometry[2]);
var height = Math.abs(geometry[1] - geometry[3]);
var deltaX = (ratio * width) / 2;
var deltaY = (ratio * height) / 2;
return [x - deltaX, y - deltaY, x + deltaX, y + deltaY];
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
var GJ = ns.GeoJson = ns.GeoJson || {};
GJ.appendPointToLineString = appendPointToLineString;
GJ.appendPointToPolygon = appendPointToPolygon;
GJ.empty = empty;
GJ.createFeature = createFeature;
GJ.createFeatureCollection = createFeatureCollection;
GJ.createLineString = createLineString;
GJ.createMultiLineString = createMultiLineString;
GJ.createMultiPoint = createMultiPoint;
GJ.createMultiPolygon = createMultiPolygon;
GJ.createPoint = createPoint;
GJ.createPolygon = createPolygon;
GJ.getId = getId;
GJ.getType = getType;
GJ.isBoundingBox = isBoundingBox;
GJ.merge = merge;
GJ.Exceptions = {
doesNotApply: doesNotApply,
notImplemented: notImplemented,
};
return ns;
//---------------------------------------------------------
function appendPointToLineString(line, point) {
line.coordinates.push(point.coordinates);
}
function appendPointToPolygon(poly, point) {
if (poly.coordinates.length == 0)
poly.coordinates.push([]);
var shell = poly.coordinates[0];
//if (shell.length == 0) {
shell.push(point.coordinates);
//}
//else if (shell.length == 1) {
// shell.push(point.coordinates);
// shell.push(shell[0]);
//}
//else {
// var first = shell[0];
// var last = shell[shell.length - 1];
// if (first[0] != last[0] || first[1] != last[1])
// shell.push([].concat(first));
// shell.splice(shell.length - 2, 0, point.coordinates)
//}
}
function empty() {
return {
type: "FeatureCollection",
features: []
};
}
function createFeature(geometry, properties, id) {
var result = {
type: "Feature",
geometry: geometry,
properties: properties || {}
};
if (id)
result.id = id;
return result;
}
//source is either array of features or single feature;
function createFeatureCollection(source) {
return merge(source, empty());
}
function createLineString(coordinates) {
return {
type: "LineString",
coordinates: [].concat(coordinates)
}
}
function createMultiLineString(coordinates) {
return {
type: "MultiLineString",
coordinates: [].concat(coordinates)
}
}
function createMultiPoint(coordinates) {
return {
type: "MultiPoint",
coordinates: [].concat(coordinates)
}
}
function createMultiPolygon(coordinates) {
return {
type: "MultiPolygon",
coordinates: [].concat(coordinates)
}
}
function createPoint(param1, param2) {
var coords;
if (ns.Util.isArray(param1))
coords = [].concat(param1);
else
coords = [param1, param2]
return {
type: "Point",
coordinates: coords
}
}
function createPolygon(coordinates) {
if (!isBoundingBox(coordinates)) {
return {
type: "Polygon",
coordinates: [].concat(coordinates)
};
}
var minX = coordinates[0],
minY = coordinates[1],
maxX = coordinates[2],
maxY = coordinates[3];
var bottomLeft = [minX, minY];
var topLeft = [minX, maxY];
var topRight = [maxX, maxY];
var bottomRight = [maxX, minY];
var shell = [bottomLeft, topLeft, topRight, bottomRight, bottomLeft];
return {
type: "Polygon",
coordinates: [shell]
}
}
function getId(feature) {
return feature.id || feature.properties["id"] || feature.properties["Id"];
}
function getType(geometry) {
if (isBoundingBox(geometry))
return "BoundingBox";
return geometry.type;
}
function isBoundingBox(bbox) {
return bbox.length == 4 &&
ns.Util.isNumeric(bbox[0]) &&
ns.Util.isNumeric(bbox[1]) &&
ns.Util.isNumeric(bbox[2]) &&
ns.Util.isNumeric(bbox[3]);
}
function merge(source, destination) {
//Feature List
if (ns.Util.isArray(source))
destination.features.push(...source);
//Feature
else if (source.type == "Feature")
destination.features.push(source);
//FeatureCollection
else
ns.Util.arrayAppend(source.features, destination.features);
return destination;
}
//----------------------EXCEPTIONS--------------------------
function notImplemented(type, functionName) {
ns.Util.logAndThrow(
"Function (" + functionName + ") not yet implemented for type=" + type + ".",
"GeoJson." + functionName + "()"
);
}
function doesNotApply(type, functionName) {
ns.Util.logAndThrow(
"Function (" + functionName + ") does not apply to geometry type=" + type + ".",
"GeoJson." + functionName + "()"
);
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
var GJ = ns.GeoJson = ns.GeoJson || {};
GJ.crop = crop;
crop.implemented = {
LineString: doLineString,
MultiLineString: doMultiLineString
};
return ns;
//---------------------------------------------------------
function crop(geometry, boundary) {
var type = GJ.getType(geometry);
var func = crop.implemented[type];
if (!func)
GJ.Exceptions.notImplemented(type, "crop");
return func(geometry, boundary);
}
//---------------------------------------------------------
function doLineString(geometry, boundary) {
var coords = _cropCoords(geometry.coordinates, boundary);
if (coords.length == 0)
return null;
return {
type: "LineString",
coordinates: coords
};
}
function doMultiLineString(geometry, boundary) {
var lines = [];
geometry.coordinates.forEach(function (line) {
var coords = _cropCoords(line, boundary);
if (coords.length != 0)
lines.push(coords);
})
if (lines.length == 0)
return null;
return {
type: "MultiLineString",
coordinates: lines
};
}
//---------------------------------------------------------
function _cropCoords(coords, bbox) {
var result = [];
if (coords.length < 2)
return [];
for (var i = 1; i < coords.length; i++) {
var start = coords[i - 1];
var end = coords[i];
var startIsContained = GJ.isContainedBy(GJ.createPoint(start), bbox);
var endIsContained = GJ.isContainedBy(GJ.createPoint(end), bbox);
//Both points inside
if (startIsContained && endIsContained) {
result.push(start);
result.push(end);
continue;
}
// Both points outside
if (!startIsContained && !endIsContained) {
continue;
}
var minX = bbox[0], minY = bbox[1], maxX = bbox[2], maxY = bbox[3];
var bottomLeft = [minX, minY];
var topLeft = [minX, maxY];
var topRight = [maxX, maxY];
var bottomRight = [maxX, minY];
var xpoint = GJ.Math.segmentIntersection(start, end, bottomLeft, topLeft) ||
GJ.Math.segmentIntersection(start, end, topLeft, topRight) ||
GJ.Math.segmentIntersection(start, end, topRight, bottomRight) ||
GJ.Math.segmentIntersection(start, end, bottomRight, bottomLeft);
if (startIsContained) {
result.push(start);
result.push(xpoint);
}
else {
result.push(xpoint);
result.push(end);
}
}
return result;
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
var GJ = ns.GeoJson = ns.GeoJson || {};
GJ.explode = explode;
explode.implemented = {
Point: toPoint,
MultiPoint: toPoints,
LineString: toPoints,
MultiLineString: toLines,
Polygon: toLines,
MultiPolygon: toPolygons
};
return ns;
//---------------------------------------------------------
function explode(geometry) {
var type = GJ.getType(geometry);
var func = explode.implemented[type];
if (!func)
GJ.Exceptions.notImplemented(type, "explode");
return func(geometry);
}
//---------------------------------------------------------
function toPoint(geometry) {
return [ns.Util.assign({}, geometry)];
}
function toPoints(geometry) {
return geometry.coordinates.map(m => GJ.createPoint(m));
}
function toLines(geometry) {
return geometry.coordinates.map(m => GJ.createLineString(m));
}
function toPolygons(geometry) {
return geometry.coordinates.map(m => GJ.createPolygon(m));
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
var GJ = ns.GeoJson = ns.GeoJson || {};
GJ.getArea = getArea;
getArea.implemented = {
Point: zero,
MultiPoint: zero,
LineString: zero,
MultiLineString: zero,
Polygon: doPolygon,
MultiPolygon: doMultiPolygon,
GeometryCollection: doGeometryCollection
};
return ns;
//---------------------------------------------------------
function getArea(geometry) {
var type = GJ.getType(geometry);
var func = getArea.implemented[type];
if (!func)
GJ.Exceptions.notImplemented(type, "getArea");
return func(geometry);
}
//---------------------------------------------------------
function zero(geometry) {
return 0;
}
function doPolygon(geometry) {
//https://github.com/Turfjs/turf/tree/master/packages/turf-area
var coords = geometry.coordinates;
var area = 0;
if (coords && coords.length > 0) {
area += Math.abs(ringArea(coords[0]));
for (var i = 1; i < coords.length; i++) {
area -= Math.abs(ringArea(coords[i]));
}
}
return area;
function ringArea(coords) {
var RADIUS = 6378137;
var p1;
var p2;
var p3;
var lowerIndex;
var middleIndex;
var upperIndex;
var i;
var area = 0;
var coordsLength = coords.length;
function rad(_) {
return _ * Math.PI / 180;
}
if (coordsLength > 2) {
for (i = 0; i < coordsLength; i++) {
if (i === coordsLength - 2) { // i = N-2
lowerIndex = coordsLength - 2;
middleIndex = coordsLength - 1;
upperIndex = 0;
} else if (i === coordsLength - 1) { // i = N-1
lowerIndex = coordsLength - 1;
middleIndex = 0;
upperIndex = 1;
} else { // i = 0 to N-3
lowerIndex = i;
middleIndex = i + 1;
upperIndex = i + 2;
}
p1 = coords[lowerIndex];
p2 = coords[middleIndex];
p3 = coords[upperIndex];
area += (rad(p3[0]) - rad(p1[0])) * Math.sin(rad(p2[1]));
}
area = area * RADIUS * RADIUS / 2;
}
return area;
}
}
function doMultiPolygon(geometry) {
var area = 0;
for (i = 0; i < geometry.coordinates.length; i++) {
area += doPolygon({ coordinates: geometry.coordinates[i] });
}
return area;
}
function doGeometryCollection(geometry) {
var area = 0;
for (i = 0; i < geometry.geometries.length; i++) {
area += getArea(geometry.geometries[i]);
}
return area;
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
var GJ = ns.GeoJson = ns.GeoJson || {};
GJ.getBoundingBox = getBoundingBox;
getBoundingBox.implemented = {
BoundingBox:doBoundingBox,
Point: doPoint,
MultiPoint: doMultiPoint,
LineString: doLineString,
MultiLineString: doMultiLineString,
Polygon: doPolygon,
MultiPolygon: doMultiPolygon,
GeometryCollection: doGeometryCollection
};
return ns;
//---------------------------------------------------------
function getBoundingBox(geometry) {
var type = GJ.getType(geometry);
var func = getBoundingBox.implemented[type];
if (!func)
GJ.Exceptions.notImplemented(type, "getBoundingBox");
return func(geometry);
}
//---------------------------------------------------------
function doBoundingBox(geometry) {
return [].concat(geometry);
}
function doPoint(geometry) {
var coords = geometry.coordinates;
return [coords[0], coords[1], coords[0], coords[1]];
}
function doMultiPoint(geometry) {
var res = _empty();
geometry.coordinates.forEach(function (coord) {
_include(res, coord);
})
return res;
}
function doLineString(geometry) {
return doMultiPoint(geometry);
}
function doMultiLineString(geometry) {
var res = _empty();
geometry.coordinates.forEach(function (coord) {
var bbox = doLineString({ coordinates:coord });
_merge(res, bbox);
})
return res;
}
function doPolygon(geometry) {
return doMultiPoint({
coordinates: geometry.coordinates[0]
});
}
function doMultiPolygon(geometry) {
var res = _empty();
geometry.coordinates.forEach(function (coord) {
var bbox = doPolygon({ coordinates: coord });
_merge(res, bbox);
})
return res;
}
function doGeometryCollection(geometry) {
var res = _empty();
geometry.geometries.forEach(function (geom) {
var bbox = bbox(geom);
_merge(res, bbox);
})
return res;
}
//---------------------------------------------------------
function _merge(bbox, new_bbox) {
if (bbox[0] < new_bbox[0]) bbox[0] = new_bbox[0];
if (bbox[1] < new_bbox[1]) bbox[1] = new_bbox[1];
if (bbox[2] > new_bbox[2]) bbox[2] = new_bbox[2];
if (bbox[3] > new_bbox[3]) bbox[3] = new_bbox[3];
}
function _include(bbox, coord) {
if (bbox[0] > coord[0]) bbox[0] = coord[0];
if (bbox[1] > coord[1]) bbox[1] = coord[1];
if (bbox[2] < coord[0]) bbox[2] = coord[0];
if (bbox[3] < coord[1]) bbox[3] = coord[1];
}
function _empty() {
return [Number.MAX_VALUE, Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE];
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
var GJ = ns.GeoJson = ns.GeoJson || {};
GJ.getCentroid = getCentroid;
getCentroid.implemented = {
BoundingBox: doBoundingBox,
Point: doPoint,
MultiPoint: doMultiPoint,
LineString: doLineString,
MultiLineString: doMultiLineString,
Polygon: doPolygon,
MultiPolygon: doMultiPolygon,
GeometryCollection: doGeometryCollection
};
return ns;
//---------------------------------------------------------
function getCentroid(geometry) {
var type = GJ.getType(geometry);
var func = getCentroid.implemented[type];
if (!func)
GJ.Exceptions.notImplemented(type, "getCentroid");
return func(geometry);
}
//---------------------------------------------------------
function doBoundingBox(bbox) {
return GJ.createPoint([
(bbox[0] + bbox[2]) / 2,
(bbox[1] + bbox[3]) / 2,
]);
}
function doPoint(geometry) {
return GJ.createPoint(geometry.coordinates);
}
function doMultiPoint(geometry) {
var bbox = GJ.getBoundingBox(geometry);
doBoundingBox(bbox);
}
function doLineString(geometry) {
var length = GJ.getLength(geometry);
var ftr = GJ.getFeatureAt(geometry, length / 2);
if (ftr)
return ftr.geometry;
else
return null;
}
function doMultiLineString(geometry) {
var longest = GJ.getLongest(geometry);
return doLineString(longest);
}
function doPolygon(geometry) {
var dx = Number.MAX_VALUE;
var dy = Number.MAX_VALUE;
geometry.coordinates[0].forEach(function (coord) {
if (coord[0] < dx) dx = coord[0];
if (coord[1] < dy) dy = coord[1];
});
var paths = [];
geometry.coordinates[0].forEach(function (coord) {
paths.push([coord[0] - dx, coord[1] - dy]);
});
var X = 0;
var Y = 0;
var AA = 0;
for (var i = 0; i < paths.length - 1; i++) {
X += (paths[i][0] + paths[i + 1][0]) * (paths[i][0] * paths[i + 1][1] - paths[i + 1][0] * paths[i][1]);
Y += (paths[i][1] + paths[i + 1][1]) * (paths[i][0] * paths[i + 1][1] - paths[i + 1][0] * paths[i][1]);
AA += (paths[i][0] * paths[i + 1][1] - paths[i + 1][0] * paths[i][1]);
}
var A = AA * 0.5;
var x = 1 / (6 * A) * X;
var y = 1 / (6 * A) * Y;
return GJ.createPoint([x + dx, y + dy]);
}
function doMultiPolygon(geometry) {
var totalArea = 0;
var res = [];
geometry.coordinates.forEach(function (coord) {
var poly = {
type: "Polygon",
coordinates: coord
};
var centroid = doPolygon(poly).coordinates;
var area = GJ.getArea(poly);
if (totalArea == 0) {
res = centroid;
totalArea = area;
}
else {
res[0] = (totalArea * res[0] + area * centroid[0]) / (totalArea + area);
res[1] = (totalArea * res[1] + area * centroid[1]) / (totalArea + area);
totalArea += area;
}
});
return GJ.createPoint(res);
}
function doGeometryCollection(geometry) {
var bbox = GJ.getBoundingBox(geometry);
doBoundingBox(bbox);
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
var GJ = ns.GeoJson = ns.GeoJson || {};
GJ.getFeatureAt = getFeatureAt;
getFeatureAt.implemented = {
LineString: doLineString,
MultiLineString: doMultiLineString
};
return ns;
//---------------------------------------------------------
function getFeatureAt(geometry, distanceAlong) {
var type = GJ.getType(geometry);
var func = getFeatureAt.implemented[type];
if (!func)
GJ.Exceptions.notImplemented(type, "getFeatureAt");
return func(geometry, distanceAlong);
}
//---------------------------------------------------------
function doLineString(geometry, distanceAlong) {
var totalLength = 0.0;
var coords = geometry.coordinates;
for (var i = 0; i < coords.length - 1; i++) {
var p1x = coords[i][0];
var p1y = coords[i][1];
var p2x = coords[i + 1][0];
var p2y = coords[i + 1][1];
var distance = GJ.Math.distance(p1x, p1y, p2x, p2y);
totalLength += distance;
if (totalLength >= distanceAlong) {
var delta = totalLength - distanceAlong;
var f = 1 - (delta / distance);
var point = GJ.createPoint([
p1x + (p2x - p1x) * f,
p1y + (p2y - p1y) * f
]);
var feature = GJ.createFeature(point);
feature.properties.rotation = Math.atan2((p2y - p1y), (p2x - p1x));
return feature;
}
}
return null;
}
function doMultiLineString(geometry, distanceAlong) {
var longest = GJ.getLongest(geometry);
return doLineString(longest, distanceAlong);
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
var GJ = ns.GeoJson = ns.GeoJson || {};
GJ.getLength = getLength;
getLength.implemented = {
BoundingBox: zero,
Point: zero,
MultiPoint: zero,
LineString: doLineString,
MultiLineString: doMultiLineString,
Polygon: zero,
MultiPolygon: zero,
GeometryCollection: doGeometryCollection
};
return ns;
//---------------------------------------------------------
function getLength(geometry) {
var type = GJ.getType(geometry);
var func = getLength.implemented[type];
if (!func)
GJ.Exceptions.notImplemented(type, "getLength");
return func(geometry);
}
//---------------------------------------------------------
function zero(geometry) {
return 0;
}
function doLineString(geometry) {
var coords = geometry.coordinates;
if (coords.length < 2)
return 0;
var result = 0;
for (var i = 1; i < coords.length; i++)
result += ns.GeoJson.Math.distance(
coords[i - 1][0],
coords[i - 1][1],
coords[i][0],
coords[i][1]
);
return result;
}
function doMultiLineString(geometry) {
return geometry.coordinates.reduce(function (total, coords) {
return total + doLineString({ coordinates: coords });
}, 0);
}
function doGeometryCollection(geometry) {
for (i = 0; i < geometry.geometries.length; i++) {
length += getLength(geometry.geometries[i]);
}
return length;
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
var GJ = ns.GeoJson = ns.GeoJson || {};
GJ.getLongest = getLongest;
getLongest.implemented = {
BoundingBox: doesNotApply,
Point: doesNotApply,
MultiPoint: doesNotApply,
LineString: doesNotApply,
MultiLineString: doMultiLineString,
Polygon: doesNotApply,
MultiPolygon: doesNotApply,
GeometryCollection: doesNotApply
};
return ns;
//---------------------------------------------------------
function getLongest(geometry) {
var type = GJ.getType(geometry);
var func = getLongest.implemented[type];
if (!func)
GJ.Exceptions.notImplemented(type, "getLongest");
return func(geometry);
}
//---------------------------------------------------------
function doesNotApply(geometry) {
var type = GJ.getType(geometry);
GJ.Exceptions.doesNotApply(type, "getLongest");
}
function doMultiLineString(geometry) {
var longest = { item: null, length: 0 };
geometry.coordinates.forEach(function (lineCoords) {
var line = GJ.createLineString(lineCoords);
var length = GJ.getLength(line);
if (length > longest.length) {
longest.item = line;
longest.length = length;
}
});
return longest.item;
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
var GJ = ns.GeoJson = ns.GeoJson || {};
GJ.heal = heal;
return ns;
//---------------------------------------------------------
function heal(obj) {
if (obj.type == "Feature")
_healFeature(obj);
if (obj.type == "FeatureCollection")
_healFeatureCollection(obj);
if (obj.type == "Polygon")
_healPolygon(obj);
}
//---------------------------------------------------------
function _healFeature(feature) {
if (!feature.properties)
feature.properties = {};
}
function _healFeatureCollection(fc) {
if (!fc.features)
fc.features = [];
fc.features.forEach(function (ftr) {
_healFeature(ftr);
})
}
function _healPolygon(polygon) {
var coords = polygon.coordinates[0][0];
var point = GJ.createPoint(coords);
GJ.appendPointToPolygon(polygon, point);
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
var GJ = ns.GeoJson = ns.GeoJson || {};
GJ.intersection = intersection;
intersection.implemented = {
LineString: {
LineString: doLineStringWithLineString
}
}
return ns;
//---------------------------------------------------------
function intersection(geometry1, geometry2) {
var type = GJ.getType(geometry1);
var funcs = intersection.implemented[type];
if (!funcs)
GJ.Exceptions.notImplemented(type, "intersection");
type = GJ.getType(geometry2);
var func = funcs[type];
if (!func)
GJ.Exceptions.notImplemented(type, "intersection");
return func(geometry1, geometry2);
}
//---------------------------------------------------------
function doLineStringWithLineString(line1, line2) {
var coords1 = line1.coordinates;
var coords2 = line2.coordinates;
var points = [];
for (var i = 1; i < coords1.length; i++) {
var start1 = coords1[i - 1];
var end1 = coords1[i];
for (var j = 1; j < coords2.length; i++) {
var start2 = coords2[j - 1];
var end2 = coords2[j];
var point = GJ.Math.segmentIntersection(start1, end1, start2, end2);
if (point)
points.push(point);
}
}
if (points.length == 0)
return null;
return {
type: "MultiPoint",
coordinates: points
}
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
var GJ = ns.GeoJson = ns.GeoJson || {};
GJ.intersects = intersects;
intersects.implemented = {
BoundingBox: {
BoundingBox: doBoundingBoxWithBoundingBox
},
LineString: {
LineString: doLineStringWithLineString
},
Polygon: {
Polygon: doPolygonWithPolygon
}
};
return ns;
//---------------------------------------------------------
function intersects(geometry1, geometry2) {
var type = GJ.getType(geometry1);
var funcs = intersects.implemented[type];
if (!funcs)
GJ.Exceptions.notImplemented(type, "intersects");
type = GJ.getType(geometry2);
var func = funcs[type];
if (!func)
GJ.Exceptions.notImplemented(type, "intersects");
return func(geometry1, geometry2);
}
//---------------------------------------------------------
function doBoundingBoxWithBoundingBox(bbox1, bbox2) {
var minX1 = bbox1[0], minY1 = bbox1[1], maxX1 = bbox1[2], maxY1 = bbox1[3];
var minX2 = bbox2[0], minY2 = bbox2[1], maxX2 = bbox2[2], maxY2 = bbox2[3];
return (Math.max(minY1, maxY1) > minY2) &&
(Math.min(minY1, maxY1) < maxY2) &&
(Math.max(minX1, maxX1) > minX2) &&
(Math.min(minX1, maxX1) < maxX2);
}
function doLineStringWithLineString(line1, line2) {
var coords1 = line1.coordinates;
var coords2 = line2.coordinates;
var points = [];
for (var i = 1; i < coords1.length; i++) {
var start1 = coords1[i - 1];
var end1 = coords1[i];
for (var j = 1; j < coords2.length; j++) {
var start2 = coords2[j - 1];
var end2 = coords2[j];
var point = GJ.Math.segmentIntersection(start1, end1, start2, end2);
if (point)
points.push(point);
}
}
if (points.length == 0)
return null;
return {
type: "MultiPoint",
coordinates: points
}
}
function doPolygonWithPolygon(poly1, poly2) {
var bbox1 = GJ.getBoundingBox(poly1);
var bbox2 = GJ.getBoundingBox(poly2);
if (doBoundingBoxWithBoundingBox(bbox1, bbox2) == false)
return false;
var shell1 = GJ.createLineString(poly1.coordinates[0]);
var shell2 = GJ.createLineString(poly2.coordinates[0]);
if (doLineStringWithLineString(shell1, shell2))
return true;
if (GJ.isContainedBy(poly1, poly2))
return true;
if (GJ.isContainedBy(poly2, poly1))
return true;
return false;
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
var GJ = ns.GeoJson = ns.GeoJson || {};
GJ.isContainedBy = isContainedBy;
isContainedBy.implemented = {
Point: {
BoundingBox: doPointByBoundingBox,
LineString: doPointByRing,
Polygon: doPointByPolygon
},
LineString: {
LineString: doLineStringByRing,
},
Polygon: {
Polygon: doPolygonByPolygon
}
};
return ns;
//---------------------------------------------------------
function isContainedBy(geometry, container) {
var type = GJ.getType(geometry);
var funcs = isContainedBy.implemented[type];
if (!funcs)
GJ.Exceptions.notImplemented(type, "isContainedBy");
type = GJ.getType(container);
var func = funcs[type];
if (!func)
GJ.Exceptions.notImplemented(type, "isContainedBy");
return func(geometry, container);
}
//---------------------------------------------------------
function doPointByBoundingBox(geometry, container) {
var bbox = container;
var minX = bbox[0];
var minY = bbox[1];
var maxX = bbox[2];
var maxY = bbox[3];
var px = geometry.coordinates[0];
var py = geometry.coordinates[1];
return (px >= minX && px <= maxX) && (py >= minY && py <= maxY);
}
function doPointByRing(point, ring) {
var xInt; // x intersection of e with ray
var crossings = 0; // number of edge/ray crossings
var x1, y1, x2, y2;
var nPts = ring.length;
var pointx = point.coordinates[0];
var pointy = point.coordinates[1];
// For each line edge l = (i-1, i), see if it crosses ray from test point in positive x direction.
for (i = 1; i < nPts; i++) {
var p1 = ring.coordinates[i];
var p2 = ring.coordinates[i - 1];
x1 = p1[0] - pointx;
y1 = p1[1] - pointy;
x2 = p2[0] - pointx;
y2 = p2[1] - pointy;
if (((y1 > 0) && (y2 <= 0)) ||
((y2 > 0) && (y1 <= 0))) {
// e straddles x axis, so compute intersection.
xInt = (x1 * y2 - x2 * y1) / (y2 - y1);
//xsave = xInt;
// crosses ray if strictly positive intersection.
if (0.0 < xInt) {
crossings++;
}
}
}
// point is inside if an odd number of crossings.
if ((crossings % 2) == 1) {
return true;
}
else {
return false;
}
}
function doPointByPolygon(point, poly) {
var ring = { coordinates: poly2.coordinates[0] };
return doPointByRing(point, ring)
}
function doLineStringByRing(line, ring) {
line.coordinates.forEach(function (coord) {
if (!doPointByRing({ coordinates: coord }, ring))
return false;
})
return true;
}
function doPolygonByPolygon(poly1, poly2) {
var line = { coordinates: poly1.coordinates[0] };
var ring = { coordinates: poly2.coordinates[0] };
return doLineStringByRing(line, ring);
}
//---------------------------------------------------------
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
var GJ = ns.GeoJson = ns.GeoJson || {};
GJ.Math = {};
GJ.Math.distance = distance;
GJ.Math.nearestPointOnSegment = nearestPointOnSegment;
GJ.Math.segmentIntersection = segmentIntersection;
GJ.Math.segmentize = segmentize;
GJ.Math.desegmentize = desegmentize;
GJ.Math.degreesToRadians = degreesToRadians;
GJ.Math.radiansToDegrees = radiansToDegrees;
return ns;
//---------------------------------------------------------
function distance(param1, param2, param3, param4) {
if (!ns.Util.isUndefined(param3)) {
x1 = param1;
y1 = param2;
x2 = param3;
y2 = param4;
}
else {
x1 = param1[0];
y1 = param1[1];
x2 = param2[0];
y2 = param2[1];
}
var R = 6371000;
deltaX = (x2 - x1) * Math.PI / 180;
y1 = y1 * Math.PI / 180;
y2 = y2 * Math.PI / 180;
var x = deltaX * Math.cos((y1 + y2) / 2);
var y = (y2 - y1);
var d = Math.sqrt(x * x + y * y);
return R * d;
};
function segmentIntersection(start1, end1, start2, end2) {
// http://jsfiddle.net/justin_c_rounds/Gd2S2/light/
var p1x = start1[0];
var p1y = start1[1];
var p2x = end1[0];
var p2y = end1[1];
var p3x = start2[0];
var p3y = start2[1];
var p4x = end2[0];
var p4y = end2[1];
var denominator, a, b, numerator1, numerator2, result = {
x: null,
y: null,
onLine1: false,
onLine2: false
};
denominator = ((p4y - p3y) * (p2x - p1x)) - ((p4x - p3x) * (p2y - p1y));
if (denominator == 0) {
return null;
}
a = p1y - p3y;
b = p1x - p3x;
numerator1 = ((p4x - p3x) * a) - ((p4y - p3y) * b);
numerator2 = ((p2x - p1x) * a) - ((p2y - p1y) * b);
a = numerator1 / denominator;
b = numerator2 / denominator;
// if we cast these lines infinitely in both directions, they intersect here:
result.x = p1x + (a * (p2x - p1x));
result.y = p1y + (a * (p2y - p1y));
/*
// it is worth noting that this should be the same as:
x = p3x + (b * (p4x - p3x));
y = p3x + (b * (p4y - p3y));
*/
// if line1 is a segment and line2 is infinite, they intersect if:
if (a > 0 && a < 1) {
result.onLine1 = true;
}
// if line2 is a segment and line1 is infinite, they intersect if:
if (b > 0 && b < 1) {
result.onLine2 = true;
}
if (result.onLine1 && result.onLine2)
return [result.x, result.y];
else
return null;
}
function nearestPointOnSegment(point, start, end) {
var startX = start[0];
var startY = start[1];
var endX = end[0];
var endY = end[1];
var pointX = point[0];
var pointY = point[1];
lineDeltaX = endX - startX;
lineDeltaY = endY - startY;
var len = lineDeltaX * lineDeltaX + lineDeltaY * lineDeltaY;
var pointDeltaX = pointX - startX;
var pointDeltaY = pointY - startY;
var dot = pointDeltaX * lineDeltaX + pointDeltaY * lineDeltaY;
var t = Math.min(1, Math.max(0, dot / len));
var resultX = startX + lineDeltaX * t;
var resultY = startY + lineDeltaY * t;
return [resultX, resultY];
}
function segmentize(lineString) {
var result = [];
var coords = lineString.coordinates;
for (var i = 1; i < coords.length; i++) {
var start = coords[i - 1];
var end = coords[i];
result.push([start, end]);
}
return result;
}
function desegmentize(segments) {
var coords = [];
for (var i = 0; i < segments.length; i++) {
if (i == 0)
coords.push(segments[i][0]);
coords.push(segments[i][1]);
}
return GJ.createLineString(coords);
}
function degreesToRadians(degrees) {
return degrees * Math.PI / 180;
};
function radiansToDegrees(radians) {
return radians * 180 / Math.PI;
};
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
var GJ = ns.GeoJson = ns.GeoJson || {};
GJ.rotate = rotate;
rotate.implemented = {
Point: doPoint,
MultiPoint: doMultiPoint,
LineString: doLineString,
MultiLineString: doMultiLineString,
Polygon: doPolygon,
MultiPolygon: doMultiPolygon,
GeometryCollection: doGeometryCollection
};
return ns;
//---------------------------------------------------------
function rotate(geometry, origin, angle) {
var type = GJ.getType(geometry);
var func = rotate.implemented[type];
if (!func)
GJ.Exceptions.notImplemented(type, "rotate");
return func(geometry, origin, angle);
}
//---------------------------------------------------------
function doPoint(point, origin, angle) {
var pointX = point.coordinates[0];
var pointY = point.coordinates[1];
var originX = origin.coordinates[0];
var originY = origin.coordinates[1];
var cos = Math.cos(angle);
var sin = Math.sin(angle);
// Rotate the point (counter clockwise)
var x = (pointX - originX) * cos - (pointY - originY) * sin + originX;
var y = (pointX - originX) * sin + (pointY - originY) * cos + originY;
return GJ.createPoint(x, y);
}
function doMultiPoint(mpoint, origin, angle) {
var res = GJ.createMultiPoint([]);
mpoint.coordinates.forEach(function (coord) {
var point = GJ.createPoint(coord);
var rotated = doPoint(point, origin, angle);
res.coordinates.push(rotated.coordinates);
})
return res;
}
function doLineString(line, origin, angle) {
var res = GJ.createLineString([]);
line.coordinates.forEach(function (coord) {
var point = GJ.createPoint(coord);
var rotated = doPoint(point, origin, angle);
res.coordinates.push(rotated.coordinates);
})
return res;
}
function doMultiLineString(mline, origin, angle) {
var res = GJ.createMultiLineString([]);
mline.coordinates.forEach(function (coord) {
var line = GJ.createLineString(coord);
var rotated = doLineString(line, origin, angle);
res.coordinates.push(rotated.coordinates);
})
return res;
}
function doPolygon(poly, origin, angle) {
var res = GJ.createPolygon([]);
poly.coordinates.forEach(function (coord) {
var line = GJ.createLineString(coord);
var rotated = doLineString(line, origin, angle);
res.coordinates.push(rotated.coordinates);
})
return res;
}
function doMultiPolygon(mpoly, origin, angle) {
var res = GJ.createMultiPolygon([]);
mpoly.coordinates.forEach(function (coord) {
var poly = GJ.createPolygon(coord);
var rotated = doPolygon(poly, origin, angle);
res.coordinates.push(rotated.coordinates);
})
return res;
}
function doGeometryCollection(gc, origin, angle) {
var res = {
type: "GeometryCollection",
geometries:[]
}
gc.geometries.forEach(function (geom) {
var rotated = rotate(geom, origin, angle);
res.geometries.push(rotated);
})
return res;
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
var GJ = ns.GeoJson = ns.GeoJson || {};
GJ.slice = slice;
slice.implemented = {
LineString: {
//LineString: doLineStringWithLineString,
Point: doLineStringWithPoint
}
}
return ns;
//---------------------------------------------------------
function slice(geometry, splitBy) {
var type = GJ.getType(geometry);
var funcs = slice.implemented[type];
if (!funcs)
GJ.Exceptions.notImplemented(type, "slice");
type = GJ.getType(splitBy);
var func = funcs[type];
if (!func)
GJ.Exceptions.notImplemented(type, "slice");
return func(geometry, splitBy);
}
//---------------------------------------------------------
function doLineStringWithLineString(line1, line2) {
}
function doLineStringWithPoint(line, point) {
var segments = GJ.Math.segmentize(line);
var calcs = [];
for (var i = 0; i < segments.length; i++) {
calcs.push(_calc(point.coordinates, segments[i]));
}
var min = calcs.reduce(function (prev, current) {
return (current.distance < prev.distance) ? current : prev;
});
var idx = calcs.indexOf(min);
var segments1 = segments.slice(0, idx);
var segments2 = segments.slice(idx + 1);
segments1.push([segments[idx][0], min.nearest]);
segments2.unshift([min.nearest, segments[idx][1]]);
return [
GJ.Math.desegmentize(segments1),
GJ.Math.desegmentize(segments2)
];
}
//---------------------------------------------------------
function _calc(point, segment) {
var start = segment[0];
var end = segment[1];
var nearest = GJ.Math.nearestPointOnSegment(point, start, end);
var distance = GJ.Math.distance(point[0], point[1], nearest[0], nearest[1]);
return {
nearest: nearest,
distance: distance
};
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
var GJ = ns.GeoJson = ns.GeoJson || {};
GJ.snapTo = snapTo;
snapTo.implemented = {
LineString: doLineString,
MultiLineString: doMultiLineString,
//Polygon: doPolygon,
//MultiPolygon: doMultiPolygon
};
return ns;
//---------------------------------------------------------
function snapTo(point, geometry) {
var type = GJ.getType(geometry);
var func = snapTo.implemented[type];
if (!func)
GJ.Exceptions.notImplemented(type, "snapTo");
return func(point, geometry);
}
//---------------------------------------------------------
function doLineString(point, line) {
var result = _nearestResult(point, line.coordinates);
return GJ.createPoint(result.coords);
}
function doMultiLineString(point, mline) {
var coords = mline.coordinates;
var currentDistance = Number.MAX_VALUE;
var currentCoords = null;
for (var i = 0; i < coords.length; i++) {
var res = _nearestResult(point, coords[i]);
if (res.distance < currentDistance) {
currentDistance = res.distance;
currentCoords = res.coords;
}
}
return GJ.createPoint(currentCoords);
}
//function doPolygon(point, mline) {
//}
//function doMultiPolygon(point, mline) {
//}
//---------------------------------------------------------
function _nearestResult(point, coords) {
var pnt = point.coordinates;
var currentDistance = Number.MAX_VALUE;
var currentCoords = null;
for (var i = 1; i < coords.length; i++) {
var start = coords[i - 1];
var end = coords[i];
var nearest = GJ.Math.nearestPointOnSegment(pnt, start, end);
var distance = GJ.Math.distance(pnt[0], pnt[1], nearest[0], nearest[1]);
if (distance < currentDistance) {
currentCoords = nearest;
currentDistance = distance;
}
}
return {
coords: currentCoords,
distance: currentDistance
};
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.LabelEngine = LabelEngine;
return ns;
//---------------------------------------------------------
function LabelEngine(layerManager, view) {
this.run = function () {
var state = view.getState();
var trf = view.getPixelTransformer();
var allLabels = [];
var layers = layerManager.getLayers();
layers.forEach(function (layer) {
if (layer.getType() == "VectorLayer" && layer.isVisible()) {
var theme = layer.getThemer().getTheme(state.zoom);
if (theme) {
var features = layer
.getFeatureEngine()
.getLoadedFeatureCollection()
.features;
var labels = new ns.LabelMaker()
.makeLabels(features, theme, state);
labels.sort(function (x, y) {
return y.weight - x.weight;
});
ns.LabelFilters.removeDuplicates(labels);
ns.LabelFilters.removeCollisions(labels, trf);
ns.Util.arrayAppend(labels, allLabels);
}
}
});
ns.LabelFilters.removeCollisions(allLabels, trf);
return _toFeatureCollection(allLabels);
}
//---------------------------------------------------------
function _toFeatureCollection(labels) {
return {
type: "FeatureCollection",
features: labels.map(function (m) {
return {
type: "Feature",
geometry: m.centroid,
properties: {
text: m.text,
symbol: m.symbol,
rotation: m.rotation
}
}
})
};
}
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.LabelFilters = {
removeDuplicates: removeDuplicates,
removeCollisions: removeCollisions
}
var GJ = ns.GeoJson;
return ns;
//---------------------------------------------------------
function removeDuplicates(labels) {
var labelsToRemove = {};
for (var i = labels.length - 1; i >= 0; i--) {
var symbol = labels[i].symbol;
if (symbol && symbol.allowDuplicates)
continue;
var text = labels[i].text;
if (labelsToRemove[text])
labels.splice(i, 1);
labelsToRemove[text] = true;
}
}
function removeCollisions(labels, trf) {
for (var i = 0; i < labels.length; i++) {
_boundarize(labels[i], trf);
}
for (var i = labels.length - 1; i >= 0; i--) {
var symbol = labels[i].symbol;
if (symbol && !symbol.collisionDetection !== false)
continue;
var collides = false;
for (var j = 0; j < labels.length; j++) {
if (labels[j] == labels[i]) continue;
if (GJ.intersects(labels[i].boundary, labels[j].boundary)) {
collides = true;
break;
}
}
if (collides)
labels.splice(i, 1);
}
}
//---------------------------------------------------------
function _boundarize(label, trf) {
var size = trf.measureText(label.text, label.symbol);
var pos = trf.translate(label.centroid);
var bbox = [
pos.x - size.width / 2,
pos.y - size.height / 2,
pos.x + size.width / 2,
pos.y + size.height / 2
];
label.boundary = bbox;
if (label.rotation != 0 || label.symbol.autoRotate) {
var poly = GJ.createPolygon(bbox);
poly = GJ.rotate(poly, GJ.createPoint(pos.x, pos.y), label.rotation);
label.boundary = poly;
}
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.LabelMaker = LabelMaker;
return ns;
//---------------------------------------------------------
function LabelMaker() {
this.makeLabels = function (features, theme, state) {
var labels = [];
features.forEach(function (ftr) {
var label = _getLabel(theme, ftr, state);
if (label)
labels.push(label);
})
return labels;
}
//---------------------------------------------------------
function _getLabel(theme, feature, state) {
var result = {
text: theme.getLabelText(feature),
symbol: theme.getLabeller(feature),
rotation: 0,
weight: 0
};
if (result.text == null)
return null;
if (result.symbol == null)
return null;
switch (feature.geometry.type) {
case "LineString":
case "MultiLineString":
var info = _getLineInfo(result.symbol, feature.geometry, state);
if (!info)
return null;
ns.Util.assign(result, info);
break;
case "Polygon":
case "MultiPolygon":
result.weight = ns.GeoJson.getArea(feature.geometry);
case "Point":
case "MultiPoint":
result.centroid = ns.GeoJson.getCentroid(feature.geometry);
}
return result;
}
function _getLineInfo(symbol, geometry, state) {
var cropped = ns.GeoJson.crop(geometry, state.bounds);
if (!cropped)
return null;
var result = {
rotation: 0,
centroid: ns.GeoJson.getCentroid(cropped),
weight: ns.GeoJson.getLength(cropped)
}
if (symbol.rotation != 0)
result.rotation = symbol.rotation;
if (symbol.autoRotate) {
var ftr = ns.GeoJson.getFeatureAt(cropped, result.weight / 2);
var rotation = 0;
if (ftr)
rotation = ftr.properties.rotation;
result.rotation += rotation;
}
//Ensure the labels do not show upside down
if (result.rotation > Math.PI / 2)
result.rotation -= Math.PI;
if (result.rotation < -Math.PI / 2)
result.rotation += Math.PI;
return result;
}
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.RasterLayer = RasterLayer;
return ns;
//---------------------------------------------------------
function RasterLayer(layerJSON, sourceJSON) {
var isVisible = layerJSON.visible;
this.isVisible = function () {
return isVisible;
}
this.show = function () {
isVisible = true;
}
this.hide = function () {
isVisible = false;
}
this.getType = function () {
return "RasterLayer";
}
this.getKey = function () {
return layerJSON.key;
}
this.getUrl = function () {
return sourceJSON.url;
}
this.isGreyScale = function () {
return layerJSON.greyScale;
}
this.getAttribution = function () {
return sourceJSON.attribution;
}
this.info = function () {
return {
key: layerJSON.key,
name: layerJSON.name,
sourceKey: layerJSON.sourceKey,
visible: this.isVisible()
};
}
this.toJSON = function () {
return {
type:"RasterLayer",
key: layerJSON.key,
name: layerJSON.name,
sourceKey: layerJSON.sourceKey,
visible: this.isVisible(),
greyScale: this.isGreyScale()
};
}
}
})(Mapzania || {})
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.VectorLayer = VectorLayer;
return ns;
//---------------------------------------------------------
function VectorLayer(layerJSON, featureEngine, themer, attribution) {
var hidden = [];
var filters = [];
var responseFilters = [];
var isVisible = layerJSON.visible;
// ---INFO---
this.getType = function () {
return "VectorLayer";
}
this.getKey = function () {
return layerJSON.key;
}
this.getFeatureEngine = function () {
return featureEngine;
}
this.getThemer = function () {
return themer;
}
this.getFilterText = function () {
return layerJSON.filter;
}
this.getFields = function () {
var fields = layerJSON.fields;
if (ns.Util.isArray(fields))
return [].concat(fields);
return [];
}
this.isVisible = function () {
return isVisible;
}
// ---BEHAVIOUR---
this.show = function () {
isVisible = true;
}
this.hide = function () {
isVisible = false;
}
// ---FILTERS---
this.getFilters = function () {
return [].concat(filters);
}
this.addFilter = function (filter, index) {
if (index)
filters.splice(index, 0, filter)
else
filters.push(filter);
}
this.removeFilter = function (index) {
filters.splice(index, 1);
}
this.clearFilters = function (layerKey) {
filters = [];
}
// ---STYLES---
this.addStyle = function (style) {
themer.setDynamicTheme(style);
}
this.clearStyles = function () {
themer.removeDynamicTheme();
}
this.setFeatureStyle = function (id, style) {
themer.setFeatureStyle(id, style);
}
this.clearFeatureStyle = function (layerKey, id) {
themer.setFeatureStyle(id);
}
// ---FEATURES---
this.addFeatureCollection = function (featureCollection) {
featureEngine.addLocalFeatureCollection(featureCollection);
}
this.addFeature = function (feature) {
var fc = ns.GeoJson.createFeatureCollection(feature);
featureEngine.addLocalFeatureCollection(fc);
}
this.clearFeatures = function () {
featureEngine.clearLocalFeatures();
}
this.hideFeature = function (id) {
featureEngine.hideFeature(id);
}
this.showFeature = function (id) {
featureEngine.showFeature(id);
}
// ---OTHER---
this.getAttribution = function () {
return attribution;
}
this.info = function () {
return {
key: layerJSON.key,
name: layerJSON.name,
sourceKey: layerJSON.sourceKey,
visible: this.isVisible()
};
}
this.toJSON = function () {
return {
type: "VectorLayer",
key: layerJSON.key,
name: layerJSON.name,
sourceKey: layerJSON.sourceKey,
visible: this.isVisible(),
fields: this.getFields(),
filter: this.getFilterText(),
themes: this.getThemer().toJSON()
};
}
//---------------------------------------------------------
//function _notifyClientFeaturesChanged(layer) {
// var data = {
// layerKey: layer.key,
// features: layer.localFeatures
// };
// me.fire("client_features_changed", data);
//}
}
})(Mapzania || {})
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.Leaflet = ns.Leaflet || {};
ns.Leaflet.InfoControl = make();
return ns;
//---------------------------------------------------------
function make() {
return L.Control.extend({
options: {
position: "topright"
},
onAdd: function (map) {
this._map = map;
var el = L.DomUtil.create("div", "leaflet-control-zoom-display leaflet-bar-part leaflet-bar");
el.style.backgroundColor = "rgba(255, 255, 255, 0.7)";
el.style.border = "2px solid #777";
el.style.borderRadius = "0px";
el.style.padding = "1px";
el.style.paddingLeft = "4px";
el.style.paddingRight = "4px";
el.style.color = "black";
el.style.width = "170px";
this._container = el;
this._updateInfo(map.getZoom(), map.getCenter());
map.on("moveend", this._onMoveEnd, this);
map.on("mousemove", this._onMouseMove, this);
return el;
},
onRemove: function (map) {
map.off("moveend", this._onMoveEnd, this);
map.off("mousemove", this._onMouseMove, this);
},
_onMouseMove: function (evt) {
this._updateInfo(this._map.getZoom(), evt.latlng);
},
_onMoveEnd: function () {
var map = this._map;
this._updateInfo(map.getZoom(), map.getCenter());
},
_updateInfo: function (zoom, latlng) {
var lat = Number(latlng.lat).toFixed(4);
var lng = Number(latlng.lng).toFixed(4);
this._container.innerHTML = ""
+ "
"
+ ""
+ " Zoom | "
+ " Location | "
+ "
"
+ ""
+ " " + zoom + " | "
+ " "
+ " "
+ " Lat:"
+ " " + lat + ""
+ " "
+ " "
+ " Lng:"
+ " " + lng + ""
+ " "
+ " | "
+ "
"
+ "
";
}
});
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.Leaflet = ns.Leaflet || {};
ns.Leaflet.Toolbar = make();
return ns;
//---------------------------------------------------------
function make() {
return L.Control.extend({
options: {
position: 'topleft'
},
initialize: function (buttons, options) {
if (options) {
L.Util.setOptions(this, options);
}
this._bar = this.container = L.DomUtil.create('div', 'leaflet-bar');
if (!buttons)
buttons = [];
for (var i = 0; i < buttons.length; i++) {
addButton(buttons[i]);
}
},
onAdd: function (map) {
return this.container;
},
addButton: function (button) {
var link = L.DomUtil.create("a", "leaflet-control-zoom-in", this._bar);
link.href = '#';
link.innerHTML = button.html;
link.title = button.title;
link.setAttribute('role', 'button');
link.setAttribute('aria-label', button.title);
link.setAttribute("style", button.style);
L.DomEvent.disableClickPropagation(link);
L.DomEvent.on(link, 'click', L.DomEvent.stop);
if (button.fn)
L.DomEvent.on(link, 'click', button.fn, this);
L.DomEvent.on(link, 'click', this._refocusOnMap, this);
return link;
}
});
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.Leaflet = ns.Leaflet || {};
ns.Leaflet.Convert = {
latLngBoundsToBBox: latLngBoundsToBBox,
pixelBoundsToBBox: pixelBoundsToBBox
};
return ns;
//---------------------------------------------------------
function latLngBoundsToBBox(latLngBounds) {
var sw = latLngBounds.getSouthWest();
var ne = latLngBounds.getNorthEast();
return [sw.lng, sw.lat, ne.lng, ne.lat];
}
function pixelBoundsToBBox(pixelBounds) {
var p = pixelBounds;
return [p.min.x, p.min.y, p.max.x, p.max.y];
}
})(Mapzania || {});
/*
* L.TileLayer.Grayscale is a regular tilelayer with grayscale makeover.
*/
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.Leaflet = ns.Leaflet || {};
ns.Leaflet.GreyScaleTileLayer = make();
return ns;
//---------------------------------------------------------
function make() {
// https://github.com/Zverik/leaflet-grayscale
return L.TileLayer.extend({
options: {
quotaRed: 21,
quotaGreen: 71,
quotaBlue: 8,
quotaDividerTune: 0,
quotaDivider: function () {
return this.quotaRed + this.quotaGreen + this.quotaBlue + this.quotaDividerTune;
}
},
initialize: function (url, options) {
options = options || {}
options.crossOrigin = true;
L.TileLayer.prototype.initialize.call(this, url, options);
this.on('tileload', function (e) {
this._makeGrayscale(e.tile);
});
},
_createTile: function () {
var tile = L.TileLayer.prototype._createTile.call(this);
tile.crossOrigin = "Anonymous";
return tile;
},
_makeGrayscale: function (img) {
if (img.getAttribute('data-grayscaled'))
return;
img.crossOrigin = '';
var canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
var imgd = ctx.getImageData(0, 0, canvas.width, canvas.height);
var pix = imgd.data;
for (var i = 0, n = pix.length; i < n; i += 4) {
pix[i] = pix[i + 1] = pix[i + 2] = (this.options.quotaRed * pix[i] + this.options.quotaGreen * pix[i + 1] + this.options.quotaBlue * pix[i + 2]) / this.options.quotaDivider();
}
ctx.putImageData(imgd, 0, 0);
img.setAttribute('data-grayscaled', true);
img.src = canvas.toDataURL();
}
});
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.Leaflet = ns.Leaflet || {};
ns.Leaflet.Label = make();
return ns;
//---------------------------------------------------------
function make() {
return L.DivOverlay.extend({
initialize: function (options) {
L.setOptions(this, options);
},
_initLayout: function () {
var className = "leaflet-zoom-" + (this._zoomAnimated ? "animated" : "hide");
var node = this._contentNode = this._container = L.DomUtil.create('div', className);
var o = this.options;
node.setAttribute("style", o.style);
//node.style["background-color"] = "white";
node.innerHTML = o.text;
this.setLatLng(o.position);
},
// ---------- Required Overrides----------------
_updateLayout: function () { },
_adjustPan: function () { },
_animateZoom: function (e) {
var pos = this._map._latLngToNewLayerPoint(this._latlng, e.zoom, e.center);
this._setPosition(pos);
},
_updatePosition: function () {
var pos = this._map.latLngToLayerPoint(this._latlng);
this._setPosition(pos);
},
_setPosition: function (pos) {
var map = this._map;
var container = this._container;
var offset = L.point(this.options.offset);
pos = pos.add(offset);
//chrome blurriness fix
pos.x = Math.round(pos.x);
pos.y = Math.round(pos.y);
L.DomUtil.setPosition(container, pos);
//var origin = node.style["transform-origin"]
container.style["transform-origin"] = "center";
container.style[L.DomUtil.TRANSFORM] += (" rotate(" + this.options.rotation + "rad)");
},
});
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.Leaflet = ns.Leaflet || {};
ns.Leaflet.LabelLayer = make();
return ns;
//---------------------------------------------------------
function make() {
return L.FeatureGroup.extend({
initialize: function (options) {
L.Util.setOptions(this, options);
this._layers = {};
},
addLabels: function (featureCollection) {
var me = this;
featureCollection.features.forEach(function (ftr) {
var coords = ftr.geometry.coordinates;
var latlng = new L.LatLng(coords[1], coords[0], coords[2]);
//---TEMP----
//var layer = L.circleMarker(latlng, {
// radius: 2,
// stroke: false,
// fillOpacity: 1,
// fillColor: "#FF0000"
//});
//me.addLayer(layer);
//-----------
var symbol = ftr.properties["symbol"];
var style = ns.Leaflet.SymbolConverter.toCss(symbol);
var text = ftr.properties["text"];
var measure = me._measureText(text, style);
var offset = { x: 0, y: 0 };
if (symbol.offset)
offset = Object.assign({}, symbol.offset);
offset.y = -offset.y;
switch (symbol.alignment) {
case 0:
offset.x -= measure.width / 2;
offset.y -= measure.height / 2;
break;
case 1:
offset.x -= measure.width;
offset.y -= measure.height / 2;
break;
case 2:
offset.y -= measure.height / 2;
break;
default:
throw "Unknown text alignment";
}
var layer = new ns.Leaflet.Label({
offset: [offset.x, offset.y],
position: latlng,
text: text,
style: style,
rotation: -ftr.properties["rotation"]
});
me.addLayer(layer);
});
return this;
},
_measureText: function (text, style) {
var el;
if (!this._el) {
el = this._el = document.createElement("div");
document.body.appendChild(el);
}
else
el = this._el;
el.setAttribute("style", style);
el.style.position = "absolute";
el.style.left = "-1000px";
el.style.top = "-1000px";
el.innerHTML = text;
return { height: el.offsetHeight, width: el.offsetWidth };
}
});
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.Leaflet = ns.Leaflet || {};
ns.Leaflet.MarkerLayer = make();
register();
return ns;
//---------------------------------------------------------
function register() {
L.SVG.include({
_mzUpdateMarkers: function (layer) {
var centerX = layer._point.x;
var centerY = layer._point.y;
var size = layer._radius;
var shape = layer.options.pattern;
var rotation = layer.options.rotation;
//var offsetX = 0;
//var offsetY = 0;
//if (layer.options.offset) {
var offsetX = layer.options.offset.x;
var offsetY = -layer.options.offset.y;
//}
if (shape === "diamond") {
var def = [
["M", 0.0, -0.5],
["L", -0.5, 0],
["L", 0.0, 0.5],
["L", 0.5, 0.0]
];
var path = _makePath(def, centerX, centerY, size, rotation, offsetX, offsetY, true);
this._setPath(layer, path);
}
if (shape === "square") {
var def = [
["M", -0.5, -0.5],
["L", -0.5, 0.5],
["L", 0.5, 0.5],
["L", 0.5, -0.5]
];
var path = _makePath(def, centerX, centerY, size, rotation, offsetX, offsetY, true);
this._setPath(layer, path);
}
if (shape === "triangle") {
var def = [
["M", -0.5, 0.289],
["L", 0.5, 0.289],
["L", 0, -0.577]
];
var path = _makePath(def, centerX, centerY, size, rotation, offsetX, offsetY, true);
this._setPath(layer, path);
}
if (shape === "chevron") {
var def = [
["M", 0.5, 0.289],
["L", 0, -0.577],
["L", -0.5, 0.289],
];
var path = _makePath(def, centerX, centerY, size, rotation, offsetX, offsetY, false);
this._setPath(layer, path);
}
if (shape === "circle") {
var def = [
["M", -0.5, 0],
["C", -0.5, 0, -0.475, -0.475, 0, -0.5],
["C", 0, -0.5, 0.475, -0.475, 0.5, 0],
["C", 0.5, 0, 0.475, 0.475, 0, 0.5],
["C", 0, 0.5, -0.475, 0.475, -0.5, 0],
];
var path = _makePath(def, centerX, centerY, size, rotation, offsetX, offsetY, true);
this._setPath(layer, path);
}
}
});
}
function make() {
var layerClass = L.Path.extend({
options: {
fill: true,
shape: 'square',
radius: 10
},
initialize: function (latlng, options) {
L.setOptions(this, options);
this._latlng = L.latLng(latlng);
this._radius = this.options.radius;
},
setLatLng: function (latlng) {
this._latlng = L.latLng(latlng);
this.redraw();
return this.fire('move', { latlng: this._latlng });
},
getLatLng: function () {
return this._latlng;
},
setRadius: function (radius) {
this.options.radius = this._radius = radius;
return this.redraw();
},
getRadius: function () {
return this._radius;
},
setStyle: function (options) {
var radius = options && options.radius || this._radius;
L.Path.prototype.setStyle.call(this, options);
this.setRadius(radius);
return this;
},
_project: function () {
this._point = this._map.latLngToLayerPoint(this._latlng);
this._updateBounds();
},
_updateBounds: function () {
var r = this._radius,
r2 = this._radiusY || r,
w = this._clickTolerance(),
p = [r + w, r2 + w];
this._pxBounds = new L.Bounds(this._point.subtract(p), this._point.add(p));
},
_update: function () {
if (this._map) {
this._updatePath();
}
},
_updatePath: function () {
this._renderer._mzUpdateMarkers(this);
},
_empty: function () {
return this._radius && !this._renderer._bounds.intersects(this._pxBounds);
},
_containsPoint: function (p) {
return p.distanceTo(this._point) <= this._radius + this._clickTolerance();
}
});
return layerClass;
}
//---------------------------------------------------------
function _makePath(instructions, centerX, centerY, scale, rotation, offsetX, offsetY, close) {
_scale(instructions, scale);
if (rotation && rotation.angle != 0)
_rotate(instructions, rotation);
_translate(instructions, centerX, centerY);
_translate(instructions, offsetX, offsetY);
var path = "";
for (var i = 0; i < instructions.length; i++) {
var inst = instructions[i];
var type = inst[0];
if (type == "C")
path += "C " + inst[1] + " " + inst[2] + " " + inst[3] + " " + inst[4] + " " + inst[5] + " " + inst[6] + ",";
else
path += inst[0] + " " + inst[1] + " " + inst[2] + ",";
}
if (close)
path += "Z";
return path;
}
function _scale(instructions, scale) {
for (var i = 0; i < instructions.length; i++) {
var inst = instructions[i];
for (var j = 1; j < inst.length; j++) {
inst[j] *= scale;
}
}
}
function _rotate(instructions, rotation) {
var GJ = ns.GeoJson;
for (var i = 0; i < instructions.length; i++) {
var inst = instructions[i];
for (var j = 2; j < inst.length; j = j + 2) {
var x = inst[j - 1];
var y = inst[j];
var cos = Math.cos(GJ.Math.degreesToRadians(rotation.angle));
var sin = Math.sin(GJ.Math.degreesToRadians(rotation.angle));
var ox = rotation.originX;
var oy = rotation.originY;
inst[j - 1] = (x - ox) * cos - (y - oy) * sin;
inst[j] = (x - ox) * sin + (y - oy) * cos;
}
}
}
function _translate(instructions, x, y) {
for (var i = 0; i < instructions.length; i++) {
var inst = instructions[i];
for (var j = 1; j < inst.length; j++) {
if (j % 2 != 0)
inst[j] += x;
else inst[j] += y;
}
}
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.Leaflet = ns.Leaflet || {};
ns.Leaflet.PixelTransformer = PixelTransformer;
return ns;
//---------------------------------------------------------
function PixelTransformer(map) {
ns.Log.debug("Object created.", "PixelTransformer");
this.measureText = function (text, symbol) {
var style = ns.Leaflet.SymbolConverter.toCss(symbol);
var el;
if (!this._el) {
el = this._el = document.createElement("div");
document.body.appendChild(el);
}
else
el = this._el;
el.setAttribute("style", style);
el.style.position = "absolute";
el.style.left = "-1000px";
el.style.top = "-1000px";
el.innerHTML = text;
return { height: el.offsetHeight, width: el.offsetWidth };
}
this.translate = function (geometry) {
var type = geometry.type;
switch (type) {
case 'Point':
return _translatePoint(geometry);
case 'MultiPoint':
case "LineString":
case "MultiLineString":
case 'Polygon':
case 'MultiPolygon':
case 'GeometryCollection':
ns.Util.logAndThrow("Not yet implemented for type=" + type,
"PixelTransformer.translate()");
default:
ns.Util.logAndThrow("Unknown geometry type=" + type,
"PixelTransformer.translate()");
}
}
//---------------------------------------------------------
function _translatePoint(point) {
var coords = point.coordinates;
var latlng = new L.LatLng(coords[1], coords[0], coords[2]);
var point = map.latLngToLayerPoint(latlng);
return { x: point.x, y: point.y };
}
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.Leaflet = ns.Leaflet || {};
ns.Leaflet.RasterLayers = RasterLayers;
return ns;
//---------------------------------------------------------
function RasterLayers(map) {
var layers = [];
this.add = add;
this.show = show;
this.hide = hide;
this.sendBackwards = sendBackwards;
this.bringForwards = bringForwards;
this.remove = remove;
this.replace = replace;
ns.Log.debug("Object created.", "Leaflet.RasterLayers", map);
//-----------------------------------------------------
function add(layer, index) {
var key = layer.getKey();
var pane = map.createPane(key);
// panes[key] = pane;
//}
var zIndex = 399 - layers.length;
pane.style.zIndex = zIndex;
var options = {
pane: key,
_mz: {
pane: key,
key: layer.getKey(),
layer: layer,
zIndex: zIndex
},
attribution: layer.getAttribution(),
minZoom: 0,
maxZoom: 21
};
var leafletLayer = layer.isGreyScale() ?
new ns.Leaflet.GreyScaleTileLayer(layer.getUrl(), options) :
L.tileLayer(layer.getUrl(), options);
layers.push(leafletLayer);
if (!Mapzania.Util.isUndefined(index)) {
for (var i = layers.length - 1; i > index; i--) {
var key = at(i).options._mz.key;
bringForwards(key);
}
}
if (layer.isVisible())
leafletLayer.addTo(map);
}
function show(layerKey) {
var layer = get(layerKey);
if (!map.hasLayer(layer))
map.addLayer(layer);
}
function hide(layerKey) {
var layer = get(layerKey);
if (map.hasLayer(layer))
map.removeLayer(layer);
}
function get(layerKey) {
return layers.find(m => m.options._mz.key == layerKey);
}
function at(index) {
return layers[index];
}
function sendBackwards(layerKey) {
var layer = get(layerKey);
var index = indexOf(layer);
var from = at(index);
var to = at(index + 1);
var itm = layers[index];
layers[index] = layers[index + 1];
layers[index + 1] = itm;
setZ(from, index + 1);
setZ(to, index);
}
function bringForwards(layerKey) {
var layer = get(layerKey);
var index = indexOf(layer);
var from = at(index);
var to = at(index - 1);
var itm = layers[index];
layers[index] = layers[index - 1];
layers[index - 1] = itm;
setZ(from, index - 1);
setZ(to, index);
}
function indexOf(layer) {
return layers.indexOf(layer);
}
function replace(layerKey, layer) {
var idx = indexOf(get(layerKey));
remove(layerKey);
add(layer, idx);
}
//function remove(layerKey) {
// layer = get(layerKey);
// var idx = indexOf(layer);
// layers.splice(idx, 1);
// if (map.hasLayer(layer))
// map.removeLayer(layer);
//}
function remove(layerKey) {
var layer = get(layerKey);
var idx = indexOf(layer);
layers.splice(idx, 1);
if (map.hasLayer(layer)) {
map.removeLayer(layer);
delete map.getPanes()[layerKey];
map._paneRenderers = {};
var paneKey = "leaflet-" + layerKey + "-pane";
var el = document.getElementsByClassName(paneKey)[0];
el.parentNode.removeChild(el);
}
}
function setZ(layer, index) {
var z = 399 - index;
var mz = layer.options._mz;
mz.zIndex = z;
var paneKey = "leaflet-" + mz.key + "-pane";
var el = document.getElementsByClassName(paneKey)[0];
el.style.zIndex = z;
}
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.Leaflet = ns.Leaflet || {};
ns.Leaflet.SymbolConverter = {
convert: convert,
toCss: toCss
}
return ns;
//---------------------------------------------------------
function convert(symbol) {
if (!symbol)
ns.Util.logAndThrow("Null or undefined symbol.", "Leaflet.SymbolConverter.convert()");
switch (symbol.type) {
case "PointSymbol":
return _convertPointSymbol(symbol);
case "CompoundPointSymbol":
return _convertPointSymbol(symbol.points[symbol.points.length - 1]);
case "LineSymbol":
return _convertLineSymbol(symbol);
case "CompoundLineSymbol":
return _convertLineSymbol(symbol.lines[symbol.lines.length - 1]);
case "FillSymbol":
return _convertPolygonSymbol(symbol);
case "Labeller":
return _convertLabelSymbol(symbol);
default:
ns.Util.logAndThrow("Unknown SymbolType=" + symbol.type, "Leaflet.SymbolConverter.convert()");
}
}
function toCss(symbol) {
if (!symbol)
ns.Util.logAndThrow("Null or undefined symbol.", "Leaflet.SymbolConverter.toCss()");
switch (symbol.type) {
case "Labeller":
return _convertLabelSymbolToCss(symbol);
default:
ns.Util.logAndThrow("Unsupported SymbolType=" + symbol.type, "Leaflet.SymbolConverter.toCss()");
}
}
//---------------------------------------------------------
function _convertPointSymbol(symbol) {
var patterns = ["circle", "square", "triangle", "cross", "diamond", "crosshair", "chevron"];
var strokePatterns = ["solid", "10,5", "1,3"];
var result = {
pattern: patterns[symbol.pattern],
fillColor: symbol.color,
fillOpacity: 1.0,
radius: symbol.size,
stroke: false,
rotation: symbol.rotation,
offset: symbol.offset,
}
if (symbol.strokeWidth > 0) {
result.stroke = true;
result.color = symbol.strokeColor;
result.weight = symbol.strokeWidth;
var pat = symbol.strokePattern;
result.dashArray = pat ? strokePatterns[pat] : strokePatterns[0];
}
return result;
}
function _convertLineSymbol(symbol) {
//var patterns = ["solid", "dash", "dots"];
var patterns = ["solid", "10,5", "1,3"];
var endcaps = ["round", "butt", "square"];
var joins = ["round", "bevel", "mitre"];
return {
color: symbol.color,
weight: symbol.size,
lineCap: symbol.endCap ? endcaps[symbol.endCap] : endcaps[0],
lineJoin: symbol.join ? joins[symbol.join] : joins[0],
dashArray: symbol.pattern ? patterns[symbol.pattern] : patterns[0]
}
}
function _convertPolygonSymbol(symbol) {
//var patterns = ["solid", "dash", "dots"];
var patterns = ["solid", "10,5", "1,3"];
var endcaps = ["round", "butt", "square"];
var joins = ["round", "bevel", "mitre"];
var fillColor = symbol.color;
var result = {
fill: fillColor,
fillOpacity: 1.0,
fillColor: fillColor,
stroke: false
}
return result;
}
function _convertLabelSymbol(symbol) {
return symbol;
}
function _convertLabelSymbolToCss(symbol) {
var values = {
"position": "absolute",
"white-space": "nowrap",
"color": symbol.color,
"font-size": symbol.fontSize + "px",
"font-family": symbol.fontFamily,
"padding": "0px",
//"display":"inline",
"cursor": "inherit"
};
if (symbol.bold)
values["font-weight"] = "bold";
if (symbol.italic)
values["font-style"] = "italic";
if (symbol.haloThickness) {
var shadow = "0 0 " + symbol.haloThickness + "pt " + symbol.haloColor;
values["text-shadow"] = shadow + "," + shadow + "," + shadow;
}
var res = "";
for (key in values) {
res += key + ":" + values[key] + ";";
}
return res;
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.Leaflet = ns.Leaflet || {};
ns.Leaflet.VectorLayers = VectorLayers;
return ns;
//---------------------------------------------------------
function VectorLayers(map) {
var layers = [];
//var panes = {};
this.add = add;
this.show = show;
this.hide = hide;
this.sendBackwards = sendBackwards;
this.bringForwards = bringForwards;
this.remove = remove;
this.replace = replace;
this.draw = draw;
ns.Log.debug("Object created.", "Leaflet.VectorLayers", map);
//-----------------------------------------------------
function add(layer, index) {
var key = layer.getKey();
//var pane = panes[key];
//if (!pane) {
var pane = map.createPane(key);
// panes[key] = pane;
//}
var zIndex = 499 - layers.length;
pane.style.zIndex = zIndex;
var leafletLayer = L.geoJSON(null, {
pane: key,
attribution: layer.getAttribution(),
_mz: {
pane: pane,
key: key,
layer: layer,
zIndex: zIndex
},
style: function (feature) {
return ns.Leaflet.SymbolConverter.convert(feature.symbol);
},
pointToLayer: function (feature, latlng) {
var options = ns.Leaflet.SymbolConverter.convert(feature.symbol);
Object.assign(options, {
pane: pane,
map: map
});
return new ns.Leaflet.MarkerLayer(latlng, options);
}
})
layers.push(leafletLayer);
if (!Mapzania.Util.isUndefined(index)) {
for (var i = layers.length - 1; i > index; i--) {
var key = at(i).options._mz.key;
bringForwards(key);
}
}
if (layer.isVisible())
leafletLayer.addTo(map);
}
function show(layerKey) {
var layer = get(layerKey);
if (!map.hasLayer(layer))
map.addLayer(layer);
}
function hide(layerKey) {
var layer = get(layerKey);
if (map.hasLayer(layer))
map.removeLayer(layer);
}
function get(layerKey) {
return layers.find(m => m.options._mz.key == layerKey);
}
function at(index) {
return layers[index];
}
function sendBackwards(layerKey) {
var layer = get(layerKey);
var index = indexOf(layer);
var from = at(index);
var to = at(index + 1);
var itm = layers[index];
layers[index] = layers[index + 1];
layers[index + 1] = itm;
setZ(from, index + 1);
setZ(to, index);
}
function bringForwards(layerKey) {
var layer = get(layerKey);
var index = indexOf(layer);
var from = at(index);
var to = at(index - 1);
var itm = layers[index];
layers[index] = layers[index - 1];
layers[index - 1] = itm;
setZ(from, index - 1);
setZ(to, index);
}
function indexOf(layer) {
return layers.indexOf(layer);
}
function replace(layerKey, layer) {
var idx = indexOf(get(layerKey));
remove(layerKey);
add(layer, idx);
}
function draw(layerKey, data) {
var layer = get(layerKey);
layer.clearLayers();
layer.addData(data);
}
function remove(layerKey) {
var layer = get(layerKey);
var idx = indexOf(layer);
layers.splice(idx, 1);
if (map.hasLayer(layer)) {
map.removeLayer(layer);
delete map.getPanes()[layerKey];
map._paneRenderers = {};
var paneKey = "leaflet-" + layerKey + "-pane";
var el = document.getElementsByClassName(paneKey)[0];
el.parentNode.removeChild(el);
}
}
function setZ(layer, index) {
var z = 499 - index;
var mz = layer.options._mz;
mz.zIndex = z;
var paneKey = "leaflet-" + mz.key + "-pane";
var el = document.getElementsByClassName(paneKey)[0];
el.style.zIndex = z;
}
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.Leaflet = ns.Leaflet || {};
ns.Leaflet.View = View;
return ns;
//---------------------------------------------------------
function View(elementId, settings) {
var view = this;
var GJ = ns.GeoJson;
ns.Util.eventify(this, "Leaflet.View");
validate();
var map = L.map(elementId, { zoomControl: false });
//PN**
map.options.minZoom = settings.minZoom;
map.options.maxZoom = settings.maxZoom;
addControls();
addEvents();
var vlayers = new ns.Leaflet.VectorLayers(map);
var rlayers = new ns.Leaflet.RasterLayers(map);
var labelLayer = createLabelLayer();
var selectorLayer = createSelectorLayer();
//---------------------- STARTUP --------------------------
function validate() {
if (typeof L == "undefined")
ns.Util.logAndThrow("Mapzania cannot continue because Leaflet is not installed.", "Leaflet.View");
else
ns.Log.debug("Object created.", "Leaflet.View");
}
function addControls() {
view.toolbar = new ns.Leaflet.Toolbar();
map.addControl(view.toolbar);
}
function addEvents() {
map.on("moveend", function (event) {
view.fire("changed", view.getState());
});
map.on("click", function (e) {
view.fire("clicked", {
position: { type: "Point", coordinates: [e.latlng.lng, e.latlng.lat] },
pixel: { x: e.layerPoint.x, y: e.layerPoint.y }
});
})
map.on("dblclick", function (e) {
view.fire("double_clicked", {
position: { type: "Point", coordinates: [e.latlng.lng, e.latlng.lat] },
pixel: { x: e.layerPoint.x, y: e.layerPoint.y }
});
})
}
//---------------------- FACTORY --------------------------
this.getPixelTransformer = function () {
return new ns.Leaflet.PixelTransformer(map);
}
//------------------------ MAP ----------------------------
this.getViewer = function () {
return map;
}
this.getState = function () {
var bounds = ns.Leaflet.Convert.latLngBoundsToBBox(map.getBounds());
var pixelBounds = ns.Leaflet.Convert.pixelBoundsToBBox(map.getPixelBounds());
var center = map.getCenter();
return {
bounds: bounds,
pixelBounds: pixelBounds,
zoom: map.getZoom(),
center: { latitude: center.lat, longitude: center.lng }
};
}
this.fitToBoundingBox = function (bbox) {
map.fitBounds([[bbox[1], bbox[0]], [bbox[3], bbox[2]]]);
}
this.zoomIn = function () {
map.zoomIn(1);
}
this.zoomOut = function () {
map.zoomOut(1);
}
//PN**
this.setMinZoom = function (zoom) {
map.setMinZoom(zoom);
}
//PN**
this.setMaxZoom = function (zoom) {
map.setMaxZoom(zoom);
}
//PN**
this.getMinZoom = function (zoom) {
map.getMinZoom(zoom);
}
//PN**
this.getMaxZoom = function (zoom) {
map.getMaxZoom(zoom);
}
this.setMouseMode = function (mode) {
selectorLayer.clearLayers();
switch (mode) {
case ns.MouseModes.Pan:
map.doubleClickZoom.enable();
document.getElementById(elementId).style.cursor = "-webkit-grab";
break;
case ns.MouseModes.Query: //TODO
break;
case ns.MouseModes.DrawPoint:
case ns.MouseModes.DrawLine:
case ns.MouseModes.DrawPolygon:
map.doubleClickZoom.disable();
document.getElementById(elementId).style.cursor = "crosshair";
break;
}
}
this.setBackColor = function (color) {
document.getElementById(elementId).style.backgroundColor = color;
}
this.setControls = function (controls) {
if (controls.scale && controls.scale.show)
L.control.scale(controls.scale).addTo(map);
if (controls.legend && controls.legend.show) {
L.control.layers(null, null, controls.legend).addTo(map);
}
if (controls.info && controls.info.show) {
var control = new ns.Leaflet.InfoControl();
map.addControl(control);
}
}
//----------------------LAYERS-----------------------------
this.addLayer = function (layer, index) {
switch (layer.getType()) {
case "VectorLayer":
vlayers.add(layer, index);
break;
case "RasterLayer":
rlayers.add(layer, index);
break;
default:
throw ("Unknown layer type");
}
}
this.showLayer = function (layer) {
switch (layer.getType()) {
case "VectorLayer":
vlayers.show(layer.getKey());
break;
case "RasterLayer":
rlayers.show(layer.getKey());
break;
default:
throw ("Unknown layer type");
}
}
this.hideLayer = function (layer) {
switch (layer.getType()) {
case "VectorLayer":
vlayers.hide(layer.getKey());
break;
case "RasterLayer":
rlayers.hide(layer.getKey());
break;
default:
throw ("Unknown layer type");
}
}
this.removeLayer = function (layer) {
switch (layer.getType()) {
case "VectorLayer":
vlayers.remove(layer.getKey());
break;
case "RasterLayer":
rlayers.remove(layer.getKey());
break;
default:
throw ("Unknown layer type");
}
}
this.sendLayerBackwards = function (layer) {
switch (layer.getType()) {
case "VectorLayer":
vlayers.sendBackwards(layer.getKey());
break;
case "RasterLayer":
rlayers.sendBackwards(layer.getKey());
break;
default:
throw ("Unknown layer type");
}
}
this.bringLayerForwards = function (layer) {
switch (layer.getType()) {
case "VectorLayer":
vlayers.bringForwards(layer.getKey());
break;
case "RasterLayer":
rlayers.bringForwards(layer.getKey());
break;
default:
throw ("Unknown layer type");
}
}
this.replaceLayer = function (layerKey, layer) {
switch (layer.getType()) {
case "VectorLayer":
vlayers.replace(layerKey, layer);
break;
case "RasterLayer":
rlayers.replace(layerKey, layer);
break;
default:
throw ("Unknown layer type");
}
}
this.drawLayer = function (layer, data) {
switch (layer.getType()) {
case "VectorLayer":
vlayers.draw(layer.getKey(), data);
break;
case "RasterLayer":
throw ("drawLayer should not be called for RasterLayers");
default:
throw ("Unknown layer type");
}
}
this.drawLabels = function (data) {
labelLayer.clearLayers();
labelLayer.addLabels(data);
}
this.drawSelector = function (feature) {
view.toDraw = feature;
//hack to allow dblclick event to propogate
setTimeout(function () {
if (!view.toDraw) {
selectorLayer.clearLayers();
return;
}
if (feature.type == "LineString") {
view.toDraw = { type: "FeatureCollection", features: [] };
view.toDraw.features.push(feature);
for (var i = 0; i < feature.coordinates.length; i++) {
view.toDraw.features.push(GJ.createPoint(feature.coordinates[i]));
}
}
if (feature.type == "Polygon") {
view.toDraw = { type: "FeatureCollection", features: [] };
view.toDraw.features.push(feature);
for (var i = 0; i < feature.coordinates[0].length; i++) {
view.toDraw.features.push(GJ.createPoint(feature.coordinates[0][i]));
}
}
selectorLayer.clearLayers();
selectorLayer.addData(view.toDraw);
}, 100);
}
//---------------------- TOOLBAR --------------------------
this.Toolbar = {
addButton: function (button) {
view.toolbar.addButton(button);
}
};
//---------------------------------------------------------
function createLabelLayer() {
var key = "MZ_LABELS";
var index = 625;
var pane = map.createPane(key);
pane.style.zIndex = index;
var layer = new ns.Leaflet.LabelLayer({ pane: key });
layer.addTo(map);
return layer;
}
function createSelectorLayer() {
var key = "MZ_SELECTOR";
var index = 800;
var pane = map.createPane(key);
pane.style.zIndex = index;
var layer = L.geoJSON(null, {
pane: key,
style: function (feature) {
return {
color: "#000000",
fillColor: "#FFFF00",
weight: 2,
radius: 5
}
},
pointToLayer: function (feature, latlng) {
return L.circleMarker(latlng, { pane: key });
}
});
layer.addTo(map);
return layer;
}
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.DefaultTheme = DefaultTheme;
return ns;
//---------------------------------------------------------
function DefaultTheme() {
ns.Log.debug("Object created.", "DefaultTheme");
this.getType = function () {
return "DefaultTheme";
}
this.getMinZoom = function () {
return 0;
};
this.getMaxZoom = function () {
return 100;
};
this.getSymbol = function (feature) {
switch (feature.geometry.type) {
case "Point":
case "MultiPoint":
return ns.Symbols._defaultPoint;
case "LineString":
case "MultiLineString":
return ns.Symbols._defaultLine;
case "Polygon":
case "MultiPolygon":
return ns.Symbols._defaultPolygon;
default:
ns.Util.logAndThrow("Unknown geometry type=" + feature.geometry.type,
"DefaultTheme.getStyle()");
}
}
this.getLabelText = function (feature) {
return null;
}
this.getLabeller = function (feature) {
return ns.Symbols._defaultLabeller;
}
this.getFilterText = function () {
return null;
}
}
})(Mapzania || {})
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.DynamicTheme = DynamicTheme;
return ns;
//---------------------------------------------------------
function DynamicTheme(style) {
//HACKY: use last symbols and labellers for "converting" to server-side theme
var lastSymbol, lastLabeller;
validateStyle(style);
setStyleDefaults(style);
ns.Log.debug("Object created.", "DynamicTheme");
this.getType = function () {
return "DynamicTheme";
}
this.getMinZoom = function () {
return 1;
};
this.getMaxZoom = function () {
return 25;
};
this.getSymbol = function (feature) {
var symbol;
if (ns.Util.isFunction(style))
symbol = style(feature.properties);
else
symbol = style;
var res;
switch (feature.geometry.type) {
case "Point":
case "MultiPoint":
res = ns.Symbols.createPoint(symbol);
break;
case "LineString":
case "MultiLineString":
res = ns.Symbols.createLine(symbol);
break;
case "Polygon":
case "MultiPolygon":
res = ns.Symbols.createPolygon(symbol);
break;
default:
ns.Util.logAndThrow("Unknown geometry type=" + feature.geometry.type,
"DynamicTheme.getStyle()");
}
lastSymbol = res;
return res;
}
this.getLabelText = function (feature) {
var symbol;
var props = feature.properties;
if (ns.Util.isFunction(style))
symbol = style(feature);
else
symbol = style;
if (symbol.labelText)
return symbol.labelText;
if (symbol.labelField)
return props[symbol.labelField];
if (!symbol.label)
return null;
if (symbol.label.text)
return symbol.label.text;
if (symbol.label.field)
return props[symbol.label.field];
return null;
}
this.getLabeller = function (feature) {
//label: {
// color: "#000000",
// fontSize: 12,
// fontWeight: "bold",
// field: "Name"
//}
var res = ns.Util.assign({}, ns.Symbols._defaultLabeller);
var symbol;
var props = feature.properties;
if (ns.Util.isFunction(style))
symbol = style(feature);
else
symbol = style;
var label = symbol.label;
if (label)
res = ns.Util.assign(res, label);
lastLabeller = res;
return res;
}
this.getFilterText = function () {
return null;
}
//---------------------------------------------------------
function validateStyle(style) {
if (!style)
throw "Style cannot be undefined or null.";
var sc = style.strokeColor;
var so = style.strokeOpacity;
var sw = style.strokeWidth;
var isArray = ns.Util.isArray;
if (isArray(sc) || isArray(so) || isArray(sw)) {
if (!(isArray(sc) && isArray(so) && isArray(sw)))
throw "If one stroke property is an array, all stroke properties must be arrays.";
if (sc.length != so.length || sc.length != sw.length)
throw "All stroke property arrays must be the same length";
}
}
function setStyleDefaults (style) {
if (ns.Util.isNullOrUndefined(style.size))
style.size = 10;
if (ns.Util.isNullOrUndefined(style.strokeColor))
style.strokeColor = "#000000";
if (ns.Util.isNullOrUndefined(style.strokeOpacity))
style.strokeOpacity = 1;
if (ns.Util.isNullOrUndefined(style.strokeWidth))
style.strokeWidth = 1;
if (ns.Util.isNullOrUndefined(style.fillColor)) {
style.fillColor = "rgba(0,0,0,0)";
}
}
this.toJSON = function () {
return {
type: "Theme",
minZoom: 0,
maxZoom: 30,
filter: this.getFilterText(),
labeller: lastLabeller,
scaleType: null,
field: null,
values: [],
symbology: 0,
symbol: lastSymbol
}
}
}
})(Mapzania || {})
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.LayerThemer = LayerThemer;
return ns;
//---------------------------------------------------------
function LayerThemer() {
var themes = [];
var dynamicTheme;
var featureStyles = {};
ns.Log.debug("Object created.", "LayerThemer");
//-------------------MANAGEMENT------------------------
this.addTheme = function (theme) {
themes.push(theme);
}
this.addThemeJson = function (themeJson) {
var theme = createTheme(themeJson);
this.addTheme(theme);
}
this.setDynamicTheme = function (style) {
dynamicTheme = new ns.DynamicTheme(style);
}
this.removeDynamicTheme = function () {
dynamicTheme = null;
}
this.updateTheme = function (index, themeJson) {
themes[index] = createTheme(themeJson);
}
this.removeTheme = function (index) {
themes.splice(index, 1);
}
this.setFeatureStyle = function (id, style) {
featureStyles[id] = style;
}
this.clearFeatureStyle = function (id) {
delete featureStyles[id];
}
//-------------------QUERY-----------------------------
this.getTheme = function (zoom, id) {
var isNoU = ns.Util.isNullOrUndefined;
// Does single feature styling apply?
if (!isNoU(id) && !isNoU(featureStyles[id]))
return new ns.DynamicTheme(featureStyles[id]);
if (!isNoU(dynamicTheme))
return dynamicTheme;
if (themes.length == 0)
return new ns.DefaultTheme();
for (var i = themes.length - 1; i >= 0; i--) {
var theme = themes[i];
var minZoom = theme.getMinZoom();
var maxZoom = theme.getMaxZoom();
if (zoom >= minZoom && zoom <= maxZoom)
return theme;
}
return null;
}
this.getFilterText = function (zoom) {
var theme = this.getTheme(zoom);
if (theme)
return theme.getFilterText();
return null;
}
//-------------------OTHER-----------------------------
this.toJSON = function () {
if (!ns.Util.isNullOrUndefined(dynamicTheme))
return [dynamicTheme.toJSON()];
return themes.map(theme => theme.toJSON());
}
//----------------------------------------------------
function indexOfThemeType(type) {
return themes.findIndex(function (m) {
m.getType() == type;
});
}
function createTheme(themeJson) {
if (themeJson.type == "StandardTheme")
return new ns.StandardTheme(themeJson);
if (themeJson.type == "RangeTheme")
return new ns.RangeTheme(themeJson);
if (themeJson.type == "Theme")
return new ns.Theme(themeJson);
else
ns.Util.logAndThrow("Unknown theme type=" + themeJson.type, "LayerThemer.createTheme()");
}
}
})(Mapzania || {})
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.RangeTheme = RangeTheme;
return ns;
//---------------------------------------------------------
function RangeTheme(json) {
//TODO: Normalisation
var symbols = {};
ns.Log.debug("Object created.", "RangeTheme");
this.getType = function () {
return "RangeTheme";
}
this.getMinZoom = function () {
return json.minZoom;
};
this.getMaxZoom = function () {
return json.maxZoom;
};
this.getSymbol = function (feature) {
var val = getThemeValue(feature);
if (val && val.symbol)
return val.symbol;
else
return json.symbol;
}
this.getLabelText = function (feature) {
var labeller = null;
var themeValue = getThemeValue(feature);
if (themeValue && themeValue.labeller) {
labeller = themeValue.labeller;
} else {
labeller = json.labeller;
}
if (!labeller)
return null;
return feature.properties[labeller.field];
}
this.getLabeller = function (feature) {
var themeValue = getThemeValue(feature);
if (themeValue && themeValue.labeller && themeValue.labeller.visible) {
return themeValue.labeller;
} else {
if (!json.labeller || !json.labeller.visible)
return null;
return json.labeller;
}
}
this.getFilterText = function () {
return json.filter;
}
this.toJSON = function () {
return ns.Util.assign({}, json);
}
//---------------------------------------------------------
function getThemeValue(feature) {
var featVal = feature.properties[json.field];
for (var i = 0; i < json.values.length; i++) {
var themeVal = json.values[i];
if (themeVal.value) { // unique range
if (equalsIgnoreCase(featVal, themeVal.value)) {
return themeVal;
}
} else { // range
if (featVal >= themeVal.min && featVal <= themeVal.max) {
return themeVal;
}
}
}
return null;
}
var equalsIgnoreCase = function (s1, s2) {
s1 = s1 ? String(s1) : "";
s2 = s2 ? String(s2) : "";
return s1.toUpperCase().trim() == s2.toUpperCase().trim();
};
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.StandardTheme = StandardTheme;
return ns;
//---------------------------------------------------------
function StandardTheme(json) {
_heal(json.labeller);
ns.Log.debug("Object created.", "StandardTheme");
this.getType = function () {
return "StandardTheme";
}
this.getMinZoom = function () {
return json.minZoom;
};
this.getMaxZoom = function () {
return json.maxZoom;
};
this.getSymbol = function (feature) {
return json.symbol;
}
this.getLabelText = function (feature) {
var labeller = json.labeller;
if (!labeller)
return null;
return feature.properties[labeller.field];
}
this.getLabeller = function (feature) {
if (json.labeller && json.labeller.visible)
return json.labeller;
return null;
}
this.getFilterText = function () {
return json.filter;
}
function _heal(labeller) {
var isNull = ns.Util.isNullOrUndefined;
if (!isNull(labeller) && isNull(labeller.collisionDetection))
labeller.collisionDetection = true;
}
this.toJSON = function () {
return ns.Util.assign({}, json);
}
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.Symbols = {
_defaultPoint: _defaultPoint(),
_defaultLine: _defaultLine(),
_defaultPolygon: _defaultPolygon(),
_defaultLabeller: _defaultLabeller(),
createPoint: createPoint,
createLine: createLine,
createPolygon: createPolygon,
createLabel: createLabel
}
return ns;
//---------------------------------------------------------
function createPoint(style) {
return _createPointSymbol(
style.fillColor,
style.strokeColor,
style.strokeWidth,
style.size
);
}
function createLine(style) {
return _createLineSymbol(style.strokeColor, style.strokeWidth);
}
function createPolygon(style) {
return _createFillSymbol(
style.fillColor,
style.strokeColor,
style.strokeWidth
);
}
function createLabel(label) {
var isBold = label.fontWeight && label.fontWeight.toLowerCase() == "bold";
var res = {
type: "LabelSymbol",
color: label.fill,
bold: isBold,
fontSize: 10,
rotation: 0,
fontFamily: "arial",
offset: { x: 0, y: 0 },
field: label.field,
alignment: 0
};
return res;
}
//---------------------------------------------------------
function _defaultPoint() {
return _createPointSymbol("#000000", "rgba(0,0,0,0)", 0, 3);
}
function _defaultLine() {
return _createLineSymbol("#000000", 1);
}
function _defaultPolygon() {
return _createFillSymbol("rgba(0, 0, 0, 0.2)", "#000000", 1);
}
function _defaultLabeller() {
return {
type: "Labeller",
color: "#000000",
bold: false,
italic: false,
fontSize: 10,
fontFamily: "arial",
rotation: 0,
alignment: 0
//haloColor: "#FFFFFF",
//haloThickness: 1.6,
//offset: { x: 0, y: -12 },
};
}
function _createPointSymbol(fillColor, strokeColor, strokeWidth, size) {
return {
type: "CompoundPointSymbol",
drawByLayer: true,
points: [
{
type: "PointSymbol",
pattern: 0,
size: size,
color: fillColor,
border: _createLineSymbol(strokeColor, strokeWidth),
rotation: {},
offset: { x: 0, y: 0 },
rotation: { angle: 0, originX: 0, originY: 0 }
}
]
};
}
function _createFillSymbol(fillColor, strokeColor, strokeWidth) {
return {
type: "FillSymbol",
color: fillColor,
outline: _createLineSymbol(strokeColor, strokeWidth)
}
}
function _createLineSymbol(color, size) {
return {
type: "CompoundLineSymbol",
drawByLayer: true,
lines: [
{
type: "LineSymbol",
pattern: 0,
color: color,
size: size
}
]
};
}
})(Mapzania || {})
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.Theme = Theme;
return ns;
//---------------------------------------------------------
function Theme(json) {
//TODO: Normalisation
var symbols = {};
ns.Log.debug("Object created.", "Theme");
this.getType = function () {
return "Theme";
}
this.getMinZoom = function () {
return json.minZoom;
};
this.getMaxZoom = function () {
return json.maxZoom;
};
this.getSymbol = function (feature) {
var val = _getThemeValue(feature);
if (val && val.symbol)
return val.symbol;
else
return json.symbol;
}
this.getLabelText = function (feature) {
var labeller = json.labeller;
if (!labeller)
return null;
return feature.properties[labeller.field];
}
this.getLabeller = function (feature) {
if (json.labeller && json.labeller.visible)
return json.labeller;
return null;
}
this.getFilterText = function () {
return json.filter;
}
this.toJSON = function () {
return ns.Util.assign({}, json);
}
//---------------------------------------------------------
function _getThemeValue(feature) {
var featVal = feature.properties[json.field];
if (json.values) {
for (var i = 0; i < json.values.length; i++) {
var themeVal = json.values[i];
if (themeVal.value) { // unique range
if (equalsIgnoreCase(featVal, themeVal.value)) {
return themeVal;
}
} else { // range
if (featVal >= themeVal.min && featVal <= themeVal.max) {
return themeVal;
}
}
}
}
return null;
}
var equalsIgnoreCase = function (s1, s2) {
s1 = s1 ? String(s1) : "";
s2 = s2 ? String(s2) : "";
return s1.toUpperCase().trim() == s2.toUpperCase().trim();
};
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.Log = new Logger();
return ns;
//---------------------------------------------------------
function Logger() {
this.debugEnabled = false;
this.message = function (msg, module, object) {
log("Message", msg, module, object)
}
this.error = function (msg, module, object) {
log("ERROR", msg, module, object);
}
this.debug = function (msg, module, object) {
if (!this.debugEnabled)
return;
log("Debug", msg, module, object);
}
function log(name, msg, module, obj) {
var mod = module || "App";
console.log("Mapzania/" + name + ":" + mod + ":" + msg);
if (obj)
console.log(obj);
}
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.Timer = Timer;
return ns;
//---------------------------------------------------------
function Timer() {
var count = 0;
var time_ms = 0;
//-----------------------------------------------------
this.start = function () {
count++;
this.start_time = new Date();
}
this.stop = function () {
time_ms += ((new Date()) - this.start_time);
}
this.describe = function () {
if (count == 0)
return "0"
else
if (count == 1)
return "Time (ms) = " + (time_ms)
else
return "[Count = " + count + ", Avg Time (ms) = " + (time_ms / count) + "]";
}
}
})(Mapzania || {});
///
var Mapzania = (function (ns) {
//---------------------------------------------------------
ns.Util = {
arrayAppend: arrayAppend,
createPseudoGuid: createPseudoGuid,
truncate: truncate,
startsWith: startsWith,
endsWith: endsWith,
isFunction: isFunction,
isString: isString,
isNumeric: isNumeric,
isObject: isObject,
isArray: isArray,
isNull: isNull,
isUndefined: isUndefined,
isNullOrUndefined: isNullOrUndefined,
clone: clone,
extend: extend,
assign: assign,
deepMerge: deepMerge,
eventify: eventify,
logAndThrow: logAndThrow
};
return ns;
//---------------------------------------------------------
function arrayAppend(source, destination) {
Array.prototype.push.apply(destination, source);
}
function createPseudoGuid() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
};
function truncate(x) {
return x < 0 ? Math.ceil(x) : Math.floor(x);
};
function startsWith(str, subStr) {
return str.slice(0, subStr.length) == subStr;
};
function endsWith(str, subStr) {
return str.slice(-subStr.length) == subStr;
};
function isFunction(item) {
return item instanceof Function;
};
function isString(item) {
return typeof item === 'string' || item instanceof String;
};
function isNumeric(item) {
return !isNaN(parseFloat(item)) && isFinite(item);
}
function isObject(item) {
if (item === null)
return false;
return ((typeof item === 'function') || (typeof item === 'object'));
}
function isArray(item) {
if (Array.isArray)
return Array.isArray(item);
return item instanceof Array;
};
function isNull(item) {
return item === null;
}
function isUndefined(item) {
return typeof item === 'undefined';
}
function isNullOrUndefined(item) {
return isNull(item) || isUndefined(item);
}
function clone(object) {
return JSON.parse(JSON.stringify(object));
}
function extend() {
// Setup extended object
var extended = {};
// Merge the object into the extended object
var merge = function (obj) {
for (var prop in obj) {
if (Object.prototype.toString.call(obj[prop]) === '[object Object]') {
extended[prop] = extend(true, extended[prop], obj[prop]);
} else {
extended[prop] = obj[prop];
}
}
};
// Loop through each object and conduct a merge
for (var i = 0; i < arguments.length; i++) {
var obj = arguments[i];
merge(obj);
}
return extended;
};
function merge(target, ...sources) {
sources.forEach(function (source) {
if (isObject(source)) {
for (var key in source) {
if (source[key] != null && (typeof source[key] === 'object')) {
if (!target[key]) {
var temp = {};
temp[key] = {};
Object.assign(target, temp); // { [key] = {}});
}
merge(target[key], source[key]);
} else if (source[key] != null && typeof target[key] === 'function') {
target[key] = source[key];
} else {
var temp = {};
temp[key] = source[key];
Object.assign(target, temp);// { [key] = source[key]});
}
}
}
});
return target;
}
function deepMerge(target, source) {
function isMergeableObject(val) {
var nonNullObject = val && typeof val === 'object'
return nonNullObject
&& Object.prototype.toString.call(val) !== '[object RegExp]'
&& Object.prototype.toString.call(val) !== '[object Date]'
}
function emptyTarget(val) {
return Array.isArray(val) ? [] : {}
}
function cloneIfNecessary(value, optionsArgument) {
var clone = optionsArgument && optionsArgument.clone === true
return (clone && isMergeableObject(value)) ? deepmerge(emptyTarget(value), value, optionsArgument) : value
}
function defaultArrayMerge(target, source, optionsArgument) {
var destination = target.slice()
source.forEach(function (e, i) {
if (typeof destination[i] === 'undefined') {
destination[i] = cloneIfNecessary(e, optionsArgument)
} else if (isMergeableObject(e)) {
destination[i] = deepmerge(target[i], e, optionsArgument)
} else if (target.indexOf(e) === -1) {
destination.push(cloneIfNecessary(e, optionsArgument))
}
})
return destination
}
function mergeObject(target, source, optionsArgument) {
var destination = {}
if (isMergeableObject(target)) {
Object.keys(target).forEach(function (key) {
destination[key] = cloneIfNecessary(target[key], optionsArgument)
})
}
Object.keys(source).forEach(function (key) {
if (!isMergeableObject(source[key]) || !target[key]) {
destination[key] = cloneIfNecessary(source[key], optionsArgument)
} else {
destination[key] = deepmerge(target[key], source[key], optionsArgument)
}
})
return destination
}
function deepmerge(target, source, optionsArgument) {
var array = Array.isArray(source);
var options = optionsArgument || { arrayMerge: defaultArrayMerge }
var arrayMerge = options.arrayMerge || defaultArrayMerge
if (array) {
return Array.isArray(target) ? arrayMerge(target, source, optionsArgument) : cloneIfNecessary(source, optionsArgument)
} else {
return mergeObject(target, source, optionsArgument)
}
}
deepmerge.all = function deepmergeAll(array, optionsArgument) {
if (!Array.isArray(array) || array.length < 2) {
throw new Error('first argument should be an array with at least two elements')
}
// we are sure there are at least 2 values, so it is safe to have no initial value
return array.reduce(function (prev, next) {
return deepmerge(prev, next, optionsArgument)
})
}
return deepmerge(target, source);
}
function assign(...args) {
var extended = args.shift();
if (typeof extended === "boolean" && extended === true) {
// recursively merge all the properties
return merge(...args);
} else {
// Get an object that behaves the same
return Object.assign(extended, ...args);
}
};
function eventify(obj, name) {
obj.listeners = [];
obj._eventify_name = name;
obj.on = function (type, fn) {
this.listeners.push({
type: type,
once: false,
fn: fn
});
}
obj.onAll = function (fn) {
obj.on("_ON_ALL_", fn);
}
obj.once = function (type, fn) {
this.listeners.push({
type: type,
once: true,
fn: fn
});
}
obj.off = function (type) {
for (var i = this.listeners.length - 1; i >= 0 ; i--) {
var l = this.listeners[i];
if (l.type == type)
this.listeners.splice(i, 1);
}
}
obj.fire = function (type, data) {
var text = type + " fired. (" + this.listeners.length + " listeners)";
Mapzania.Log.debug(text, this._eventify_name, data);
for (var i = this.listeners.length - 1; i >= 0 ; i--) {
var l = this.listeners[i];
if (l.type == "_ON_ALL_") {
l.fn({
type: type,
data: data
});
}
if (l.type == type) {
l.fn(data);
if (l.once)
this.listeners.splice(i, 1);
}
}
}
}
function logAndThrow(msg, module, object) {
ns.Log.error(msg, module, object);
throw msg;
}
})(Mapzania || {})