I'm trying to display chart (Google Chart API) inside InfoWindow (Fusion Table layer), but the problem is with container "Uncaught Error: The container is null or not defined." whenever I try to include div inside InfoWindow.
I was trying to solve the problem based on this solution, but it's not working with fusion table
Add a google chart to a infowindow using google maps api
Please help
<script type="text/javascript">
google.load('visualization', '1', {packages: ['corechart']});
function drawVisualization() {
var queryText = encodeURIComponent("SELECT Year, Austria, Bulgaria, Denmark, Greece FROM 641716");
google.visualization.drawChart({
"containerId": 'visualization_div',
"dataSourceUrl": 'https://www.google.com/fusiontables/gvizdata?tq=',
"query":"SELECT Year, Austria, Bulgaria, Denmark, Greece FROM 641716",
"refreshInterval": 5,
"chartType": "PieChart",
"options": {
"title":"Yearly Coffee Consumption by Country",
"vAxis": {"title": "Year"},
"hAxis": {"title": "Cups"}
}
});
}
function initialize() {
var map = new google.maps.Map(document.getElementById('map-canvas'), {
center: new google.maps.LatLng(29.296435107347698, -29.54822280000008),
zoom: 2,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
var layer = new google.maps.FusionTablesLayer({
query: {
select: 'col0',
from: '1PoUAVtdJKOKnJT_ZYkoM7yDpGw-wNJMHXakPeC0'
},
map: map
});
google.maps.event.addListener(layer, 'click', function(e) {
drawVisualization(this);
e.infoWindowHtml += "<div id='visualization_div'></div>";{
}
});
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
PS.
One more thing ! It's possible to display chart from data from one row. In my example for one country that is clicked ?
I found also second way, maybe not so sophisticated but working
1. Create chart in Fusion Table
2. Copy link from Publish tab
3. Paste the link inside iframe. I made some tabs for this
'<div id="tab-2">' + //firts tab content
'<iframe src="https://www.google.com/fusiontables/embedviz?containerId=googft-gviz-canvas&q=select+col2%2C+col3+from+1NLk1HStpHzzSedbjQioau_7fSxeVlmb4G4A46MM+order+by+col3+desc+limit+6&viz=GVIZ&t=PIE&uiversion=2&gco_forceIFrame=true&gco_hasLabelsColumn=true&gco_useFirstColumnAsDomain=true&gco_is3D=false&gco_pieHole=0.5&gco_booleanRole=certainty&gco_colors=%5B%22%233366CC%22%2C%22%23DC3912%22%2C%22%23FF9900%22%2C%22%23109618%22%2C%22%23990099%22%2C%22%230099C6%22%2C%22%23DD4477%22%2C%22%2366AA00%22%2C%22%23B82E2E%22%2C%22%23316395%22%2C%22%23994499%22%2C%22%2322AA99%22%2C%22%23AAAA11%22%2C%22%236633CC%22%2C%22%23E67300%22%2C%22%238B0707%22%2C%22%23651067%22%2C%22%23329262%22%2C%22%235574A6%22%2C%22%233B3EAC%22%2C%22%23B77322%22%2C%22%2316D620%22%2C%22%23B91383%22%2C%22%23F4359E%22%2C%22%239C5935%22%2C%22%23A9C413%22%2C%22%232A778D%22%2C%22%23668D1C%22%2C%22%23BEA413%22%2C%22%230C5922%22%2C%22%23743411%22%5D&gco_hAxis=%7B%22useFormatFromData%22%3Atrue%2C+%22viewWindow%22%3A%7B%22max%22%3Anull%2C+%22min%22%3Anull%7D%2C+%22minValue%22%3Anull%2C+%22maxValue%22%3Anull%7D&gco_vAxes=%5B%7B%22useFormatFromData%22%3Atrue%2C+%22viewWindow%22%3A%7B%22max%22%3Anull%2C+%22min%22%3Anull%7D%2C+%22minValue%22%3Anull%2C+%22maxValue%22%3Anull%7D%2C%7B%22useFormatFromData%22%3Atrue%2C+%22viewWindow%22%3A%7B%22max%22%3Anull%2C+%22min%22%3Anull%7D%2C+%22minValue%22%3Anull%2C+%22maxValue%22%3Anull%7D%5D&gco_theme=maximized&gco_legend=none&width=00&height=150"frameborder="0"; scrolling="no"/>' +
'</div>' +
DEMO
And we can also insert query into URL so just selected rows are in Google Chart
e.row['Country_Name'].value
'<div id="tab-2">' + //firts tab content
'<iframe src="https://www.google.com/fusiontables/embedviz?containerId=googft-gviz-canvas&q=select+col0%2C+col1%2C+col2%2Ccol3+from+1r4egxlD-9QeK-4gBrdtTGQFrhdrBoxNhBwQbWUc+%20WHERE%20Country_Name=%27'+ e.row['Country_Name'].value +'%27+order+by+col1+asc+limit+10&viz=GVIZ&t=COLUMN&uiversion=2&gco_forceIFrame=true&gco_hasLabelsColumn=true&att=true&gco_theme=maximized&width=300&height=150"frameborder="0"; scrolling="no"/>' +
DEMO 2
It's a bit more difficult.
The infowindow of a FTLayer doesn't open immediately, because the data for the infowindow will be requested asynchronously.
When you call drawVisualization immediately there is no guarantee that the infowindow-content is already available in the DOM, the #visualization_div will not be available yet.
The problem: there is no domready-event for the infowindow of the FTLayer, you'll never know when the infowindow is ready.
Another problem: the chart will also be drawn asynchronously, the result would be a undesirable look of the infowindow(the chart will be drawn under the infowindow, not inside)
Possible solution(there may be others): use a custom infowindow instead:
<script type="text/javascript">
google.load('visualization', '1', {packages: ['corechart']});
//pass the infowindow as argument, we need it later
function drawVisualization(infowindow) {
var queryText = encodeURIComponent("SELECT Year, Austria, Bulgaria, \
Denmark, Greece FROM 641716");
/*note: we don't need the ContainerId here,
we use the node-reference with draw
*also note: we use ChartWrapper here, because we need
the ready-event of the chart to redraw the infowindow
*/
var chart=new google.visualization.ChartWrapper({
"dataSourceUrl": 'https://www.google.com/fusiontables/gvizdata?tq=',
"query":"SELECT Year, Austria, Bulgaria, Denmark, Greece FROM 641716",
"refreshInterval": 5,
"chartType": "PieChart",
"options": {
"title":"Yearly Coffee Consumption by Country",
"vAxis": {"title": "Year"},
"hAxis": {"title": "Cups"}
}
});
var ready=google.visualization.events.addListener(chart, 'ready', function(){
//re-assign the map-property to redraw the
//infowindow when the chart has been drawn
infowindow.setMap(infowindow.getMap());
//remove the ready-listener
google.visualization.events.removeListener(ready);
});
//draw the chart
chart.draw(infowindow.getContent().lastChild);
}
function initialize() {
map = new google.maps.Map(document.getElementById('map-canvas'), {
center: new google.maps.LatLng(29.296435107347698, -29.54822280000008),
zoom: 2,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
var layer = new google.maps.FusionTablesLayer({
query: {
select: 'col0',
from: '1PoUAVtdJKOKnJT_ZYkoM7yDpGw-wNJMHXakPeC0'
},
map: map,
//don't use the infowindows of the FTLayer
suppressInfoWindows:true
});
//a custom infowindow
infowindow=new google.maps.InfoWindow();
google.maps.event.addListener(layer, 'click', function(e) {
//call drawVisualization when the infowindow is ready
google.maps.event.addListenerOnce(infowindow,'domready',function(){
drawVisualization(infowindow);
});
//create the content for the infowindow
var node=document.createElement('div');
node.innerHTML=e.infoWindowHtml;
//create the node where the chart will be drawn
node.appendChild(document.createElement('div'));
//open the infowindow
infowindow.setOptions({position:e.latLng,content:node,map:map});
});
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
I solved this by rendering the charts to PNG with gnuplot and serving them as static images from a column of URLs in the Fusion Table.
It's not a Google Chart/javascript solution, but we have more data points than we want to plot on the fly with Google Chart anyway.
Related
I am trying to make an AJAX map Google map, where the place markers update but not the map.
I have an ajax setup with a settimeout function, which returns new javascript. When the new javascript is loaded into my HTML, the changes do not reflect on my google map.
When I go into the firefox inspector and try and manipulate the javascript, (to try and change marker GPS coordinates), nothing happens to the map, and the points are still the same. Why does that not affect the map?
I have looked at several links to try and help me, but none of them explain the logic behind the javascript.
My PHP script returns javascript in plain text. But when these get
added to the HTML, The google map does not change and looks like it
needs to be re initialized before it recognizes new javascript?
Can someone explain how I should update the javascript, so the map re-centers on the newest marker and places the newest marker without refreshing the page / re initializing the map?
<div id="map"></div>
<script>
function initMap() {
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 13,
center: {lat: -20.530637, lng: 46.450046}
});
// Create an array of alphabetical characters used to label the markers.
var labels = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
// Add some markers to the map.
// Note: The code uses the JavaScript Array.prototype.map() method to
// create an array of markers based on a given "locations" array.
// The map() method here has nothing to do with the Google Maps API.
var markers = locations.map(function(location, i) {
return new google.maps.Marker({
position: location,
label: labels[i % labels.length]
});
});
// Add a marker clusterer to manage the markers.
var markerCluster = new MarkerClusterer(map, markers,
{imagePath: 'https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/m'});
}
var locations = [
new google.maps.LatLng("-21.530637,46.450046),
new google.maps.LatLng("-22.530637,46.450046),
]
</script>
<script src="https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/markerclusterer.js">
</script>
<div class="result"></div>
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>
<script>
function refresh_div() {
jQuery.ajax({
url:'content.php',
type:'POST',
success:function(results) {
locations=results;
jQuery(".result").html(results);
}
});
}
t = setInterval(refresh_div,5000);
</script>
My "content.php" file. returns more google maps LatLng markers in plain text.
so PHP output is:
new google.maps.LatLng("-23.530637,46.450046"),
new google.maps.LatLng("-24.530637,46.450046"),
new google.maps.LatLng("-25.530637,46.450046"),
new google.maps.LatLng("-26.530637,46.450046")
I would like to summary the behavior of your ajax map:
Initialize map (probably with a set of predefined locations)
Repeatedly call content.php to retrieve new update of markers
Draw new markers to your map
The problem is that your code that handles ajax result doesn't do any map manipulation. In fact, it has to update the variable locations with new location set. Then create new markers with updated list of locations, then call MarkerCluster to apply them.
I created a fiddle to demonstrate it: https://jsfiddle.net/anhhnt/paffzadz/1/
What I did is extract the marker creating part from initMap, so that it can be called multiple times after locations is updated.
function updateMarker () {
// Create an array of alphabetical characters used to label the markers.
var labels = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
// Add some markers to the map.
// Note: The code uses the JavaScript Array.prototype.map() method to
// create an array of markers based on a given "locations" array.
// The map() method here has nothing to do with the Google Maps API.
var markers = locations.map(function(location, i) {
return new google.maps.Marker({
position: location,
label: labels[i % labels.length]
});
});
// Add a marker clusterer to manage the markers.
var markerCluster = new MarkerClusterer(map, markers,
{imagePath: 'https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/m'});
};
function initMap() {
window.map = new google.maps.Map(document.getElementById('map'), {
zoom: 3,
center: {lat: -28.024, lng: 140.887}
});
updateMarker(map);
};
var locations = [
{lat: -31.563910, lng: 147.154312},
{lat: -33.718234, lng: 150.363181},
{lat: -33.727111, lng: 150.371124}
]
function refresh_div() {
jQuery.ajax({
url:'/echo/json/',
type:'POST',
data: {
json: JSON.stringify([
{lat: -42.735258, lng: 147.438000},
{lat: -43.999792, lng: 170.463352}
])
},
success:function(results) {
locations.concat(results);
updateMarker();
}
});
}
t = setInterval(refresh_div,5000);
Hope it helps.
Perhaps you have simple syntax error in your code - missing closing double quote:
new google.maps.LatLng("-23.530637,46.450046"),
...
..or better - remove first double quote:
new google.maps.LatLng(-23.530637,46.450046),
...
I am mapping 20k records from Google Fusion table using standard circle. I would like to group them using MarkerClusters. Because there is filtering and search occuring, I am not sure where to place the var markerCluster = new MarkerClusterer(map, markers); code.
Here is the map.
Code snippet where markers are created:
//*New Fusion Tables Requirement* API key. found at https://code.google.com/apis/console/
//*Important* this key is for demonstration purposes. please register your own.
googleApiKey: "AIzaSyDj8qostHt2L3aetpO_LuipyS6YvfeZOFA",
//name of the location column in your Fusion Table.
//NOTE: if your location column name has spaces in it, surround it with single quotes
//example: locationColumn: "'my location'",
locationColumn: "geo_coordinates",
map_centroid: new google.maps.LatLng(40.7127,-74.0059), //center that your map defaults to
locationScope: "new york city", //geographical area appended to all address searches
recordName: "result", //for showing number of results
recordNamePlural: "results",
searchRadius: 805, //in meters ~ 1/2 mile
defaultZoom: 13, //zoom level when map is loaded (bigger is more zoomed in)
addrMarkerImage: 'images/blue_pin.png',
currentPinpoint: null,
initialize: function() {
$( "#result_count" ).html("");
geocoder = new google.maps.Geocoder();
var myOptions = {
zoom: MapsLib.defaultZoom,
center: MapsLib.map_centroid,
mapTypeId: google.maps.MapTypeId.TERRAIN,
};
map = new google.maps.Map($("#map_canvas")[0],myOptions);
map.setTilt(45);
map.setOptions({ styles : styles });
// maintains map centerpoint for responsive design
google.maps.event.addDomListener(map, 'idle', function() {
MapsLib.calculateCenter();
});
google.maps.event.addDomListener(window, 'resize', function() {
map.setCenter(MapsLib.map_centroid);
});
MapsLib.searchrecords = null;
Hi so I'm working a google maps element into an app I'm writing and am having trouble dropping a pin on the user's current location.
I can get the map to load a fusion table layer of pins, and center on the user's current location, but I'd like to be able to then drop a marker at the user's current location, and resize the map to fit all the markers. Is this possible? If not I can just set the zoom to an appropriate level.
This is the code I'm working with:
var geocoder = new google.maps.Geocoder();
function initialize() {
map = new google.maps.Map(document.getElementById('googft-mapCanvas'), {
center: new google.maps.LatLng([app:user-lat], [app:user-lon]),
zoom: 12,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
layer = new google.maps.FusionTablesLayer({
map: map,
heatmap: { enabled: false },
query: {
select: "col2, col0",
from: "1pbba_dFcpWQKQDXQUt9RNXp16GqX5Jz-NraafEI",
where: ""
},
options: {
styleId: 3,
templateId: 3
}
});
}
google.maps.event.addDomListener(window, 'load', initialize);
I should also say that the [app:user-lat] and [app:user-lon] calls are application specific, taking data from the mobile device, and will work to insert the current user's location. This is the reason I'm not doing a call for the current position through google maps api, thanks in advance for anyone taking the time to help.
To place a marker at the user's position, add this after you define your map:
var marker = new google.maps.Marker({
position: new google.maps.LatLng([app:user-lat], [app:user-lon]),
map: map
});
If you want to move it as the user moves, that will be a little more complicated, keep a reference to it and use marker.setPosition.
function initialize() {
map = new google.maps.Map(document.getElementById('googft-mapCanvas'), {
center: new google.maps.LatLng([app:user-lat], [app:user-lon]),
zoom: 12,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
var marker = new google.maps.Marker({
position: new google.maps.LatLng([app:user-lat], [app:user-lon]),
map: map
});
layer = new google.maps.FusionTablesLayer({
map: map,
heatmap: { enabled: false },
query: {
select: "col2, col0",
from: "1pbba_dFcpWQKQDXQUt9RNXp16GqX5Jz-NraafEI",
where: ""
},
options: {
styleId: 3,
templateId: 3
}
});
}
google.maps.event.addDomListener(window, 'load', initialize);
To center the map on the markers (or zoom the map to show them all, you will need to query the FusionTable for all the markers, construct a google.maps.LatLngBounds object from their locations, then use that as an argument to map.fitBounds.
Here are a couple of examples that do that (but with a different column layout (two column location) than your table. The concept can be adjusted for your column layout (query for the single column location, parse it to create a google.maps.LatLng and add it to the google.maps.LatLngBounds):
http://www.geocodezip.com/v3_FusionTablesLayer_centerOnMarkers.html
http://www.geocodezip.com/www_vciregionmap_comC.html
example that zooms and centers the map on the data in your table. Notes:
The GViz API that is used is limited to 500 rows, if you have more data that that you probably don't want to do this anyway.
The maps is centered on the data not the user.
Wonder if anyone can help me, I have setup a google map all works nicely. The only thing I cant work out how to do is to open an info window based on ID from an external html link that's not in the JS.
function initialize() {
// Create the map
// No need to specify zoom and center as we fit the map further down.
var map = new google.maps.Map(document.getElementById("map"), {
mapTypeId: google.maps.MapTypeId.ROADMAP,
disableDefaultUI: true
});
infowindow = new google.maps.InfoWindow();
// Custom markers
var icon = "img/marker.png";
// Define the list of markers.
// This could be generated server-side with a script creating the array.
var markers = [
{ val:0, lat: -40.149049, lng: 172.033095, title: "Title", html: "<div style='text-align:left'><h4 style='color:#0068a6;font-size:16px;margin:0px 0px 10px 0px;'>Title</h4><strong>Telephone</strong><br /><br />Address</div>" },
{ val:1, lat: -41.185765, lng: 174.827516, title: "Title", html: "<div style='text-align:left'><h4 style='color:#0068a6;font-size:16px;margin:0px 0px 10px 0px;'>Title</h4><strong>Telephone</strong><br /><br />Address</div>" },
];
// Create the markers ad infowindows.
for (index in markers) addMarker(markers[index]);
function addMarker(data) {
// Create the marker
var marker = new google.maps.Marker({
position: new google.maps.LatLng(data.lat, data.lng),
map: map,
title: data.title,
icon: icon,
id: data.val
});
// Create the infowindow with two DIV placeholders
// One for a text string, the other for the StreetView panorama.
var content = document.createElement("DIV");
var title = document.createElement("DIV");
title.innerHTML = data.html;
content.appendChild(title);
// Open the infowindow on marker click
google.maps.event.addListener(marker, "click", function() {
infowindow.setContent(content);
infowindow.open(map, this);
map.setCenter(this.position);
console.log(this.id);
});
}
// Zoom and center the map to fit the markers
// This logic could be conbined with the marker creation.
// Just keeping it separate for code clarity.
var bounds = new google.maps.LatLngBounds();
for (index in markers) {
var data = markers[index];
bounds.extend(new google.maps.LatLng(data.lat, data.lng));
}
map.fitBounds(bounds);
}
<p id="1">link to open marker</p>
Any help would be gratefully appreciated
Richard :)
The Golden Goose
Then in your js have a function to open the infowindow (such as show()) which takes the properties from that link (opening id 7).
function show(id){
myid = id;
if(markers[myid]){
map.panTo(markers[myid].getPoint());
setTimeout('GEvent.trigger(markers[myid], "click")',500);
map.hideControls();
}
}
That's the function I used previously with one of the marker managers from v2. You have to make sure you set an id for each marker as you set it and then you can call it.
The one thing I made sure of (to simplify matters) was to make sure the map marker set/array was exactly the same as the sql result I used on the page. That way, using id's was a piece of cake.
I have a website (www.auscem.com) with a link below the table to a Fusion table map. Currently, markers on the map are clickable to get the infoWindow, but I would like to make them mouseover instead. The present script is (slightly abbreviated):
var map;
var layer;
var tableid = xxxxxxx;
function load()
{
map = new google.maps.Map(document.getElementById('mapDiv'),
{
center: new google.maps.LatLng(-25.274, 133.775),
zoom: 4, //zoom
mapTypeId: google.maps.MapTypeId.ROADMAP //the map style
});
layer = new google.maps.FusionTablesLayer(tableid, {suppressInfoWindows: false});
layer.setQuery("SELECT 'Latitude' FROM " + tableid);
layer.setMap(map);
google.maps.event.addListener(layer, "click", function(event)
{
document.getElementById('siteInfo').innerHTML = event.infoWindowHtml;
});
}
// execute this
window.onload = load;
I've tried all sorts of things,, but have not gotten it working.
Ideas would be most welcome....
Paul
Have you seen the FusionTips utility library? It does tooltips based off of FusionTables data. You should be able to convert it to doing InfoWindows, I'm not sure how efficient it will be.