facilmap/frontend/app/map/map.js

449 wiersze
14 KiB
JavaScript

(function(fp, $, ng, fm, ol, undefined) {
fp.app.directive("fpMap", [ "fpMap", function(fpMap) {
return {
restrict: 'EA',
link: function(scope, element, attrs) {
fpMap.initMap(element, attrs.id, attrs.fpPadId);
}
};
} ]);
fp.app.factory("fpMap", function(fpUtils, fpSocket, fpMapMessages, fpDialogs, fpMapMarkers, fpMapPopups, $templateCache, $compile, fpMapLines, fpMapTypes, fpMapViews, $rootScope, fpMapPad, fpMapToolbox, $timeout, fpMapLegend, fpMapSearch, fpMapGpx) {
var maps = { };
var ret = { };
ret.getMap = function(id) {
return maps[id];
};
ret.initMap = function(el, id, padId) {
return maps[id] = new Map(el, id, padId);
};
return ret;
function Map(replaceEl, id, padId) {
var map = this;
map.mapEvents = $rootScope.$new(true); /* Event types: clickMarker, clickLine, click, move, moveEnd, mouseMove */
map.socket = fpSocket(padId);
map.socket.id = id; // To be in scope for template
map.markersById = { };
map.linesById = { };
var el = $($templateCache.get("map/map.html"));
replaceEl.replaceWith(el);
$compile(el)(map.socket);
map.map = new FacilMap.Map(el[0], {
attributionIcon: new ol.Icon("assets/img/logo.png", new ol.Size(191, 176), new ol.Pixel(-37, -131))
});
$(map.map.attributionIcon.imageDiv).css({ overflow: "hidden", height: "131px" });
// Map ID is not set yet as scope is not digested. So styles might change.
$timeout(map.map.updateSize.bind(map.map));
map.map.addLayer(new fm.Layer.OSM.MapSurfer.Road(ol.i18n("MapSurfer Road"), { permalinkName : "MSfR" }));
map.map.addLayer(new fm.Layer.OSM.Mapnik(ol.i18n("Mapnik"), { permalinkName : "Mpnk" }));
map.map.addLayer(new fm.Layer.OSM.CycleMap(ol.i18n("OpenCycleMap"), { permalinkName : "OCyc" }));
map.map.addLayer(new fm.Layer.OSM.HikeAndBike(ol.i18n("Hike & Bike Map"), { permalinkName : "HiBi" }));
map.map.addLayer(new fm.Layer.OSM.OpenPTMap(ol.i18n("Public transportation"), { permalinkName : "OPTM", visibility : false }));
map.map.addLayer(new fm.Layer.other.Relief(ol.i18n("Relief"), { visibility: false, permalinkName : "Rlie" }));
map.layerLines = new FacilMap.Layer.Vector("Lines", { displayInLayerSwitcher: false, visibility: true });
map.map.addLayer(map.layerLines);
var label;
map.featureHandler = new OpenLayers.Handler.Feature(null, map.layerLines, {
"over" : function(obj) {
$(map.map.div).addClass("fp-overFeature");
if(label)
label.close();
if(obj.fpMarker && obj.fpMarker.name)
label = map.showLabel(obj.fpMarker.name, obj.fpMarker, { x: 10, y: 0 });
else if(obj.fpLine && obj.fpLine.name) {
var e = map.featureHandler.evt;
label = map.showLabel(obj.fpLine.name, map.xyToPos({ x: e.offsetX == null ? e.layerX : e.offsetX, y: e.offsetY == null ? e.layerY : e.offsetY }), { x: 15, y: 0 }, true);
}
},
"out" : function(obj) {
$(map.map.div).removeClass("fp-overFeature");
if(label) {
label.close();
label = null;
}
},
"click" : function(obj) {
obj.fpOnClick(map.xyToPos(map.featureHandler.up), map.featureHandler.evt);
}
}, { map: map.map });
map.featureHandler.activate();
var dragIcon = fpUtils.createMarkerIcon("ffd700");
map.dragControl = new FacilMap.Control.DragLine(map.layerLines, dragIcon);
map.map.addControl(map.dragControl);
map.map.events.register("click", map.map, function(e) {
map.mapEvents.$emit("click", map.xyToPos(e.xy));
});
map.map.events.register("move", this, function() {
setTimeout(function() { map.mapEvents.$emit("move"); }, 0);
});
map.map.events.register("moveend", this, function() {
var x = map.map.getExtent().clone().transform(map.map.getProjectionObject(), fpUtils.proj());
setTimeout(function() {
map.mapEvents.$emit("moveEnd", { top: x.top, left: x.left, bottom: x.bottom, right: x.right, zoom: map.map.getZoom() });
}, 0);
});
map.map.events.register("mousemove", this, function(e) {
map.mapEvents.$emit("mouseMove", map.xyToPos(e.xy));
});
function _wrapFeatureFunc(superFunc) {
return function(feature) {
if(this.filterFunc(feature))
return superFunc.apply(this, arguments);
};
}
map.getCurrentView = function() {
var ret = map.map.getExtent().clone().transform(map.map.getProjectionObject(), fpUtils.proj());
ret.baseLayer = map.map.baseLayer.permalinkName;
ret.layers = [ ];
for(var i=0; i<map.map.layers.length; i++) {
if(!map.map.layers[i].isBaseLayer && map.map.layers[i].displayInLayerSwitcher && map.map.layers[i].visibility)
ret.layers.push(map.map.layers[i].permalinkName || map.map.layers[i].name);
}
return ret;
};
map.displayView = function(view) {
if(view == null) {
map.map.zoomToMaxExtent();
} else {
var bbox = OpenLayers.Bounds.prototype.clone.apply(view).transform(fpUtils.proj(), map.map.getProjectionObject());
map.map.zoomToExtent(bbox);
var matching_layers = map.map.getLayersBy("permalinkName", view.baseLayer);
if(matching_layers.length == 0)
matching_layers = map.map.getLayersBy("name", view.baseLayer);
if(matching_layers.length > 0)
map.map.setBaseLayer(matching_layers[0]);
for(var i=0; i<map.map.layers.length; i++) {
if(!map.map.layers[i].isBaseLayer && map.map.layers[i].displayInLayerSwitcher)
map.map.layers[i].setVisibility(view.layers.indexOf(map.map.layers[i].permalinkName) != -1 || view.layers.indexOf(map.map.layers[i].name) != -1);
}
}
};
map.addMarker = function(marker) {
map.deleteMarker(marker);
var feature = fm.Util.createIconVector(fm.Util.toMapProjection(new ol.LonLat(marker.lon, marker.lat), map.map), fpUtils.createMarkerIcon(marker.colour));
feature.fpMarker = marker;
feature.fpOnClick = function(pos, evt) {
map.mapEvents.$emit("clickMarker", marker, evt);
};
map.layerLines.addFeatures([ feature ]);
map.markersById[marker.id] = feature;
};
map.deleteMarker = function(marker) {
var markerObj = map.markersById[marker.id];
if(!markerObj)
return;
delete map.markersById[marker.id];
map.layerLines.removeFeatures([ markerObj ]);
};
map.addLine = function(line) {
map.deleteLine(line);
if(!line.trackPoints || line.trackPoints.length < 2)
return;
var trackPoints = [ ];
for(var i=0; i<line.trackPoints.length; i++) {
if(line.trackPoints[i] != null)
trackPoints.push(new OpenLayers.Geometry.Point(line.trackPoints[i].lon, line.trackPoints[i].lat));
}
if(trackPoints.length < 2)
return;
var style = {
strokeColor : '#'+line.colour,
strokeWidth : line.width,
strokeOpacity : 0.7
};
var feature = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.LineString(trackPoints).transform(fpUtils.proj(), map.map.getProjectionObject()), null, style);
feature.fpLine = line;
feature.fpOnClick = function(clickPos, evt) {
map.mapEvents.$emit("clickLine", line, clickPos, evt);
};
map.layerLines.addFeatures([ feature ]);
map.linesById[line.id] = feature;
};
map.deleteLine = function(line) {
var lineObj = map.linesById[line.id];
if(!lineObj)
return;
delete map.linesById[line.id];
map.layerLines.removeFeatures([lineObj]);
};
map.addClickListener = function(listener) {
map.featureHandler.deactivate(); // Disable clicking on markers and lines
$(map.map.div).addClass("fp-clickHandler");
var unregister;
var ret = {
cancel: function() {
unregister();
$(map.map.div).removeClass("fp-clickHandler");
map.featureHandler.activate();
}
};
setTimeout(function() {
unregister = map.mapEvents.$on("click", function(e, pos) {
ret.cancel();
listener(pos);
});
}, 0);
return ret;
};
map.xyToPos = function(xy) {
return map.map.getLonLatFromViewPortPx(xy).clone().transform(map.map.getProjectionObject(), fpUtils.proj());
};
map.posToXy = function(pos) {
var lonlat = new OpenLayers.LonLat(pos.lon, pos.lat).transform(fpUtils.proj(), map.map.getProjectionObject());
return map.map.getViewPortPxFromLonLat(lonlat);
};
map.getLayerInfo = function() {
var ret = { base: [ ], overlay: [ ] };
map.map.layers.forEach(function(it) {
if(!it.displayInLayerSwitcher)
return;
(it.isBaseLayer ? ret.base : ret.overlay).push({ visibility: it.getVisibility(), name: it.name, permalinkName: it.permalinkName });
});
return ret;
};
map.showLayer = function(permalinkName, show) {
var layers = map.map.getLayersBy("permalinkName", permalinkName);
if(layers.length == 0)
return;
if(layers[0].isBaseLayer)
map.map.setBaseLayer(layers[0]);
else
layers[0].setVisibility(show);
};
map.makeLineMovable = function(origLine) {
map.featureHandler.deactivate();
var line = $.extend(true, { }, origLine);
line.trackPoints = line.routePoints;
var markers = [ ];
for(var i=0; i<line.routePoints.length; i++)
markers.push(fm.Util.createIconVector(fm.Util.toMapProjection(new ol.LonLat(line.routePoints[i].lon, line.routePoints[i].lat), map.map), dragIcon));
map.layerLines.addFeatures(markers);
map.addLine(line);
var dragExcludeBkp = map.layerLines._excludeFeature;
map.layerLines._excludeFeature = function(feature) {
return dragExcludeBkp.apply(this, arguments) || (!feature.fmStartLonLat && feature != map.linesById[line.id] && markers.indexOf(feature) == -1);
};
map.dragControl.onDblClick = function(feature) {
var idx = markers.indexOf(feature);
if(idx != -1) {
line.routePoints.splice(idx, 1);
map.addLine(line);
markers.splice(idx, 1);
map.layerLines.removeFeatures([ feature ]);
feature.destroy();
}
};
map.dragControl.onDrag = function(feature) {
var idx = markers.indexOf(feature);
if(idx != -1) { // Existing marker was dragged
var lonlat = fm.Util.fromMapProjection(new ol.LonLat(feature.geometry.x, feature.geometry.y), map.map);
line.routePoints[idx] = { lat: lonlat.lat, lon: lonlat.lon };
map.addLine(line);
}
else if(feature.fmStartLonLat) { // New marker
var index = fm.Util.lonLatIndexOnLine(feature.fmStartLonLat, feature.fmLine.geometry);
if(index != null) {
var newIndex = line.routePoints.length;
var indexes = [ ];
for(var i=0; i<newIndex; i++) {
indexes.push(fm.Util.lonLatIndexOnLine(fm.Util.toMapProjection(new OpenLayers.LonLat(line.routePoints[i].lon, line.routePoints[i].lat), map.map), feature.fmLine.geometry));
if(index < fm.Util.lonLatIndexOnLine(fm.Util.toMapProjection(new OpenLayers.LonLat(line.routePoints[i].lon, line.routePoints[i].lat), map.map), feature.fmLine.geometry))
newIndex = i;
}
var lonlat = fm.Util.fromMapProjection(feature.fmStartLonLat, map.map);
line.routePoints.splice(newIndex, 0, { lat: lonlat.lat, lon: lonlat.lon });
markers.splice(newIndex, 0, feature);
map.addLine(line);
}
else
console.warn("Index = null", feature.fmStartLonLat);
}
};
map.dragControl.onComplete = function(feature) {
if(feature.fmStartLonLat)
delete feature.fmStartLonLat;
};
map.dragControl.activate();
return {
done : function() {
end();
return line.routePoints;
}
};
function end() {
if(markers.indexOf(map.dragControl.feature) != -1)
map.dragControl._simulateOverFeature(null);
map.layerLines.removeFeatures(markers);
for(var i=0; i<markers.length; i++)
markers[i].destroy();
map.layerLines._excludeFeature = dragExcludeBkp;
map.dragControl.deactivate();
map.featureHandler.activate();
}
};
map.loadStart = function() {
map.map.getControlsByClass("FacilMap.Control.Loading")[0].loadStart();
};
map.loadEnd = function() {
map.map.getControlsByClass("FacilMap.Control.Loading")[0].loadEnd();
};
map.showLabel = function(label, pos, offset, updateOnMove) {
var xy = map.posToXy(pos);
var el = $("<div/>").addClass("fp-map-label").text(label).css({ top: (xy.y+offset.y)+"px", left: (xy.x+offset.x)+"px" }).appendTo(map.map.div);
var updatePosition = function(e) {
el.css({ top: ((e.offsetY == null ? e.layerY : e.offsetY)+offset.y)+"px", left: ((e.offsetX == null ? e.layerX : e.offsetX)+offset.x)+"px" });
};
if(updateOnMove)
map.map.events.register("mousemove", null, updatePosition);
return {
close: function() {
el.remove();
if(updateOnMove)
map.map.events.unregister("mousemove", null, updatePosition);
}
};
};
map.messages = fpMapMessages(map);
map.popups = fpMapPopups(map);
map.markersUi = fpMapMarkers(map);
map.linesUi = fpMapLines(map);
map.viewsUi = fpMapViews(map);
map.typesUi = fpMapTypes(map);
map.padUi = fpMapPad(map);
map.gpxUi = fpMapGpx(map);
map.toolboxUi = fpMapToolbox(map);
fpMapLegend(map);
fpMapSearch(map);
map.socket.$on("loadStart", function() {
map.loadStart();
});
map.socket.$on("loadEnd", function() {
map.loadEnd();
});
var loadedWatcher = map.socket.$watch("loaded", function(loaded) {
if(loaded) {
setTimeout(function() {
map.displayView(map.socket.padData.defaultView);
}, 0);
loadedWatcher();
}
});
map.socket.on("marker", function(data) {
map.addMarker(data);
});
map.socket.on("deleteMarker", function(data) {
map.deleteMarker(data);
});
map.socket.on("line", function(data) {
setTimeout(function() { // trackPoints needs to be copied over
map.addLine(map.socket.lines[data.id]);
}, 0);
});
map.socket.on("deleteLine", function(data) {
map.deleteLine(data);
});
map.socket.on("linePoints", function(data) {
setTimeout(function() {
map.addLine(map.socket.lines[data.id]);
}, 0);
});
var errorMessage = null;
map.socket.$watch("disconnected", function(disconnected) {
if(disconnected && !errorMessage)
errorMessage = map.messages.showMessage("error", "The connection to the server was lost.");
else if(!disconnected && errorMessage) {
errorMessage.close();
errorMessage = null;
}
});
map.mapEvents.$on("moveEnd", function(e, bbox) {
map.socket.updateBbox(bbox);
});
}
});
})(FacilPad, jQuery, angular, FacilMap, OpenLayers);