I'm trying to add custom controls to a Google map using the API. I already have two custom controls added and they work just fine. I tried to copy and paste the code for a third control (changing the relevant variables of course) and I keep getting the above error (in the title).
Chrome console and Firebug don't seem to point to a particular problem (it breaks inside the google maps api code). By progressively commented out lines, I've narrowed it down to this particular line:
map.controls[google.maps.ControlPosition.TOP_RIGHT].push(churchControlDiv);
The full code for adding the control is as follows:
function ChurchControl(churchControlDiv, map) {
churchControlDiv.style.padding = '5px 0px';
var churchControlUI = document.createElement('DIV');
churchControlUI.style.backgroundColor = 'white';
churchControlUI.style.borderStyle = 'solid';
churchControlUI.style.borderWidth = '1px';
churchControlUI.style.borderColor = 'gray';
churchControlUI.style.boxShadow = 'rgba(0, 0, 0, 0.398438) 0px 2px 4px';
churchControlUI.style.cursor = 'pointer';
churchControlUI.style.textAlign = 'center';
churchControlUI.title = 'Click to see Churches';
churchControlDiv.appendChild(churchControlUI);
var churchControlText = document.createElement('DIV');
churchControlText.style.fontFamily = 'Arial,sans-serif';
churchControlText.style.fontSize = '13px';
churchControlText.style.padding = '1px 6px';
churchControlText.style.fontWeight = 'bold';
churchControlText.innerHTML = 'Churches<br>แสดงจำนวนคริสเตียน';
churchControlUI.appendChild(churchControlText);
google.maps.event.addDomListener(churchControlUI, 'click', function() {
toggle(churches);
if (churchControlText.style.fontWeight == 'bold') {
churchControlText.style.fontWeight = 'normal';
} else {
churchControlText.style.fontWeight = 'bold';
}
});
google.maps.event.addDomListener(churchControlUI, 'mouseover', function() {
churchControlUI.style.backgroundColor = '#e8e8e8';
});
google.maps.event.addDomListener(churchControlUI, 'mouseout', function() {
churchControlUI.style.backgroundColor = 'white';
});
}
function initialize(){
map = new google.maps.Map(document.getElementById("map_canvas"), {
center: centerLatLng,
zoom: 7,
streetViewControl: false,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
var churchControlDiv = document.createElement('DIV');
var churchControlDiv = new ChurchControl(churchControlDiv, map);
churchControlDiv.index = 3;
map.controls[google.maps.ControlPosition.TOP_RIGHT].push(churchControlDiv);
}
Any ideas? Any reason why having 3 controls would be a problem?
I had the same error pop up on my console whilst following the tutorial for a different reason.
Rather than using default javascript DOM manipulation, I'd been using jQuery to create my elements, e.g.
var controlDiv = $('<div></div>');
var controlUI = $('<div class="alert alert-info"></div>');
controlDiv.append(controlUI);
var controlText = $('<div>Control text here</div>');
controlUI.append(controlText);
Doing this is fine, so long as you give the DOM node to the map (and not the jQuery element!) at the end, using controlUI[0] or controlUI.get(0), like this:
map.controls[google.maps.ControlPosition.TOP_RIGHT].push(controlDiv[0]);
See also:
How to get the native DOM element from a jQuery object - jQuery FAQ
I followed the tutorial, which is very close to your code.
This line near the end needs to change
var churchControlDiv = new ChurchControl(churchControlDiv, map);
Replace churchControlDiv with churchControl or another name because churchControlDiv should not be overwritten.
See here http://jsfiddle.net/FTjnE/2/
I marked my changes with //CHANGED an alert for the click, and new map center
The general underlying cause of this issue seems to be the element or its properties being removed or otherwise made not present. Maps API is trying to find the zIndex in the style property.
I had this issue in a Vue app custom component that interacted with the Maps API controls. We resolved it by exercising more caution in the teardown of the component.
Basically you need to ensure that you don't add a null element to the control, and don't make the element or its properties null before removing it, by doing something funky with say, v-if.
Related
I am working with leaflet and wanted to add some custom controls on my leaflet map. That worked fine. However my problem is, that those custom controls are more in front of the map and not 'on' the map.
So here an example to better understand what i mean: (the navbar is in the same html file as the leaflet map)
I have a navbar and beneath there is the leaflet map. In the left corner of the leaflet map is a custom control (compass). So now when I use the dropdown menu from the navbar, i barely can click on on of the options, as the custom control is 'in front of it' and is blocking the hit bock. (picture below).
Is there a way to put the custom control more on the map than in front of the map?
Here is my custom control (compass):
onAdd: function() {
var controlDiv = L.DomUtil.create('div', 'leaflet-compass');
L.DomEvent
.addListener(controlDiv, 'click', L.DomEvent.stopPropagation)
.addListener(controlDiv, 'click', L.DomEvent.preventDefault);
var compassDiv = document.createElement('div');
compassDiv.id = 'compassGroup';
var compassImage = document.createElement('img');
compassImage.id = 'cpImage';
compassImage.setAttribute('src', 'images/kompass.png');
var speedHeadline = document.createElement('h2');
speedHeadline.id = 'speedHL';
var arrowImage = document.createElement('img');
arrowImage.id = 'arImage';
arrowImage.setAttribute('src', 'images/arrow.png');
controlDiv.appendChild(compassDiv);
compassDiv.appendChild(compassImage);
compassDiv.appendChild(arrowImage);
controlDiv.appendChild(speedHeadline);
return controlDiv;
}
});
L.control.compass = function(options) {
return new L.Control.Compass(options);
};
function initCompass(map, timestamp) {
var compassControl = L.control.compass();
map.addControl(compassControl);
rotateCompass(timestamp);
}
Good Day to everyone, Im developing a site that has a mapping features.
My goal here is make it drag if you click the marker.
Here is my code
else if (select1.value === "Arson"){
var note = document.getElementById('note');
var datepick = document.getElementById('demo1');
var timepick = document.getElementById('timepick');
layerpoly.on('click', function(e){
var markerA = new L.Marker(e.latlng,{icon: Icon1});
markerA.bindPopup("</a><br><strong>ARSON</strong></br><strong>Date:</strong>"+datepick.value+"</br><strong>Time:</strong>"+timepick.value+"</br><strong>Address:</strong>"+note.value+"<strong><br><strong>Suspect Sketch</strong><br><a href=legends/suspect.jpg rel=lightbox><img src = legends/suspect.jpg height=100 width = 100/><br> ").addTo(map);
closure1 (markerA)
var ll = markerA.getLatLng();
document.querySelector('#userLat').value = ll.lat;
document.querySelector('#userLng').value = ll.lng;
marker.dragging.enable();
});
}
The output of the code above is if i select arson. I will place a marker on map.
My question is how can i make it draggable if click that marker?
by the way this code
document.querySelector('#userLat').value = ll.lat;
document.querySelector('#userLng').value = ll.lng;
is connected into two textboxes with id of userLat and useLng. How can i update this textbox if i drag that marker?
Any Help? TY
Here's the documentation for L.Marker: http://leafletjs.com/reference.html#marker As you can see there is absolutely no method called dragging.enable so calling marker.dragging.enable(); will never work and should throw an obvious error to your browserconsole. There is however a draggable option which you can use when you instanciate the marker:
var markerA = new L.Marker(e.latlng,{
icon: Icon1,
draggable: true
});
Here's a working example on Plunker: http://plnkr.co/edit/Au3XlD?p=preview
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.
I am developing an application that has multiple tabs (using jQuery UI). These can be opened and closed by the user. Within each tab is an rGraph visualisation from the JavaScript InfoVis Toolkit (http://philogb.github.io/jit/static/v20/Jit/Examples/RGraph/example1.html). (The code for both the tabs and the visualisations are very similar to the examples on their respective websites)
Whenever I create a new tab, the rGraph is generated correctly. This seems to scale quite nicely and I can click back and forth through multiple tabs without any problems. However, if I interact with an rGraph in any way (e.g. by clicking on a node to move it around), the existing rGraphs in the other tabs stop working. When I click on any of the existing rGraphs, it produces the error: TypeError: node is undefined. In other words, new instances work fine but clicking on the newest one breaks the previous ones.
Is there anything that can be done about this?
Note: There does appear to be some allowance for multiple instances in the docs - you can create each instance with a different variable name, e.g. var graph1 = new ... var graph2 = new ... etc. This does indeed work, but as the tabs (and therefore the graphs) are dynamically generated, I cannot assign specific variable names like this. I tried doing the following:
var graphs = {};
graphs[unique_id_i_pass_in] = new Graph();
...but this didn't seem to make any difference.
EDIT: Here is the code I am using to call the rGraphs (document_id is the unique variable I am passing in for each graph):
var doc_rgraph = {};
//init RGraph
doc_rgraph[document_id] = new $jit.RGraph({
//Where to append the visualization
injectInto: 'document_vis_'+document_id,
//Optional: create a background canvas that plots
//concentric circles.
background: {
CanvasStyles: {
//Colour of the background circles
strokeStyle: '#C5BE94'
}
},
//Add navigation capabilities:
//zooming by scrolling and panning.
Navigation: {
enable: true,
panning: true,
zooming: 10
},
//Set Node and Edge styles.
Node: {
//Colour of the actual nodes
color: '#660000'
},
Edge: {
//Color of lines between nodes
color: '#660000',
lineWidth:1.5
},
onBeforeCompute: function(node){
Log.write("Centering " + node.name + "...");
},
//Add the name of the node in the correponding label
//and a click handler to move the graph.
//This method is called once, on label creation.
onCreateLabel: function(domElement, node){
domElement.innerHTML = node.name;
domElement.onclick = function(){
doc_rgraph[document_id].onClick(node.id, {
onComplete: function() {
Log.write("Done");
}
});
};
},
//Change some label dom properties.
//This method is called each time a label is plotted.
onPlaceLabel: function(domElement, node){
var style = domElement.style;
style.display = '';
style.cursor = 'pointer';
if (node._depth == 0) {
style.fontSize = "0.8em";
//Text colour of ring 1 nodes
style.color = "#000000";
style.backgroundColor = "#F05322";
style.padding = "1px 3px";
} else if (node._depth == 1) {
style.fontSize = "0.8em";
//Text colour of ring 1 nodes
style.color = "#FFFFFF";
style.backgroundColor = "#164557";
style.padding = "1px 3px";
} else if(node._depth == 2){
style.fontSize = "0.7em";
//Text colour of ring 2 nodes
style.color = "#333333";
style.backgroundColor = "#CAC399";
} else {
style.display = 'none';
}
var left = parseInt(style.left);
var w = domElement.offsetWidth;
style.left = (left - w / 2) + 'px';
},
onComplete: function(){
Log.write("Done");
}
});
//load JSON data
doc_rgraph[document_id].loadJSON(document_data[document_id]);
//trigger small animation
doc_rgraph[document_id].graph.eachNode(function(n) {
var pos = n.getPos();
pos.setc(-200, -200);
});
doc_rgraph[document_id].compute('end');
doc_rgraph[document_id].fx.animate({
modes:['polar'],
duration: 1000
});
//end
Creating a new object on mouseclick as a way for users to create reference points (which I call 'crumbs') when reading large web documents. I've got this working with a new Image() function, however, that won't let me assign a tabindex to each new image created by mouseclick (posX, posY). 'crumbtoggle' simply acknowledges that the crumb dropping tool has been selected.
working new Image() function:
function draw_crumb()
{
var b_canvas = document.getElementById("b");
var b_context = b_canvas.getContext("2d");
var crumb = new Image();
crumb.src = "crumb.gif";
if(crumbtoggle.className == "on")
{
b_context.drawImage(crumb, posX-20, posY-20, 50, 75);
}
}
non-working new Object () function:
function draw_crumb()
{
var b_canvas = document.getElementById("b");
var b_context = b_canvas.getContext("2d");
var crumb = new Object();
crumb.type = "button";
crumb.src = "crumb.gif";
crumb.tabindex = 1;
if(crumbtoggle.className == "on")
{
b_context.drawObject(crumb, posX-20, posY-20, 50, 75);
}
}
I've looked in to applying focus to the new Image objects, but that doesn't seem to be a good alternative to tabindex attributes. Any ideas would be greatly appreciated.
An HTML5 Canvas is like a real-world canvas with instantly-drying paint. When you paint a rectangle or line or image on the canvas, it becomes part of the canvas. You cannot later re-order the items, or move them relative to each other. It is not a separate entity that can get focus.
Any sort of focus management integrated with the browser's handling of focus will have to be done through form inputs or anchors recognized by the browser.
It's not clear to me why you need a canvas, or if you need one at all.