Adding MapBox imagery to Cesium BaseLayerPicker - cesiumjs

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
});

Related

Forge Vewer v7 - Search in Default UI

I'm trying to use Autodesk.InViewerSearch extension in Forge viewer v7, but I keep getting error that new Autodesk.Viewing.A360ViewingApplication('forgeViewer', options) is not a constructor. Does this extension work in viewer v7? If I set new Autodesk.Viewing.GuiViewer3D(htmlDiv, config3d) my app works, but Autodesk.InViewerSearch is not registered.
This is my Autodesk.Viewing.Initializer:
Autodesk.Viewing.Initializer(options, function onInitialized() {
// var randomId = makeid(36);
var documentId = 'urn:' + urn;
console.log(documentId);
var config3d = {
loaderExtensions: { svf: "Autodesk.MemoryLimited" },
extensions: [
'Autodesk.DocumentBrowser',
'Autodesk.Viewing.MarkupsCore',
'Autodesk.Viewing.MarkupsGui',
'Autodesk.VisualClusters',
'Autodesk.InViewerSearch',
'ToolbarExtension',
'BoundingBoxExtension',
],
inViewerSearchConfig: {
uiEnabled: false,
relatedItemsTab: {
enabled: true, //If false, the tab is hidden.
displayName: 'This Item',
pageSize: 20
},
loadedModelTab: {
enabled: true, //If false, the tab is hidden.
displayName: 'This View',
pageSize: 50
}
}
};
//viewerApp = new Autodesk.Viewing.A360ViewingApplication('forgeViewer', options);
//viewerApp.registerViewer(viewerApp.k3D, Autodesk.Viewing.GuiViewer3D, config3d);
// viewerApp.loadDocumentWithItemAndObject(documentId);
//viewerApp.registerViewer(viewerApp.k3D, Autodesk.Viewing.Private.GuiViewer3D, config3d);
//viewerApp.loadDocument(documentId, onDocumentLoadSuccess, onDocumentLoadFailure);
var htmlDiv = document.getElementById('forgeViewer');
viewer = new Autodesk.Viewing.GuiViewer3D(htmlDiv, config3d);
var startedCode = viewer.start();
if (startedCode > 0) {
console.error('Failed to create a Viewer: WebGL not supported.');
return;
}
console.log('Initialization complete, loading a model next...');
var documentId = 'urn:' + urn;
Autodesk.Viewing.Document.load(documentId, onDocumentLoadSuccess, onDocumentLoadFailure);
});
My options file looks like this
var options = {
env: 'AutodeskProduction',
getAccessToken: getForgeToken,
api: 'derivativeV2' + (atob(urn.replace('_', '/')).indexOf('emea') > -1 ? '_EU' : ''),
/*memory: {
limit: 1024 // in MB
}*/
};
And in my index.html I've included:
<script src="https://developer.api.autodesk.com/modelderivative/v2/viewers/7.*/three.min.js"></script>
<script src="https://developer.api.autodesk.com/modelderivative/v2/viewers/7.*/viewer3D.min.js"></script>
I haven't found the A360ViewingApplication class nor the Autodesk.InViewerSearch extension in the Forge Viewer codebase so I'm afraid these have been removed in version 7. Let us know what exactly you wanted to achieve with the extension, I'm sure there is a different way of implementing that goal with the viewer version 7.

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")
});

jQuery Mobile don't' execute function after pageshow

I have in my Phonegap app this JQM; I create a Google map and I load markers from json file.
When i launch page2, i see the first console.log (coordinates) and the last console.log (2222222) - The intermediate console.log that contains numberOfElements is displays only the first time. If I see the map and i return back the whole script isn't loaded.
Why?
$(document).on('pageshow', '#page2', function () {
var latnow = Number(localStorage.getItem("lat"));
var lngnow = Number(localStorage.getItem("lng"));
var coordinate = new google.maps.LatLng(latnow, lngnow);
console.log(latnow + ' ' + lngnow);
$('#map_canvas').gmap({
'center': coordinate,
'disableDefaultUI': true,
'zoom': 5,
'scrollwheel': false,
'panControl': false
});
$('#map_canvas').gmap().bind('init', function () {
var images = "img/icon.png";
var images2 = "img/icon2.png";
$.getJSON('http://www.site.com/app/json.php?lat=' + latnow + '&lat=' + lngnow + '', function (data) {
var myObject = data;
var numberOfElements = data.markers.length;
console.log(numberOfElements); // <- !!!!!!
if (numberOfElements == 0) {
alert("no result");
$.mobile.changePage("#home");
}
var myObject = JSON.stringify(myObject);
localStorage.setItem("json_near", myObject);
$('#map_canvas').gmap('addMarker', {
'position': coordinate,
'icon': images2,
'bounds': true
});
//marker da json
$.each(data.markers, function (i, marker) {
$('#map_canvas').gmap('addMarker', {
'position': new google.maps.LatLng(marker.latitude, marker.longitude),
'draggable': false,
'bounds': true,
'icon': images
}).click(function () {
$('#map_canvas').gmap('openInfoWindow', {
'content': marker.content,
'maxWidt': 200,
'maxHeight': 400,
'autoScroll': true
}, this);
});
});
});
});
map_element = document.getElementById("map_canvas");
var mapwidth = $(window).width();
var mapheight = $(window).height();
$("#map_canvas").height(mapheight);
$("#map_canvas").width(mapwidth);
google.maps.event.trigger(map_element, 'resize');
console.log("2222222");
});
I assume you are using this plugin - http://code.google.com/p/jquery-ui-map/ , right?
I think it is not a problem of jquery mobile. The pageshow event is called as you can see from those console.log messages.
Try to stick console.log("xxx") into the gmap init handler. I think this is the one which is NOT called at the second time.
Something like
$('#map_canvas').gmap().bind('init', function () {
console.log("xxxxxx");
var images = "img/icon.png";
var images2 = "img/icon2.png";
...
...
});
do you see xxxxxxx in the console every time you get in the page?
If not, try to find the way how to check whether the map was already initialized (second, third, fourth time, etc.) and then, call getJSON directly.

Openlayers zoom in on cluster

Is it possible to zoom in on cluster on click? I also don't know how to disable cluster popup. I read this question , but still have no idea how to do it.
Here is the code:
<html>
<script src="../ol/OpenLayers.js"></script>
<script>
var map, select;
var lat = 53.507;
var lon = 28.145;
var zoom = 7;
function init() {
map = new OpenLayers.Map("map",
{ maxExtent: new OpenLayers.Bounds(-20037508.34,-20037508.34,20037508.34,20037508.34),
numZoomLevels: 19,
maxResolution: 156543.0399,
units: 'm',
projection: new OpenLayers.Projection("EPSG:900913"),
displayProjection: new OpenLayers.Projection("EPSG:4326"),
controls: [
new OpenLayers.Control.Navigation(),
new OpenLayers.Control.PanZoomBar(),
new OpenLayers.Control.ScaleLine(),
new OpenLayers.Control.Permalink('permalink'),
new OpenLayers.Control.Attribution(),
new OpenLayers.Control.MousePosition()
] });
var osm = new OpenLayers.Layer.OSM("OpenStreetMap");
map.addLayer(osm);
var lonLat = new OpenLayers.LonLat(lon, lat).transform(map.displayProjection, map.projection);
if (!map.getCenter()) map.setCenter (lonLat, zoom);
var MyStyle = new OpenLayers.Style({
// 'cursor' : 'pointer',
fillColor : "#336699",
fillOpacity : 0.9,
fontColor: "#000080",
fontFamily: "sans-serif, Arial",
// fontWeight: "bold",
externalGraphic: "atm.png",
graphicWidth: 32,
graphicHeight: 37,
label: "${count}",
labelAlign: "ct",
fontSize: "15px",
});
var layer = new OpenLayers.Layer.Vector("Atm", {
protocol: new OpenLayers.Protocol.HTTP({
url: "atm.txt",
format: new OpenLayers.Format.Text({extractStyles: true}),
params: {
extractAttributes: false,
}
}),
styleMap: MyStyle, <!-- --------------------- style -->
projection: map.displayProjection,
strategies: [
new OpenLayers.Strategy.BBOX({ratio: 1, resFactor: 1.1}),
new OpenLayers.Strategy.Cluster({distance: 50, threshold: 3})
]
});
map.addLayer(layer);
// Interaction; not needed for initial display.
selectControl = new OpenLayers.Control.SelectFeature(layer);
map.addControl(selectControl);
selectControl.activate();
layer.events.on({
'featureselected': onFeatureSelect,
'featureunselected': onFeatureUnselect
});
}
// Needed only for interaction, not for the display.
function onPopupClose(evt) {
// 'this' is the popup.
var feature = this.feature;
if (feature.layer) { // The feature is not destroyed
selectControl.unselect(feature);
} else { // After "moveend" or "refresh" events on POIs layer all
// features have been destroyed by the Strategy.BBOX
this.destroy();
}
}
function onFeatureSelect(evt) {
feature = evt.feature;
popup = new OpenLayers.Popup.FramedCloud("featurePopup",
feature.geometry.getBounds().getCenterLonLat(),
new OpenLayers.Size(100,100),
"<h2>"+feature.attributes.title + "</h2>" +
feature.attributes.description,
null, true, onPopupClose);
feature.popup = popup;
popup.feature = feature;
map.addPopup(popup, true);
}
function onFeatureUnselect(evt) {
feature = evt.feature;
if (feature.popup) {
popup.feature = null;
map.removePopup(feature.popup);
feature.popup.destroy();
feature.popup = null;
}
}
</script>
</head>
<body onload="init()">
<div id="map"></div>
</body>
</html>
Thanks. Your post does not have much context to explain the code sections; please explain your scenario more clearly.
function onFeatureSelect(event) {
if(!event.feature.cluster) // if not cluster
{
// handle your popup code for the individual feature
}
else
{
// fetch the cluster's latlon and set the map center to it and call zoomin function
// which takes you to a one level zoom in and I hope this solves your purpose :)
map.setCenter(event.feature.geometry.getBounds().getCenterLonLat());
map.zoomIn();
}
}
Using the example code in the linked question I would iterate over all features in the cluster to create a BBX, and then zoom into that extent.
var cluster_bounds=new OpenLayers.Bounds();
event.feature.cluster.forEach(function(feature){
clouster_bounds.extend(feature.geometry);
})
map.zoomToExtent(cluster_bounds)
If you really don't know how to disable the popups then remove these functions:
function onFeatureSelect(evt) {
function onFeatureUnselect(evt) {
And replace it with:
function onFeatureSelect(event) {
var cluster_bounds=new OpenLayers.Bounds();
event.feature.cluster.forEach(function(feature){
cluster_bounds.extend(feature.geometry);
});
map.zoomToExtent(cluster_bounds);
}

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.