Activation/deactivation of OpenLayers.Controls.DrawFeature fails - javascript

When I break on the first line in the call back function and do this
this.active --> true
this.deactivate() --> true
this.activate() --> true
this.deactivate() --> false
HOW CAN THIS HAPPEN?
Let me explain where this occurs.
This map has two layers and each layer has an EditingToolbar associated with it.
When the user pressed polygon draw (in the EditingToolbar), its being draw on the "polygon_layer".
When the user presses line draw or point draw the layer is switched and the user now draws on the "vectors" layer.
When I switch layers, I need to activate the correct button in the EditingToolbar, example:
The user draws polygons in the "polygon_layer" and now he want to draw lines. He presses draw lines button (in the EditingToolbar associated with the polygon_layer).
I switch layers and activate draw lines button on the EditingToolbar for that layer.
After a while, the user now wants to draw polygons again, so i deactivate all buttons in this layer, switch layers and activate the draw polygon button in the
EditingToolbar for the polygon_layer. and so on.
Now when I do this enough times (3 switches) I notice that the buttons don't get deactivate anymore.
So I tried to debug and got this totally unexpected error described above ( at the very top).
Please tell me what am I doing wrong.
I've appended my code and I'll put ERROR HERE where this occurs. This code is ready to run.
You can use the HTML code below, just change the reference to the JavaScript file that I've provided ( I've provided the contents of the JavaScript file)
JS FILE:
var map;
var editing_toolbar_polygon=null;
var editing_toolbar_vector=null;
var drag_control=null;
var vectors;
var polygon_layer=null;
var epsg900913 = new OpenLayers.Projection('EPSG:900913');
var epsg4326 = new OpenLayers.Projection('EPSG:4326');
//var epsg900913 = new OpenLayers.Projection('EPSG:900913');
// var epsg4326 = new OpenLayers.Projection('EPSG:4326');
var line_control;
var polygon_control;
var renderer;
function initialize() {
line_control, renderer=OpenLayers.Util.getParameters(window.location.href).renderer;
renderer= (renderer) ? [renderer] : OpenLayers.Layer.Vector.prototype.renderers;
// Create the map object
map = new OpenLayers.Map('map');
//Create a Google layer
var gmap = new OpenLayers.Layer.Google(
"Google Streets", // the default
{
numZoomLevels: 20,
projection: new OpenLayers.Projection("EPSG:900913")
}
);
var wms = new OpenLayers.Layer.WMS( "OpenLayers WMS",
"http://vmap0.tiles.osgeo.org/wms/vmap0?", {layers: 'basic',
projection: new OpenLayers.Projection("EPSG:4326")});
var mystyle=new OpenLayers.StyleMap({
"default": new OpenLayers.Style({
fillColor: "#66ccff",
strokeColor: "#3399ff",
graphicZIndex: 2,
strokeWidth: 5,
}),
"temporary": new OpenLayers.Style({
fillColor:"#3399ff",
strokeColor: "#3399ff",
strokeWidth:5,
pointRadius:10
})
});
polygon_layer=new OpenLayers.Layer.Vector(
"Polygon Layer",
{
//renderers:renderer,
}
);
vectors= new OpenLayers.Layer.Vector(
"Vector Layer",
{
//renderers:renderer,
}
);
editing_toolbar_polygon=new OpenLayers.Control.EditingToolbar(polygon_layer);
editing_toolbar_vector=new OpenLayers.Control.EditingToolbar(vectors);
map.addLayers([gmap,wms,vectors,polygon_layer]);
map.addControl(new OpenLayers.Control.LayerSwitcher());
//map.addControl(new OpenLayers.Control.MousePosition());
map.addControl(editing_toolbar_polygon);
map.addControl(editing_toolbar_vector);
editing_toolbar_vector.deactivate();
//for the drag control to work you need to activate it
drag_control=new OpenLayers.Control.DragFeature(vectors);
map.addControl(drag_control);
find_control(editing_toolbar_polygon.getControlsByClass(new RegExp(".*DrawFeature")),"Point").events.register("activate",null,function(e){
//ERROR HERE
this.deactivate();
var picked_button=find_same_control(editing_toolbar_vector.controls,e.object);
change_layer(polygon_layer,vectors);
change_control(editing_toolbar_polygon,editing_toolbar_vector);
picked_button.activate();
});
find_control(editing_toolbar_polygon.getControlsByClass(new RegExp(".*DrawFeature")),"Path").events.register("activate",null,function(e){
//ERROR HERE
this.deactivate();
var picked_button=find_same_control(editing_toolbar_vector.controls,e.object);
change_layer(polygon_layer,vectors);
change_control(editing_toolbar_polygon,editing_toolbar_vector);
picked_button.activate();
});
find_control(editing_toolbar_vector.getControlsByClass(new RegExp(".*DrawFeature")),"Polygon").events.register("activate",null,function(e){
//ERROR HERE
this.deactivate();
var picked_button=find_same_control(editing_toolbar_polygon.controls,e.object);
change_layer(vectors,polygon_layer);
change_control(editing_toolbar_vector,editing_toolbar_polygon);
picked_button.activate();
});
polygon_layer.events.register("beforefeatureadded",null,function(e){
polygon_layer.removeAllFeatures();
});
// line_control=new OpenLayers.Control.DrawFeature(vectors,OpenLayers.Handler.Path);
//polygon_control=new OpenLayers.Control.DrawFeature(vectors,OpenLayers.Handler.RegularPolygon);
//map.addControl(line_control);
//line_control.activate();
//map.addControl(polygon_control);
//polygon_control.activate();
// Zoom to Vancouver, BC
map.setCenter(new OpenLayers.LonLat(-123.12, 49.28).transform(epsg4326, epsg900913), 13);
}
function change_layer(current_layer,next_layer){
current_layer.setVisibility(false);
next_layer.setVisibility(true);
}
function change_control(current_control,next_control){
current_control.deactivate();
map.addControl(next_control);
}
//use this when you want to find a specific control type:
// DrawFeature cntrol has many types, Line, Polygon, Point.
// So what you do is pass an array of DrawFeature controls and a type(string), lets say "Point",
// then this function will return a DrawFeature thats specifically for drawing points
function find_control(controls,type){
var control;
for(var x in controls){
if(controls[x].displayClass.search(new RegExp(type+"$"))>0){
return controls[x];
}
}
return -1;
}

I just tried with a simple test.
When you desactivate a controller, you just remove the events of the controller.
So for OpenLayers.Control.LayerSwitcher, desactivate this controller is useless because nothing change and you can still choose a layer.
I think the best way is to remove the controller for your polygon and to add that for the lines.
When you select the "polygon_layer" :
map.addControl(editing_toolbar_polygon);
map.removeControl(editing_toolbar_vector);
When you select the "vectors" :
map.addControl(editing_toolbar_vector);
map.removeControl(editing_toolbar_polygon);

Related

Openlayers draw interaction: Error: drag and drop of map after click

I am trying to add a draw interaction to my map. The user should click a button, add one point and then add attribute information about the point. I'm still stuck in the drawing part: After I draw a point in the map, the cursor position remains the same and mouse movements change the map in the background (like when panning). When I click again this stops. No idea why it's doing this. In the console in Chrome I get an error in the draw.js file from openlayers (this.source_.addFeature is not a function).
Grateful for any help!
Here's my code:
function addFeature() {
var btn_cancel = document.getElementById('buttonCancel');
btn_cancel.style.display = 'block';
var btn_add = document.getElementById('buttonAdd');
btn_add.classList.add("button_clicked");
var draw;
function addInteraction() {
draw = new ol.interaction.Draw({
source: lunchvec,
type: "Point",
});
map.addInteraction(draw);
draw.on('drawend', function(evt) {
console.log(evt.feature.getGeometry().getCoordinates());
map.removeInteraction(draw);
});
};
addInteraction();
}

Mapbox popups at wrong location when map is at max zoom (multiple world copies visible)

I have an issue with a Mapbox map where Popups attached to a Marker are displayed the wrong position, when the map is zoomed out, so we see multiple world copies. See sample below. The Popup are displayed at the correct position when the map is zoomed in and only one world is visible.
This is a simplified version of the code used to add Markers + Popups and display them:
// Add markers to the map
features.forEach(function (marker: any, i: number) {
const popUpContent = '<div>Sample</div>'
// Create the popup
const popup = new mapboxgl.Popup({ offset: 25 })
.setHTML(popUpContent)
.on('open', function (event: any) {
const activePoi = document.getElementsByClassName(poiId)[0]
activePoi.classList.add('active')
})
.on('close', function () {
const activePoi = document.getElementsByClassName(poiId)[0]
if (activePoi) {
activePoi.classList.remove('active')
}
})
let mark = new mapboxgl.Marker(markerElement)
.setLngLat(marker.geometry.coordinates)
.setPopup(popup)
.addTo(map)
})
Question
How can I solve this issue, so that popup appears correctly above their respective Marker, even when multiple world copies are visible?
You can use Mapbox's solution to this: https://docs.mapbox.com/mapbox-gl-js/example/popup-on-click/
// When a click event occurs on a feature in the places layer, open a popup at the
// location of the feature, with description HTML from its properties.
map.on('click', 'places', function(e) {
var coordinates = e.features[0].geometry.coordinates.slice();
var description = e.features[0].properties.description;
// Ensure that if the map is zoomed out such that multiple
// copies of the feature are visible, the popup appears
// over the copy being pointed to.
while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360;
}
new mapboxgl.Popup()
.setLngLat(coordinates)
.setHTML(description)
.addTo(map);
});
// ...
}

Leaflet offline grid layer

I want leaflet to work offline, without title, to show only a grid as titles. To have all the features of Leaflet, add plugins to draw a line, pin a marker, draw a polygon, zoom in / zoom out on shapes etc.
Is there a simple way to show just a simple grid?
Here's a custom GridLayer (that's already been implemented by the Leaflet authors). All you have to do is copy L.GridLayer.DebugCoords where you would normally load a tile layer.
var map = L.map('map', {
center: [0, 0],
zoom: 0
});
L.GridLayer.DebugCoords = L.GridLayer.extend({
createTile: function (coords, done) {
var tile = document.createElement('div');
//this adds tile coordinates; you may or may not want this
tile.innerHTML = [coords.x, coords.y, coords.z].join(', ');
tile.style.outline = '1px solid red';
/* // you don't need this artificial timeout for your application
setTimeout(function () {
done(null, tile); // Syntax is 'done(error, tile)'
}, 500 + Math.random() * 1500);
*/
return tile;
}
});
L.gridLayer.debugCoords = function(opts) {
return new L.GridLayer.DebugCoords(opts);
};
map.addLayer( L.gridLayer.debugCoords() );
Stand-alone, working example: http://leafletjs.com/examples/extending/gridcoords.html
Code taken from: http://leafletjs.com/examples/extending/extending-2-layers.html

Cesium - TypeError : t is undefined when Focusing Camera on Object

I've loaded some JSon data outlining each country on a globe as a GeoJSonDataSource into my Cesium project. Each country is also copied as a separate entry into an array. In order to highlight a country, I use
viewer.entities.add(countryArray[countryID]);
which places a colored polygon over the selected country when the user clicks on it. However, when I click on the Camera icon in the info box that Cesium provides by default, nothing happens. In the console, the error message reads:
TypeError: t is undefined
and points to Cesium.js. If I don't add anything to the viewer.entities array, this error doesn't appear.
There may be a better way to highlight the selected country. Try capturing the selected entity, and change the material properties on the existing polygon, rather than creating a new one.
For example, give this a try: Load up the Cesium Sandcastle and paste in the following code into the code editor, then hit F8:
var viewer = new Cesium.Viewer('cesiumContainer', {
navigationHelpButton: false, animation: false, timeline: false,
selectionIndicator: false
});
var deselectColor = Cesium.Color.BLUE.withAlpha(0.3);
var selectedColor = Cesium.Color.LIME.withAlpha(0.5);
var deselectMaterial = new Cesium.ColorMaterialProperty(
new Cesium.ConstantProperty(deselectColor));
var selectedMaterial = new Cesium.ColorMaterialProperty(
new Cesium.ConstantProperty(selectedColor));
viewer.dataSources.add(Cesium.GeoJsonDataSource.load(
'../../SampleData/ne_10m_us_states.topojson', {
stroke: Cesium.Color.WHITE,
fill: deselectColor,
strokeWidth: 2
}));
//Set the camera to a US centered tilted view.
viewer.camera.lookAt(Cesium.Cartesian3.fromDegrees(-98.0, 40.0),
new Cesium.Cartesian3(0.0, -4790000.0, 3930000.0));
viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
var previousEntity;
Cesium.knockout.getObservable(viewer, '_selectedEntity').subscribe(function(newEntity) {
if (Cesium.defined(previousEntity) && Cesium.defined(previousEntity.polygon)) {
previousEntity.polygon.material = deselectMaterial;
}
if (Cesium.defined(newEntity) && Cesium.defined(newEntity.polygon)) {
newEntity.polygon.material = selectedMaterial;
}
previousEntity = newEntity;
});

Rendering Issue for Openstreet Maps with Yii

I have had issue previouslys with jquery and Yii and how it renders.
using the following code:
<div id="mapdiv" height="1000" width="1000"></div>
<script src="http://www.openlayers.org/api/OpenLayers.js"></script>
<script>
var mainLonLat = [0.166081 ,38.789011];
map = new OpenLayers.Map("mapdiv");
map.addLayer(new OpenLayers.Layer.OSM());
epsg4326 = new OpenLayers.Projection("EPSG:4326"); //WGS 1984 projection
projectTo = map.getProjectionObject(); //The map projection (Spherical Mercator)
var lonLat = new OpenLayers.LonLat( 0.166081 ,38.789011 ).transform(epsg4326, projectTo);
var zoom=14;
map.setCenter (lonLat, zoom);
var mastsOneK = [new OpenLayers.LonLat(0.154539,38.738778)];
//Create the Circle
circleLayer = new OpenLayers.Layer.Vector("circleLayer");
circleLayer.addFeatures(createCircle());
function createCircle()
{
var x = 0;
var extent = map.getExtent();
var features = [];
while(x < mastsOneK.length)
{
var threeKStyle = {
strokeWidth: 1,
strokeColor: '#FF6600',
fill: 1,
fillColor: '#FF6600',
fillOpacity: 0.4,
strokeOpacity: 0.4,
};
var newThreeK = new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.Polygon.createRegularPolygon(
new OpenLayers.Geometry.Point(mastsOneK[x].lon,mastsOneK[x].lat).transform(
epsg4326, projectTo),
2000,
40),"",threeKStyle);
features.push(newThreeK);
x++;
}
return features;
}
map.addLayer(circleLayer);
</script>
I am able to get a map showing with a single circle using just a standard html page, this is the desired result. However, when using the same code and pasting this into a Yii view. The map does not appear. I get a blank white area where the map should be.
If I use chrome inspector and set a height and width to the element (I have set width and height to the element before and this does not make a difference), I can begin to see a slice of the map.
If I then zoom in on the page, the full map then appears as expected.
I have tried to do various workarounds such as resize, redraw, refresh the image etc. Using the codes below and many more for example:
$("#mapdiv").resize();
$.fn.redraw = function(){
$(this).each(function(){
var redraw = this.offsetHeight;
});
};
$('#mapdiv').redraw();
However the map still does not show. Strangely enough if I remove the DOCTYPE tag at the start of the document, then the map appears, but obviously this causes many other issues.
Could any one suggest why this is happening and any potential fixes they may have come across as I have used every snippet I have got my hands on to no avail.
Similarly when using the highcharts extensions and trying to render the charts in a tab I also get an issue where a zoom in/out is required to see the chart and I can't help but think that the solution to the above would be the solution to this also.
Any help is appreciated.
You may have to manually call map.updateSize() ( http://dev.openlayers.org/apidocs/files/OpenLayers/Map-js.html#OpenLayers.Map.updateSize ) when the containing element size has changed after initialisation.

Categories