Google Sheets: Map Not Rendering with Custom Markers - google-maps

I am trying to render a map in Google Sheets and set custom markers. I have followed the App Script Docs that go over this topic: Visualization: Map. The map is rendering with the icons in the correct places, but the icons are the default set.
I checked my img URLs (by setting them as the default) and they work (the below urls are fake). I believe the issue is somewhere around matching the options.icons.keys with the data that is in the dataTable 3rd column.
Here is the raw data that is pulled from <?= jsonPoints ?>
[[29.59260664700021,-95.77028110299972,"Red"],
[29.591301814000055,-95.76907472100011,"Green"],
[29.591178932000005,-95.76802742100018,"Red"],
[29.587551849000003,-95.77229599100004,"Blue"]]
And here is the function that creates the map:
function drawMap() {
points = <?= jsonPoints ?>;
var data = new google.visualization.DataTable();
data.addColumn('number', 'Latitude');
data.addColumn('number', 'Longitude');
data.addColumn('string', 'Point Type');
data.addRows(JSON.parse(points))
var url = 'https://image.ibb.co/';
var options = {
showTooltip: true,
showInfoWindow: true,
useMapTypeControl: true,
icons: {
Red: {
normal: url + '/red.png',
selected: url + '/red.png'
},
Blue: {
normal: url + '/Blue.png',
selected: url + '/Blue.png'
},
Green: {
normal: url + '/Green.png',
selected: url + '/Green.png'
}
}
};
var map = new google.visualization.Map(document.getElementById('chart'));
map.draw(data, options);
};
I have tried putting quotation marks on the options.icons.keys, like "Green", but that did not work.
Any thoughts?
Thank you!

Figured it out. Added a fourth column that essentially had the same data. One column goes to the tooltip, the other is used as the marker:
data.addColumn('number', 'Latitude');
data.addColumn('number', 'Longitude');
data.addColumn('string', 'Tooltip_Data');
data.addColumn('string', 'Marker');
Now icons are rendered!

Related

Adding MapBox imagery to Cesium BaseLayerPicker

I'm able to add a custom base layer picker to may cesium viewer and can add imagery view models, but can't figure out how to add Map Box as one of those layers. Here is my code so far:
// Cesium Viewer
var viewer = new Cesium.Viewer('cesiumContainer', {
timeline: false,
animation: false,
geocoder: false,
baseLayerPicker: false,
imageryProvider: false
});
// Array of view models (map layers)
var imageryViewModels = [];
// MapBox layer (not working)
imageryViewModels.push(new Cesium.ProviderViewModel({
name : 'Map Box layer',
iconUrl : Cesium.buildModuleUrl('Widgets/Images/ImageryProviders/mapBox.png'),
tooltip : 'A custom layer',
creationFunction : function() {
return Cesium.createTileMapServiceImageryProvider({
url : url,
credit : 'MapBox'
});
}
}));
// Working layer from Cesium docs.
imageryViewModels.push(new Cesium.ProviderViewModel({
name : 'Natural Earth\u00a0II',
iconUrl : Cesium.buildModuleUrl('Widgets/Images/ImageryProviders/naturalEarthII.png'),
tooltip : 'Natural Earth II, darkened for contrast.\nhttp://www.naturalearthdata.com/',
creationFunction : function() {
return Cesium.createTileMapServiceImageryProvider({
url : Cesium.buildModuleUrl('Assets/Textures/NaturalEarthII')
});
}
}));
var blp2 = new Cesium.BaseLayerPicker('baseLayerPickerContainer', {
globe:viewer.scene,
imageryProviderViewModels : imageryViewModels
});
When I add the MapBox layer without the Base Layer Picker, it works great, eg:
var viewer = new Cesium.Viewer('cesiumContainer', {
timeline: false,
animation: false,
geocoder: false,
baseLayerPicker: false,
imageryProvider: new Cesium.UrlTemplateImageryProvider({
url: url
})
});
And for completion, my url is generated like this:
var MAPBOX_ACCESS_TOKEN = 'access-token';
var MAPBOX_STYLE_ID = 'style-id';
var MAPBOX_USERNAME = 'username';
var url = 'https://api.mapbox.com/styles/v1/' + MAPBOX_USERNAME + '/' + MAPBOX_STYLE_ID + '/tiles/256/{z}/{x}/{y}?access_token=' + MAPBOX_ACCESS_TOKEN;
When I try adding the MapBox layer with a ProviderViewModel, I get a 404 and the following Cesium error:
An error occurred in "b": Failed to obtain image tile X: 0 Y: 1 Level: 1.
I'm obviously constructing the ProviderViewModel incorrectly for a custom map layer, but I can't figure out what I need to change.
So I had to do some trial and error to get the MapBox URL right, but here is my solution for anyone else looking:
var MAPBOX_ACCESS_TOKEN = 'your_access_token';
var MAPBOX_STYLE_ID = 'style_id_from_your_account';
var MAPBOX_USERNAME = 'your_mapbox_username';
var defaultMap = 'https://api.mapbox.com/styles/v1/' + MAPBOX_USERNAME + '/' + MAPBOX_STYLE_ID + '/tiles/256/{z}/{x}/{y}?access_token=' + MAPBOX_ACCESS_TOKEN;
Then:
You can create an array to store all the different map themes a user can choose from.
var providerViewModels = [];
providerViewModels.push(new Cesium.ProviderViewModel({
name: 'Name of your map theme (can be anything)',
iconUrl: Cesium.buildModuleUrl("path_to_an_icon_image"),
tooltip: 'some tooltip text (optional)',
creationFunction: function() {
return new Cesium.UrlTemplateImageryProvider({
url: defaultMap
});
}
}));
Finally, you add the layers to your map:
var viewer = new Cesium.Viewer('cesiumContainer', {
imageryProviderViewModels: providerViewModels
});

Google charts csv ignore first rows

I have the below google charts code which reads from a local CSV file on my web server.
This is great & works well.
However, the files I will be using when this goes 'live' will be auto-generated and have a header of 10 rows, which I want to ignore (data should not be read).
Is there any way to alter this script to ignore the first 10 lines of the CSV file?
<script type='text/javascript'>
// load the visualization library from Google and set a listener
google.load("visualization", "1", {packages:["corechart"]});
google.setOnLoadCallback(drawChartfromCSV);
function drawChartfromCSV(){
// grab the CSV
$.get("EDU_INST_SCHOOL_EXPENDTR_29_1.csv", function(csvString) {
// transform the CSV string into a 2-dimensional array
var arrayData = $.csv.toArrays(csvString, {onParseValue: $.csv.hooks.castToScalar});
// this new DataTable object holds all the data
var data = new google.visualization.arrayToDataTable(arrayData);
// this view can select a subset of the data at a time
var view = new google.visualization.DataView(data);
view.setColumns([0,2]);
var options = {
title: "EDUCATIONAL INSTITUTIONS, SCHOOLS AND EXPENDITURE - INDIA",
hAxis: {title: data.getColumnLabel(0), minValue: data.getColumnRange(0).min, maxValue: data.getColumnRange(0).max},
vAxis: {title: data.getColumnLabel(2), minValue: data.getColumnRange(2).min, maxValue: data.getColumnRange(2).max},
legend: 'none'
};
var chart = new google.visualization.LineChart(document.getElementById('csv2chart'));
chart.draw(view, options);
});
}
</script>
you could remove the elements from the array before creating the DataTable...
Array.prototype.shift() removes the first element from an array
// transform the CSV string into a 2-dimensional array
var arrayData = $.csv.toArrays(csvString, {onParseValue: $.csv.hooks.castToScalar});
// remove unwanted headers
var removeRows = 10;
while (removeRows--) {
arrayData.shift();
}
// this new DataTable object holds all the data
var data = new google.visualization.arrayToDataTable(arrayData);

Leaflet MarkerCluster with GeoJson

I am currently working on a Leaflet Project where I use external geojson files as data input. Since the json contains a lot of objects I would like to use the MarkerCluster plugin which I got from Mappbox:
<script src='https://api.tiles.mapbox.com/mapbox.js/plugins/leaflet-markercluster/v0.4.0/leaflet.markercluster.js'></script>
<link href='https://api.tiles.mapbox.com/mapbox.js/plugins/leaflet-markercluster/v0.4.0/MarkerCluster.css' rel='stylesheet' />
<link href='https://api.tiles.mapbox.com/mapbox.js/plugins/leaflet-markercluster/v0.4.0/MarkerCluster.Default.css' rel='stylesheet' />
Displaying the json-layer without the clustering works just fine, but if i try to assign it to the cluster nothing is displayed.
var markersBar = L.markerClusterGroup();
var barLayer = new L.GeoJSON.AJAX("json/eat_drink/bar.geojson", {
pointToLayer: function(feature, latlng) {
var icon = L.icon({
iconSize: [27, 27],
iconAnchor: [13, 27],
popupAnchor: [1, -24],
iconUrl: 'icon/' + feature.properties.amenity + '.png'
});
return L.marker(latlng, {icon: icon})
},
onEachFeature: function(feature, layer) {
layer.bindPopup(feature.properties.name + ': ' + feature.properties.opening_hours);
}
});
markersBar.addLayer(barLayer);
console.log(markersBar);
map.addLayer(markersBar);
The console.log output lets me assume that there are no objects, but I don't get it why.
Object { options: Object, _featureGroup: Object, _leaflet_id: 24, _nonPointGroup: Object, _inZoomAnimation: 0, _needsClustering: Array[0], _needsRemoving: Array[0], _currentShownBounds: null, _queue: Array[0], _initHooksCalled: true }
What am I doing wrong?
Well it looks like you are using Leaflet-Ajax...so an async request is made to grab your geojson..and your immediate next line is markersBar.addLayer(barLayer);..which would contain nothing since the request is almost certainly not complete yet...
Instead, I believe you can use the loaded event provided in the documentation like
barLayer.on('data:loaded', function () {
markersBar.addLayer(barLayer);
console.log(markersBar);
map.addLayer(markersBar);
});
For anyone looking for a straight forward example for adding a marker cluster with geojson ajax to a map, binding pop-ups and adding to layer control:
// pop-up function
function popUp(f, l) {
var out = [];
if (f.properties) {
for (key in f.properties) {
out.push(key + ": " + f.properties[key]);
}
l.bindPopup(out.join("<br />"));
}
}
// add layer to map and layer control
function add_layer(layr, layr_name) {
map.addLayer(layr);
layerControl.addOverlay(layr, layr_name);
}
// fire ajax request
var points = new L.GeoJSON.AJAX("../data/points.geojson", { onEachFeature: popUp });
// create empty marker cluster group
var markers = L.markerClusterGroup()
// when geojson is loaded, add points to marker cluster group and add to map & layer control
points.on('data:loaded', function () {
markers.addLayer(points);
add_layer(markers, "Point Markers")
});

OpenLayers - clear 'map' div

I am using OpenLayers to display dynamically loaded images. The code I am using is:
var map;
function init(strURL) {
map = new OpenLayers.Map('map');
var options = { numZoomLevels: 3,
isBaseLayer: true, };
var graphic = new OpenLayers.Layer.Image(
'City Lights',
strURL + "?sc=page",
new OpenLayers.Bounds(-180, -88.759, 180, 88.759),
new OpenLayers.Size(580, 288),
options
);
// graphic.events.on({
// loadstart: function () {
// OpenLayers.Console.log("loadstart");
// },
// loadend: function () {
// OpenLayers.Console.log("loadend");
// }
// });
var jpl_wms = new OpenLayers.Layer.WMS("NASA Global Mosaic",
"http://t1.hypercube.telascience.org/cgi-bin/landsat7",
{ layers: "landsat7" }, options);
map.addLayers([graphic, jpl_wms]);
map.addControl(new OpenLayers.Control.LayerSwitcher());
map.zoomToMaxExtent();
}
I am calling this function on a button click event and passing the strURL (sources of the images) at that time. The result is, with each click a different image is loaded and displayed on the web page but is not clearing the previous image. So I 5 different images on the webpage are shown with 5 clicks and so on.
My javascript knowledge is limited, so my apologies if this is a stupid question. How to stop this behavior? Thanks for any assistance.
Also, I didn't quite understand the lines:
var jpl_wms = new OpenLayers.Layer.WMS("NASA Global Mosaic",
"http://t1.hypercube.telascience.org/cgi-bin/landsat7",
{ layers: "landsat7" }, options);
But I know these lines are needed since I'm getting js error if I remove them.
So currently you are calling init(strURL) with each button click? Divide that code into two parts:
On page load, create map and layer objects
On button click, just update URL of existing image layer. Image layer has setUrl(url) method for that: http://dev.openlayers.org/apidocs/files/OpenLayers/Layer/Image-js.html#OpenLayers.Layer.Image.setUrl
Here is sample, that should explain it: http://jsfiddle.net/mEHrN/6/
About var jpl_wms = ... - it creates WMS layer, that should display Landsat imagery (but that URL doesn't seem to work). If you remove it, remember also to remove it from map.addLayers:
map.addLayers([graphic]);
Probably this was reason, why you got JS error.

OpenLayers Google Maps Projection Problem w/ KML

This is my first time on stackoverflow and working with Openlayers & Google Maps.
I've been browsing different forums & sites, including OpenLayers.org, to solve my issue. I've done searches on a combination of the following: openlayers, google map projections, and spherical mercator... but I have not found a solution.
Problem: The KML data from a web service call (func setDataSource) is shifting as I zoom in and out of the map. My guess is that the projections in my code are wrong or perhaps wrongly placed. I don't have any background on map projections so it is difficult to digest mapping terminology online :-(. Can someone help?
//start here
var options = {
projection: new OpenLayers.Projection("EPSG:900913"),
displayProjection: new OpenLayers.Projection("EPSG:4326"),
units: "m",
numZoomLevels: 18,
maxResolution: 156543.0339,
maxExtent: new OpenLayers.Bounds(-20037508, -20037508,
20037508, 20037508)};
//*map = new OpenLayers.Map('map');
map = new OpenLayers.Map('map', options);
var gphy = new OpenLayers.Layer.Google(
"Google Street",
{'sphericalMercator':true});
// Add the background images via WMS
var bglayer = new OpenLayers.Layer.WMS( "OpenLayers WMS",
"http://labs.metacarta.com/wms/vmap0", {layers: 'basic'}, {'reproject': true});
//map.addLayer(bglayer);
map.addLayers([gphy, bglayer]);
map.addControl(new OpenLayers.Control.LayerSwitcher());
map.zoomToMaxExtent(); //* Zoom all the way out, this command also initalizes the map
OpenLayers.Console.log("initialized");
}
function setDataSource() {
OpenLayers.Console.log("Setting data source to " + OpenLayers.Util.getElement('loc').value);
if (layer != undefined) {map.removeLayer(layer)};
if (selectControl != undefined) {map.removeControl(selectControl)};
// Encode the destination url as a parameter string.
var params = OpenLayers.Util.getParameterString({url:OpenLayers.Util.getElement('loc').value})
// Make the http request to the transformer, with the destination url as a parameter.
layer = new OpenLayers.Layer.GML("KML", transformerURL + params,
{
format: OpenLayers.Format.KML,
formatOptions: {
extractStyles: true,
extractAttributes: true,
maxDepth: 2,
//projection: new OpenLayers.Projection("EPSG:4326"),
}
});
map.addLayer(layer);
Thank you!!!
I figured out the problem. Instead of GML, I tried using Vector instead like this:
layer = new OpenLayers.Layer.Vector("KML", {
projection: map.displayProjection,
strategies: [new OpenLayers.Strategy.Fixed()],
protocol: new OpenLayers.Protocol.HTTP({
url: transformerURL + params,
format: new OpenLayers.Format.KML({
extractStyles: true,
extractAttributes: true
})
})
});
I found the solution in this sundials example: http://openlayers.org/dev/examples/sundials-spherical-mercator.html :-) Hope this helps anyone w/ the same problem.