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.
Related
I've got a Leaflet map with a single tile layer and then a LayerGroup (densityLayer) consisting of many (typically a few hundred) Rectangle layers, each of which is a semitransparent filled overlay with its fillColor based on population density for a particular year.
Based on a user action, the contents of densityLayer change. Pretty trivial to just run densityLayer.clearLayers() then generate all the new Rectangle layers and densityLayer.addLayer(aRectangle) for each of them.
What I want to do, though, is to animate a fade from the old to the new data: i.e., generate all the new Rectangle layers and put them in a new LayerGroup (newDensityLayer), and simultaneously fade out the original oldDensityLayer and fade in the newDensityLayer, and when the fade is complete, then clear out and remove oldDensityLayer and replace it with newDensityLayer.
My current solution is hideously inefficient:
var oldDensityLayer = densityLayer
var newDensityLayer = {...create new density layer here, add polygons, etc...}
oldDensityLayer.eachLayer(function(l) {
$(l._path).fadeOut(1000) // 1000ms animation time
})
setTimeout(function() {
oldDensityLayer.clearLayers()
myLeafletMap.removeLayer(oldDensityLayer)
oldDensityLayer = null
}, 1000)
myLeafletMap.addLayer(newDensityLayer)
// now fade in all the new polygons
newDensityLayer.eachLayer(function(l) {
$(l._path).hide() // so they start out invisible
$(l._path).fadeIn(1000)
})
densityLayer = newDensityLayer
This basically works, but gets pretty choppy and slow on anything but a very fast machine.
Is there some way to fade in/out an entire LayerGroup, or perhaps some option I haven't considered...?
This is critical functionality, so if adding another js library would help, that's fine. Also, SVG-specific answers are fine, as that's what I've got Leaflet using for its drawing functions, and cross-browser compatibility isn't a concern in this application.
Is there some way to fade in/out an entire LayerGroup, or perhaps some option I haven't considered...?
There is, in fact, an option which you haven't considered: manipulate the L.Renderer which actually draws the geometries as an HTML element. This means manipulating the actual <canvas> of a L.Canvas, or the actual <svg> of a L.SVG.
Remember any subclass of L.Path (Polygons, Polylines and such) can have its own renderer. Leaflet, by default, creates just one instance of L.Renderer and reuses it in all L.Paths unless told otherwise - this means less HTML elements and (in 99% of use cases) better performance.
So it should look something like:
var rendererA = L.canvas();
var rendererB = L.canvas();
var groupA = L.layerGroup().addTo(map);
var layerA1 = L.polygon(…, {renderer: rendererA}).addTo(groupA);
var layerA2 = L.polygon(…, {renderer: rendererA}).addTo(groupA);
var groupB = L.layerGroup().addTo(map);
var layerB1 = L.polygon(…, {renderer: rendererB}).addTo(groupB);
var layerB2 = L.polygon(…, {renderer: rendererB}).addTo(groupB);
// Here comes the magic - using the *undocumented*, *private* _container
// property of L.Canvas to access the <canvas> HTML element itself
rendererA._container.style.opacity = 0.5;
The code is obviously incomplete, but it should illustrate the idea properly.
That will create two different <canvas> in the browser, and changing the opacity of the HTML element itself will bypass re-rendering the features. There should be an analogous solution using L.SVG instead, but I'm not sure how browsers composite the opacity of SVG containers.
There are obvious disadvantages for this method - like losing any z-ordering (bringToFront, etc) if geometries from both groups should be intertwined.
Also, please remember: Using undocumented, private properties of leaflet objects is not recommended unless you really really really know what you're doing and are willing to see your code break in API changes or rare circumstances.
You could include an SVG layer populated with your shapes. Below in an example that fades out 500 svg shapes, then builds a new bunch of SVG shapes and fades them in. (Edited to zoom shapes at their locations)
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Fade Out/In SVG Elements in Leaflet World Map</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script src='https://api.tiles.mapbox.com/mapbox.js/v2.1.5/mapbox.js'></script>
<link href='https://api.tiles.mapbox.com/mapbox.js/v2.1.5/mapbox.css' rel='stylesheet' />
</head>
<body style='font-family:arial'>
<center><h4>Fade Out/In SVG Elements in Leaflet World Map</h4>
<div style='width:90%;background-color:gainsboro;text-align:justify;padding:10px;border-radius:6px;'>
This adds 500 svg elements(circles, ellipses, rects, polygons) to the SVG layer in the world map. The map's mouse wheel zoom remains smooth in IE/CH/FF. Each element has a lat/lng value, converted to the needed x,y values to translate each symbol to the desired point.
During map zoom level changes, the symbols are automatically scaled and translated, maintaining their original size and position.
</div>
<br />
<table border=1>
<tr>
<td>
<b>Scenerio:</b><br />
1). The map is placed into its DIV (width:800px, height:400px).<br />
2). The map is centered at Lat/Lng (0,0) at zoom level 1.<br />
3.) The SVG element is added via <b>initPathRoot.</b><br />
4.) 500 SVG elements are added, randomly place about the world.<br />
5.) The svg <b>viewBox</b> is computed, used to create x,y values for the symbols.<br />
6.)Each element is translated/scaled when the map is zoomed, using the <b>viewreset</b> event.<br /> This calls the map method <b>latLngToLayerPoint(MyLatLng)</b> to accomplish this.
<br>7.) Select <button>fade out/in</button> to fade out the current elements, build a new group, then fade In new group
</td>
</tr>
</table>
<div style='width:800px;height:400px' id='MyMap'></div>
<button onClick=fadeOutIn()>fade out/in</button>
<br />Javascript:<br />
<textarea spellcheck=false id=jsValue style='border-radius:26px;font-size:110%;font-weight:bold;color:midnightblue;padding:16px;background-color:beige;border-width:0px;font-size:100%;font-family:lucida console;width:90%;height:400px'></textarea>
</center>
<script id=myScript>
L.mapbox.accessToken = 'pk.eyJ1IjoiZmhlbXNoZXIiLCJhIjoiODQ5MW9WayJ9.px2P6wVMFucfXHE1zmDA1A';
MyMap = L.mapbox.map('MyMap', 'mapbox.streets', { zoomControl:false,center: new L.latLng(0,0),zoom:1,minZoom:1});
//---zooming the map---
MyMap.on("viewreset", adjustSVGSymbols);
var MySVG
var SymbolG //---<g> element containing all symbols---
var VBw
var VBh
var NS="http://www.w3.org/2000/svg"
//---body onload---
function initSVG()
{
MyMap._initPathRoot() //---creates an svg layer---
MySVG=document.querySelector("svg") //---access svg element---
//---place symbols in here---
SymbolG=document.createElementNS(NS,"g")
SymbolG.setAttribute("id","symbolG")
MySVG.appendChild(SymbolG)
//---create random svg elements, place in SymbolG--
getViewBox()//---used to place svg random elements
//---create 500 symbols at size 10 pixels--
svgGLOB(500,10)
}
//--- on map zoom - fired via map event: viewreset---
function adjustSVGSymbols()
{
var symbols=SymbolG.childNodes
for(var k=0;k<symbols.length;k++)
{
var symbol=symbols.item(k)
//---initial lat/lng for symbol---
var lat=parseFloat(symbol.getAttribute("lat"))
var lng=parseFloat(symbol.getAttribute("lng"))
var latLng= new L.latLng(lat, lng)
var transX=MyMap.latLngToLayerPoint(latLng).x
var transY=MyMap.latLngToLayerPoint(latLng).y
//---scale---
var initZoom=parseFloat(symbol.getAttribute("initZoom"))
var scale = (Math.pow(2, MyMap.getZoom())/2)/(Math.pow(2, initZoom)/2);
//---trash previous transform---
symbol.setAttribute("transform","")
symbol.removeAttribute("transform")
var transformRequestObj=MySVG.createSVGTransform()
var animTransformList=symbol.transform
//---get baseVal to access/place object transforms
var transformList=animTransformList.baseVal
//---translate----
transformRequestObj.setTranslate(transX,transY)
transformList.appendItem(transformRequestObj)
transformList.consolidate()
//---scale---
transformRequestObj.setScale(scale,scale)
transformList.appendItem(transformRequestObj)
transformList.consolidate()
}
}
//---needed for random symbol placement: create x,y values---
function getViewBox()
{
vb=MySVG.viewBox.baseVal
VBw=vb.width
VBh=vb.height
}
//---compute svg elems: circles, rects, ellipses, polygons---
function svgGLOB(elems,elemSize)
{
//---note: each browser creates a different sized svg layer---
var svgWidth=VBw
var svgHeight=VBh
//---obtain a random whole number from a thru b---
function rdm(a,b)
{
return a + Math.floor(Math.random()*(b-a+1));
}
function randomPoints(elems,svgWidth,svgHeight,elemSize)
{
//--return format:[ [x,y],[x,y],,, ]
//---Generate random points---
function times(n, fn)
{
var a = [], i;
for (i = 0; i < n; i++)
{
a.push(fn(i));
}
return a;
}
var width=svgWidth-2*elemSize //---offset from edge---
var height=svgHeight-2*elemSize //---offset from edge---
return RandomPnts = times(elems, function() { return [Math.floor(width * Math.random()) + elemSize, Math.floor(height * Math.random()) + elemSize] });
}
//---random color---
function rcolor()
{
var letters = '0123456789ABCDEF'.split('');
var color = '#';
for (var i = 0; i < 6; i++ )
{
color += letters[Math.round(Math.random() * 15)];
}
return color;
}
function polygon(vCnt,radius,centerX,centerY)
{
var myPoints=[]
var polyXPts = Array(vCnt);
var polyYPts = Array(vCnt);
var vertexAngle = 360/vCnt;
//---init polygon points processor---
for(var v=0; v<vCnt; v++)
{
theAngle = (v*vertexAngle)*Math.PI/180;
polyXPts[v] = radius*Math.cos(theAngle);
polyYPts[v] = -radius*Math.sin(theAngle);
}
//--note points are CCW---
for(var v=0;v<vCnt; v++)
{
var point=[centerX+polyXPts[v],centerY+polyYPts[v]]
myPoints.push(point)
}
return myPoints
}
var Points=randomPoints(elems,svgWidth,svgHeight,elemSize)
var n=Points.length
var circleCnt=0
var ellipseCnt=0
var rectCnt=0
var polygonCnt=0
var RandomElems=[]
RandomElems[0]="circle"
RandomElems[1]="rect"
RandomElems[2]="ellipse"
RandomElems[3]="polygon_3"
RandomElems[4]="polygon_4"
RandomElems[5]="polygon_5"
RandomElems[6]="polygon_6"
RandomElems[7]="polygon_7"
RandomElems[8]="polygon_8"
RandomElems[9]="polygon_9"
RandomElems[10]="polygon_10"
RandomElems[11]="polygon_11"
RandomElems[12]="polygon_12"
//---create all at center(0,0), then translate---
for(var k=0;k<n;k++)
{
var rand=rdm(0,12)
var elemStr=RandomElems[rand]
if(!elemStr.indexOf("_"))
var elemSt=elemStr
else
var elemSt=elemStr.split("_")[0]
//var elem=document.createElementNS(NS,elemSt)
var x=Points[k][0]
var y=Points[k][1]
var lng=((x * 360 / VBw) - 180)
var lat= (90 - (y * 180 / VBh))
var id="symbol"+k
var fill=rcolor()
var elem=document.createElementNS(NS,elemSt)
elem.setAttribute("id",id)
elem.setAttribute("cursor","default")
elem.setAttribute("fill",fill)
elem.setAttribute("lat",lat)
elem.setAttribute("lng",lng)
if(elemSt=="circle")
{
var r=elemSize
elem.setAttribute("r",r)
}
else if(elemSt=="ellipse")
{
var rx=elemSize
var ry=elemSize/2
elem.setAttribute("rx",rx)
elem.setAttribute("ry",ry)
}
else if(elemSt=="rect")
{
var width=elemSize
var height=elemSize
//---center at 0,0---
var x=-elemSize/2
var y=-elemSize/2
elem.setAttribute("width",width)
elem.setAttribute("height",height)
elem.setAttribute("x",x)
elem.setAttribute("y",y)
}
else if(elemSt=="polygon")
{
var pgonSides=parseInt(elemStr.split("_")[1])
var pgonPnts=polygon(pgonSides,elemSize,0,0)
var points=pgonPnts.join()
elem.setAttribute("points",points)
}
elem.setAttribute("initZoom",1)
SymbolG.appendChild(elem)
}
//---initialize locations---
adjustSVGSymbols()
}
//---fade out/In button----
function fadeOutIn()
{
$("#symbolG").fadeOut(1000, function(){
createAnotherGlob()
});
}
function createAnotherGlob()
{
var symbols=SymbolG.childNodes
for(var k=symbols.length-1;k>=0;k--)
SymbolG.removeChild(symbols.item(k))
svgGLOB(500,10,true)
$("#symbolG").fadeIn(1500)
}
</script>
<script>
document.addEventListener("onload",init(),false)
function init()
{
jsValue.value=myScript.text
initSVG()
}
</script>
</body>
</html>
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;
});
The code snippet shown below (HTML5/javascript) loads Microsoft Bing Map (VirtualEarth 6.3), then adds two Shape layers and two sample Pushpins, one per each layer.
QUESTION: What pure javascript function (or solution) to use in order to clear all pushpins from just the 1st layer keeping the other layer intact?
Note: clear layer function should be implemented without deleting the entire layer.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Bing VE Map w/layers</title>
<script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.3"></script>
<script type="text/javascript">
// VE map
var _map;
// 1st shape layer
var _layer1 ;
// 2nd shape layer
var _layer2;
function MapLoad() {
// load map
_map = new VEMap('Map');
_map.LoadMap();
// center point (Columbus Circle NY)
var _center = new VELatLong(40.7681, -73.9819);
// set center point and initial zoom level
_map.SetCenterAndZoom(_center, 12);
// set Map style
_map.SetMapStyle(VEMapStyle.Shaded);
// add 1st shape layer1 to Map obj
_layer1 = new VEShapeLayer()
_map.AddShapeLayer(_layer1);
// add 2nd shape layer2 to Map obj
_layer2 = new VEShapeLayer()
_map.AddShapeLayer(_layer2);
// add pushpin to layer1
var _pushpin1 = new VEShape(VEShapeType.Pushpin, _center);
_layer1.AddShape(_pushpin1);
// add pushpin (Apple Store on 5th) to layer2
var _pushpin2 = new VEShape(VEShapeType.Pushpin, new VELatLong(40.7639, -73.9725));
_layer2.AddShape(_pushpin2);
// QUESTION: HOW TO CLEAR ALL SHAPES FROM LAYER 1, (BUT NOT DELETING THE ENTIRE LAYER)?
}
</script>
</head>
<body onload="MapLoad();">
<div id="Map" style="position:absolute; top:100px; height:90%; width:100%;"></div>
</body>
</html>
You could use the dedicated method DeleteAllShapes() of the VEShapeLayer class, see the MSDN:
https://msdn.microsoft.com/en-us/library/bb412473.aspx
See the example:
// Delete all shapes within the layer at the selected index.
function DeleteAllShapes()
{
layer = map.GetShapeLayerByIndex(selIndex);
layer.DeleteAllShapes();
IndexChanged(selIndex);
}
Also, I would recommend to use AJAX v7.0 instead of v6.3 since it's now deprecated and due to be out of support on November 30, 2016.
I'm trying to build a transform manager for KineticJS that would build a bounding box and allow users to scale, move, and rotate an image on their canvas. I'm getting tripped up with the logic for the anchor points.
http://jsfiddle.net/mharrisn/whK2M/
I just want to allow a user to scale their image proportionally from any corner, and also rotate as the hold-drag an anchor point.
Can anyone help point me in the right direction?
Thank you!
Here is a proof of concept of a rotational control I've made:
http://codepen.io/ArtemGr/pen/ociAD
While the control is dragged around, the dragBoundFunc is used to rotate the content alongside it:
controlGroup.setDragBoundFunc (function (pos) {
var groupPos = group.getPosition()
var rotation = degrees (angle (groupPos.x, groupPos.y, pos.x, pos.y))
status.setText ('x: ' + pos.x + '; y: ' + pos.y + '; rotation: ' + rotation); layer.draw()
group.setRotationDeg (rotation); layer.draw()
return pos
})
I am doing the same thing, and I've posted a question which is allmoast the same, but I found a link where you have the resize and move tool ready developed. So I have used the same. It does not contain the rotate tool however, but this can be a good start for you too, it is very simple and logical. Here is the link: http://www.html5canvastutorials.com/labs/html5-canvas-drag-and-drop-resize-and-invert-images/
I will come back with the rotation tool as well if I manage to get it working perfectly.
I hope I am not late yet for posting this code snippet that I made. I had the same problem with you guys dealing with this kind of task. Its been 3 days since I tried so many workarounds to mimic the fabricjs framework capability when dealing with images and objects. I could use Fabricjs though but it seems that Kineticjs is more faster/consistent to deal with html5.
Luckily, we already have existing plugin/tool that we could easily implement together with kineticjs and this is jQuery Transform tool. SUPER THANKS TO THE AUTHOR OF THIS! Just search this on google and download it.
I hope the code below that I created would help lots of developers out there who is pulling their hair off to solve this kind of assignment.
$(function() {
//Declare components STAGE, LAYER and TEXT
var _stage = null;
var _layer = null;
var simpleText = null;
_stage = new Kinetic.Stage({
container: 'canvas',
width: 640,
height: 480
});
_layer = new Kinetic.Layer();
simpleText = new Kinetic.Text({
x: 60,
y: 55,
text: 'Simple Text',
fontSize: 30,
fontFamily: 'Calbiri',
draggable: false,
name:'objectInCanvas',
id:'objectCanvas',
fill: 'green'
});
//ADD LAYER AND TEXT ON STAGE
_layer.add(simpleText);
_stage.add(_layer);
_stage.draw();
//Add onclick event listener to the Stage to remove and add transform tool to the object
_stage.on('click', function(evt) {
//Remove all objects' transform tool inside the stage
removeTransformToolSelection();
// get the shape that was clicked on
ishape = evt.targetNode;
//Add and show again the transform tool to the selected object and update the stage layer
$(ishape).transformTool('show');
ishape.getParent().moveToTop();
_layer.draw();
});
function removeTransformToolSelection(){
//Search all objects inside the stage or layer who has the name of "objectInCanvas" using jQuery iterator and hide the transform tool.
$.each(_stage.find('.objectInCanvas'), function( i, child ) {
$(child).transformTool('hide');
});
}
//Event listener/Callback when selecting image using file upload element
function handleFileSelect(evt) {
//Remove all objects' transform tool inside the stage
removeTransformToolSelection();
//Create image object for selected file
var imageObj = new Image();
imageObj.onload = function() {
var myImage = new Kinetic.Image({
x: 0,
y: 0,
image: imageObj,
name:'objectInCanvas',
draggable:false,
id:'id_'
});
//Add to layer and add transform tool
_layer.add(myImage);
$(myImage).transformTool();
_layer.draw();
}
//Adding source to Image object.
var f = document.getElementById('files').files[0];
var name = f.name;
var url = window.URL;
var src = url.createObjectURL(f);
imageObj.src = src;
}
//Attach event listener to FILE element
document.getElementById('files').addEventListener('change', handleFileSelect, false);
});
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);