Loading a view after Google Maps load in Backbone.js - backbone.js

I have the following setup:
class App.Views.Maps extends Backbone.View
el: '#map'
events:
initialize: ->
#searchModel = new App.Models.Search()
#view = new App.Views.MapBox(map: this)
#render()
render: ->
#loadMap()
$("[rel=tooltip]").tooltip()
loadMap: =>
osmMapType = new google.maps.ImageMapType(
getTileUrl: (coord, zoom) ->
"http://tile.openstreetmap.org/#{zoom}/#{coord.x}/#{coord.y}.png"
tileSize: new google.maps.Size(256, 256)
isPng: true
alt: "OpenStreetMap layer"
name: "OSM"
maxZoom: 19
)
cloudMadeMapType = new google.maps.ImageMapType(
getTileUrl: (coord, zoom) ->
"http://b.tile.cloudmade.com/111/54912/256/#{zoom}/#{coord.x}/#{coord.y}.png"
tileSize: new google.maps.Size(256, 256)
isPng: true
alt: "CloudMade layer"
name: "CMade"
maxZoom: 13
)
lat = 51.503
lng = -0.113
latlng = new google.maps.LatLng(lat, lng)
options =
zoom: 10
center: latlng
mapTypeId: 'OSM'
#gMap = new google.maps.Map(document.getElementById("map"), options)
#gMap.mapTypes.set('OSM', osmMapType)
#gMap.mapTypes.set('CloudMade', cloudMadeMapType)
#gMap.setMapTypeId('CloudMade')
allowedBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(51.278, -0.536)
new google.maps.LatLng(51.701, 0.309)
)
lastValidCenter = new google.maps.LatLng(51.503,-0.113)
google.maps.event.addListener #gMap, "dragend", =>
if allowedBounds.contains(#gMap.getCenter())
lastValidCenter = #gMap.getCenter()
return
$('#myModal').modal(backdrop: true)
$('#myModal').on('hide', =>
origin = new google.maps.LatLng(51.438264485659836,-0.05715396179630261)
#gMap.setCenter(origin)
center = google.maps.LatLng(51.503,-0.113)
#gMap.panTo(origin)
)
#initLabel()
initLabel: =>
#rendered = view.render().el
#console.log rendered
#initLabel = new InfoBubble(
position: new google.maps.LatLng(51.44115356738888, 0.14849636779354114)
maxWidth: 240
maxHeight: 210
padding: 0
content: '<div class="tooltip_header"></div>'
tabPadding: 15
backgroundColor: 'black'
borderRadius: 0
arrowSize: 10
borderWidth: 0
borderColor: '#AB2424'
disableAutoPan: true
hideCloseButton: false
arrowPosition: 0.5
backgroundClassName: 'phoney'
tabClassName: 'tabClass'
activeTabClassName: 'activeTabClass'
arrowStyle: 2
)
#initLabel.open(#gMap)
This loads a map and then loads an InfoBubble ontop of the map. It loads it with the content <div class="tooltip_header"></div>
After this has loaded, if I append the loadMap and add
view = new App.Views.MapBox()
view.render().el
which attempts to load the view:
class App.Views.MapBox extends Backbone.View
el: '.tooltip_header'
events:
'click .testdrive' : 'loadTestDrive'
'click .test' : 'loadTestDrive'
template: JST["app/backbone/templates/mapbox"]
initialize: ->
#render()
render: ->
$(#el).html(#template())
this
loadTestDrive: ->
console.log #options.map
console.log "yessss"
#options.map.loadTestDrive()
Nothing happens... however if I go into console and do:
view = new App.Views.MapBox({map: this})
The content is rendered inside the Infobubble ontop of the map.
I think its because the load of InfoBubble is Asynchronous and I am calling the div to be rendered before it exists. But I have tried delay loading and it still happens.
What is the best way to get this view to render after the infobubble is loaded and the div is therefore available. This is why it works in console. but not on load.

Just use google maps events to listen to when the map is fully loaded like this
google.maps.event.addListener(map, 'tilesloaded', _.bind(function() {
this.render();
google.maps.event.clearListeners(map, 'tilesloaded');
},this));
With this you are 100% sure the map is rendered and the google.maps globals are avaliable and initialized.

Related

How do I update marker position via geometry, with a smooth transition?

I'm currently on a ReactJS+Nodejs application, trying to integrate OpenLayers. What I need is to change the GPS position of a marker, in real-time (via socket.io).
So far, I've come up with this code:
this.map = new Map({
target: "map",
layers: [
new TileLayer({
source: new XYZ({
attributions: 'Tiles © ArcGIS',
url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}'
})
}),
],
view: new View({
center: fromLonLat([-8.455826, 40.168307]),
rotation: 1.1344640138,
easing: 0.5
})
});
var vectorSource = new VectorSource({});
var markersLayer = new VectorLayer({
source: vectorSource,
});
this.map.addLayer(markersLayer);
var point1 = new Point(
fromLonLat([-8.455826, 40.168307])
);
var point2 = new Point(
fromLonLat([-8.456819, 40.166388])
);
var marker = new Feature({
geometry: point1,
name: "My point",
});
vectorSource.addFeature(marker);
var style = new Style({
image: new CircleStyle({
radius: 7,
fill: new Fill({color: 'black'}),
stroke: new Stroke({
color: 'white', width: 2
})
})
});
marker.setStyle(style);
setTimeout(function () {
marker.setGeometry(point2);
marker.getGeometry().translate(40, -40);
}, 3500);
The marker moves, however the transition occurs in an instant. Is there a way to make it move like a "CSS linear transition" to give it a more realistic look?
Using a timer you could split the move into steps along the line between the old and new positions, e.g. for 100 10ms steps
var line = new LineString([oldCoordinates, newCoordinates])];
var step = 0;
var key = setInterval( function() {
if (step < 100) {
step++;
marker.setGeometry(new Point(line.getCoordinateAt(step/100)));
} else {
clearInterval(key);
}
}, 10);
You might also be able to base something on the flight animation example https://openlayers.org/en/latest/examples/flight-animation.html

Unable to draw the default line between two location in OpenLayers with ReactJS

I am trying to draw some default line between two location (Location A, Location B) using location latitude and longitude with the help of OpenLayers and ReactJS. But defaulted line is not getting drawn. Unfortunately, I couldn't find the root cause. How can I solve this?
Code:
componentDidMount() {
var map;
var raster=new Tile({
source: new OSM()
});
//Location A - Latitude and Longitude
var iconFeature1 =new Feature({
geometry: new Point(proj.transform([79.2652587890625,19.532871485421026], 'EPSG:4326', 'EPSG:3857')),
name: 'Marker 1' });
//Location B - Latitude and Longitude
var iconFeature2 =new Feature({
geometry: new Point(proj.transform([81.24279785156249,18.02679570052561], 'EPSG:4326', 'EPSG:3857')),
name: 'Marker 2' });
var source = new SourceVector({
features: [iconFeature1,iconFeature2],
wrapX: false
});
var vector = new LayerVector({
source: source,
style: new Style({
fill: new Fill({
color: 'white'
}),
stroke: new Stroke({
color: 'red'
})
})
});
map = new Map({
target: 'map',
layers: [raster,vector],
view: new View({
center: proj.fromLonLat([78.8718, 21.7679]),
zoom: 4
})
})
//To draw Line
var draw = new Draw({
source: source,
type: "LineString"
});
map.addInteraction(draw);
});
Your main issue is the fact are creating two points but do not create a line.
It's what I demonstrate with the following code.
It does the job outside of your particular context (e.g React) but principles remain the same (you will just need to change namespaces)
Go to http://openlayers.org/en/v4.6.5/examples/simple.html
Open the browser debugger console and paste the following
// Location A - Latitude and Longitude
var coords1 = ol.proj.fromLonLat([79.2652587890625,19.532871485421026]);
var iconFeature1 =new ol.Feature({
geometry: new ol.geom.Point(coords1),
name: 'Marker 1'
});
// Location B - Latitude and Longitude
var coords2 = ol.proj.fromLonLat([81.24279785156249,18.02679570052561]);
var iconFeature2 =new ol.Feature({
geometry: new ol.geom.Point(coords2),
name: 'Marker 2'
});
var lineBetweenTwoFeatures =new ol.Feature({
geometry: new ol.geom.LineString([coords1, coords2]),
name: 'Line between markers'
});
// I add the 2 markers and the linestring
// between the two in the same source
// You may need to separate them in two sources
// depending of your use case
var source = new ol.source.Vector({
features: [iconFeature1, iconFeature2, lineBetweenTwoFeatures],
wrapX: false
});
var width = 3;
vector = new ol.layer.Vector({
source: source,
style: [
new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'white',
width: width + 2
})
}),
new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'red',
width: width
})
})
]
});
map.addLayer(vector);
map.getView().fit(source.getExtent());
The important part is in lineBetweenTwoFeatures
You will get the following result

Window on load doesn't change content

I have a Backbone view in which I want to fire a event resizeMovieFrame when the view gets initialized. It reacts to the $(window).on("load", #resizeMovieFrame) because 'hello' gets shown in the console.
But the resize code doesn't do anything on load. But when I resize my browser it does work. So I'm thinking that when the $(window).on("resize", #resizeMovieFrame) gets fired there aren't any .movie-frame divs to resize. If this is the case, what would be the propper load order?
class Movieseat.Views.MovieseatsIndex extends Backbone.View
template: JST['movieseats/index']
id: 'something'
initialize: ->
#listenTo #collection, 'change', #renderEntries, this
#listenTo #collection, 'add', #renderEntries, this
#listenTo #collection, 'destroy', #renderEntries, this
$(window).on("resize", #resizeMovieFrame)
$(window).on("load", #resizeMovieFrame)
render: ->
$(#el).html(#template(entries: #collection))
this
events: ->
"click li": "addEntry"
"click .remove": "destroyEntry"
addEntry: (e) ->
movie_title = $(e.target).parent().find('.movie-title').text()
poster_path = $(e.target).parent().find('img').attr('src')
release_date = $(e.target).parent().find('.release_date').text()
console.log poster_path
#collection.create title: movie_title, image: poster_path, release_date: release_date
destroyEntry: (e) ->
thisid = #$(e.currentTarget).closest('div').parent().data('id')
#collection.get(thisid).destroy()
renderEntries: (entry) ->
view = new Movieseat.Views.Showmovie(collection: #collection)
$('#movie-container').html(view.render().el)
resizeMovieFrame: ->
equalheight = (container) ->
currentTallest = 0
currentRowStart = 0
rowDivs = new Array()
$el = undefined
topPosition = 0
$(container).each ->
$el = $(this)
$($el).height "auto"
topPostion = $el.position().top
unless currentRowStart is topPostion
currentDiv = 0
while currentDiv < rowDivs.length
rowDivs[currentDiv].height currentTallest
currentDiv++
rowDivs.length = 0 # empty the array
currentRowStart = topPostion
currentTallest = $el.height()
rowDivs.push $el
else
rowDivs.push $el
currentTallest = (if (currentTallest < $el.height()) then ($el.height()) else (currentTallest))
currentDiv = 0
while currentDiv < rowDivs.length
rowDivs[currentDiv].height currentTallest
currentDiv++
return
return
$(window).load ->
equalheight ".movie-frame"
return
$(window).resize ->
equalheight ".movie-frame"
return
console.log ('hello')
The resizeMovieFrame event resizes all the .movie-frame divs to the same height.
you probably need to bind the context of the resizeWindowFrame function.
resizeMovieFrame: =>

Display Image with Backbone + KineticJS

I'm trying to load an image on canvas using Backbone + KineticJS. However the image doesn't seem to appear.
First I load the images using a model. (I'm loading the image locally so its already available)
var KineticModel = Backbone.Model.extend({
myImg: null,
createImg : function() {
var imageObj = new Image();
var kinImg = new Kinetic.Image()
imageObj.onload = function() {
kinImg.setAttrs({
x: 10,
y: 10,
image: imageObj,
width: 578,
height: 400
})
}
imageObj.src = 'test/img/vader.png';
return kinImg;
}
});
Then create the View
var KineticView = Backbone.View.extend({
id: 'container',
stage: null,
layer: null,
initialize: function (options) {
model: options.model;
el: options.el;
this.layer = new Kinetic.Layer();
this.stage = new Kinetic.Stage({ container: this.el, width: 600, height: 600 });
this.stage.add(this.layer);
},
render: function () {
var myImg = this.model.createImg();
this.layer.add(myImg);
this.stage.add(this.layer);
this.stage.draw();
}
});
Finally to tie it all up
var KModel= new KineticModel({});
var imgcontainer = $('#container').get();
view = new KineticView({model:KModel, el:imgcontainer});
view.render();
The page loads without any errors, but no image.
Console logs show that the Image Models have been passed to the layers.
Any help will be greatly appreciated!
Redraw layer after setting attrs:
kinImg.setAttrs({
x: 10,
y: 10,
image: imageObj,
width: 578,
height: 400
});
yourLayer.draw();
Note: you are working with view (Kinetic object) inside Backbone.Model - this is bad approach. Model should works only with data. Move createImg function to View.
Also look at this plugin: https://github.com/slash-system/backbone.kineticview

Center and auto zoom google map

;)
I'm a not so familiar with the Google Maps API yet but I was able to figure out most questions a beginners faults. ;) But what I don't get is to center the map between the two markers I set and to auto zoom it... ;(
Maybe someone has the right hint for me...
Thanks and cheers!
<script> function initialize() {
var myLatLng = new google.maps.LatLng(0, 0);
var mapOptions = {
zoom: 3,
mapTypeControl: false,
navigationControl: false,
scrollwheel: false,
streetViewControl: false,
zoomControl: false,
center: myLatLng,
mapTypeId: google.maps.MapTypeId.TERRAIN
};
var map = new google.maps.Map(document.getElementById('map'), mapOptions);
var flightPlanCoordinates = [
new google.maps.LatLng(100, 100),
new google.maps.LatLng(120, 120)
];
var lineSymbol = {
path: google.maps.SymbolPath.FORWARD_CLOSED_ARROW
};
var flightPath = new google.maps.Polyline({
path: flightPlanCoordinates,
geodesic: true,
strokeColor: '#FF0000',
strokeOpacity: 0.5,
icons: [{
icon: lineSymbol,
offset: '100%'
}],
strokeWeight: 2
});
flightPath.setMap(map);
}
google.maps.event.addDomListener(window, 'load', initialize);</script>
<div id="map" style="width: 100%; height: 300px"></div>
<script>jQuery('#myModal-<? the_ID(); ?>').on('shown', function () {
google.maps.event.trigger(map, 'resize');
map.setCenter(new google.maps.LatLng(42.3605336, -72.6362989));
})</script>
You need to fit the bounds of the map as it pertains to your markers.
// Make an array of the LatLng's of the markers you want to show
var LatLngList = new Array (new google.maps.LatLng (52.537,-2.061), new google.maps.LatLng (52.564,-2.017));
// Create a new viewpoint bound
var bounds = new google.maps.LatLngBounds ();
// Go through each...
for (var i = 0, LtLgLen = LatLngList.length; i < LtLgLen; i++) {
// And increase the bounds to take this point
bounds.extend (LatLngList[i]);
}
// Fit these bounds to the map
map.fitBounds (bounds);
// Make an array of the LatLng's of the markers you want to show
var LatLngList = new Array (
new google.maps.LatLng(<?php echo esc_html( $et_location_lat ); ?>, <?php echo esc_html( $et_location_lng ); ?>),
new google.maps.LatLng(<?php echo esc_html( $destination_lat ); ?>, <?php echo esc_html( $destination_lng ); ?>)
);
// Create a new viewpoint bound
var bounds = new google.maps.LatLngBounds ();
// Go through each...
for (var i = 0, LtLgLen = LatLngList.length; i < LtLgLen; i++) {
// And increase the bounds to take this point
bounds.extend (LatLngList[i]);
}
// Fit these bounds to the map
map.fitBounds (bounds);
As I open the map within a modal box I've to reload the bounced map as soon as I open it:
jQuery('#myModal-<? the_ID(); ?>').on('shown', function () {
google.maps.event.trigger(map, 'resize');
map.fitBounds (bounds);
})

Resources