I am trying to use the Google Maps API. I have gotten a authorization key and pasted in the sample code they gave us, but I can't make the map render even when they tell me to make sure I put a height of 100% on both my map div and the body.
I have tried and it won't show up. If I put a 500px height on the map div, and give the body a 100% height it works... but I want to know why height of 100% will not will not render. I am copying exactly what the Google documentation (https://developers.google.com/maps/documentation/javascript/examples/map-simple) is giving me and what the video tells me to double check. HELP, i am insanely curious on why 100% height won't render. I want to use percentages, so that it can be compatible on mobile devices!
<!doctype html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<title>Ice Cream</title>
<!-- Google Docs-->
<!-- external CSS link -->
<link rel="stylesheet" href="css/reset.css">
<link rel="stylesheet" href="css/style.css">
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
</head>
<body>
<div id='map_canvas'> HELLOooo <!--dimensions of map are set in CSS-->
</div>
<!-- external CSS link -->
<!-- javascript -->
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyDuDCh7Odrr4RUUiAHMyDtfwC2NtySy-64"></script>
<script src="js/index.js"></script>
</body>
</html>
body, #map_canvas{
margin:0;
padding:0;
height: 100%;
}
$(function() {
console.log("hi");
function initialize() {
var mapOptions = {
center: { lat: -34.397, lng: 150.644},
zoom: 8
};
var map = new google.maps.Map(document.getElementById('map_canvas'),
mapOptions);
}
google.maps.event.addDomListener(window, 'load', initialize);
console.log('map');
});
The browser needs to be able to calculate a non-zero height. You need to set the height of the html element to 100% also:
$(function() {
console.log("hi");
function initialize() {
var mapOptions = {
center: { lat: -34.397, lng: 150.644},
zoom: 8
};
var map = new google.maps.Map(document.getElementById('map_canvas'),
mapOptions);
}
google.maps.event.addDomListener(window, 'load', initialize);
console.log('map');
});
html, body, #map_canvas{
margin:0;
padding:0;
height: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maps.googleapis.com/maps/api/js"></script>
<div id='map_canvas'> HELLOooo <!--dimensions of map are set in CSS-->
</div>
The reason why 100% doesn't work is because the map needs to send you images at a specific ratio (fixed width & height). Now I might be guessing here, but that's what I think happens.
Since I had a similar problem, where my map was hidden inside a tab, I wrote this function to calculate the width & height or a ratio. Then whatever size of the container, the map was in, it would adjust. It uses jQuery so I just thought I'd post it to get the idea.
/**
* Calculate the dimensions
*/
calculateMap: function () {
var self = this,
parent = this.map.parent(), // jQuery obj
w, h, id, el;
// if the container of your map is visible and wrapped it has a certain width and height...
// if it also has 100% height, it could be collapsed (not wrapped)
// so you ask the google maps api to load images at 500px width and 0height?
// if the parent has 0height, the ratio helps to set it properly
// with debug tools (F12) you can see the parent if it lights up
if (parent.is(':visible')) {
w = parent.outerWidth(false);
h = w * this.settings.options.mapRatio; // 4/3 | 16/9
this.map.css({ width: w, height: h });
} else {
// if your map is invisible after load...
id = this.onParent.prop('id'); // this id references my tab
el = this.onParent.prevAll().find('a[href=#' + id + ']'); // trigger of the tab
// add click event once
el.one(this.settings.events.onParent, function() {
setTimeout(function() {
self.activate(); // goes back to calculateMap()
}, 200);
}.bind(this));
}
},
If you trigger calculateMap on the resize event, you'll have a responsive approach.
Also a quick google showed me this approach ... notice the fixed width and height on the iframe.
In short:
fixed width and height in css gives you the cleanest solution. you might be able to use a clearfix, padding in % or min-height in px to gain dimension if that works out.
For dynamic/event loading I suggest JavaScript or jQuery
or with an iframe and a fixed width and height
Related
I have a JS variable controlling styling of the page. I want it to change depending on screen resolution. How can I make it depend on results of CSS media query.
I know that I can check screen resolution directly in JS but I want to keep all styling decisions within CSS rather than spread it across JS and CSS files.
to avoid XY problem: I am using Leaflet and JS variable decides whatever map control panel listing available layers is collapsed or not. It should be collapsed on small screens (mobile) and not collapsed on large screens (proper monitors).
The relevant code is available below
html,
body {
height: 100%;
margin: 0;
}
#map {
width: 600px;
height: 400px;
}
#media (min-width: 1000px) {
#map {
width: 1000px;
height: 900px;
}
}
<!DOCTYPE html>
<html>
<!--based on https://leafletjs.com/examples/layers-control/ example -->
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.3.3/dist/leaflet.css" integrity="sha512-Rksm5RenBEKSKFjgI3a41vrjkw4EVPlJ3+OiI65vTjIdo9brlAacEuKOiQ5OFh7cOI1bkDwLqdLw3Zg0cRJAAQ==" crossorigin="" />
<script src="https://unpkg.com/leaflet#1.3.3/dist/leaflet.js" integrity="sha512-tAGcCfR4Sc5ZP5ZoVz0quoZDYX5aCtEm/eu1KhSLj2c9eFrylXZknQYmxUssFaVJKvvc0dJQixhGjG2yXWiV9Q==" crossorigin=""></script>
<link rel="stylesheet" href="example.css" />
</head>
<body>
<div id='map'></div>
<script>
var positron = L.tileLayer('https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png', {
attribution: '#{openstreetmap_copyright_notice}, basemap: © CartoDB',
subdomains: 'abcd',
maxZoom: 19
}),
osmcarto = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
});
var map = L.map('map', {
center: [39.73, -104.99],
zoom: 10,
layers: [positron]
});
var baseLayers = {
"positron": positron,
"osm-carto": osmcarto
};
L.control.layers(baseLayers, {}, {
collapsed: false
}).addTo(map); //false/true should be specified by CSS
</script>
</body>
</html>
Pretty cheezy solution, but it would mean not hardcoding any width properties in JS.
Add a dummy, invisible element to the page.
<div id="dummy"></div>
#dummy::after {
display: none;
content: 'false';
}
#media (min-width: 1000px) {
#dummy::after {
content: 'true';
}
}
Then read the value of the content in JS:
var isBigScreen = window.getComputedStyle(
document.querySelector('#dummy'), ':after'
).getPropertyValue('content');
isBigScreen will be either "true" or "false". You might want to add some code to recheck that if the screen size changes.
if(isCollapsed === '"false"') {
isCollapsed = false;
} else {
isCollapsed = true;
}
may be used to convert it to a standard boolean.
You can use matchMedia to do this, either as a one-off check or (more usefully) with a callback (more on the callback option here):
window.matchMedia("(min-width: 1000px)").addListener(function(e) {
if (e.matches) {
// The window currently matches the query
} else {
// It doesn't
}
});
To avoid repeating the query text in the JavaScript, you can search through document.styleSheets and using their media property. May not be a lot of fun, but I can't imagine any other way to avoid duplicating the media query.
For example, this uses the first screen and rule it finds (jsFiddle):
// Find the rule
const rule = Array.from(document.styleSheets).reduce((found, sheet) => {
return found || Array.from(sheet.cssRules || sheet.rules).find(rule => {
return rule.conditionText && rule.conditionText.startsWith("screen and ");
});
}, null);
if (rule) {
const query = rule.conditionText.substring(11);
console.log("rule found, setting listener for: " + query);
window.matchMedia(query).addListener(function(e) {
console.log("matches? ", e.matches);
});
} else {
console.log("No rule found");
}
Naturally, you'd need to wait for any stylesheets loaded via link elements to be loaded first.
The only way I could think of is by setting a certain style in your CSS and then checking for that style in Javascript.
e.g. something like document.getElementById('map').style.width === '1000px'
Using the mapboxgl, I added a my custom map control, which can do some special functions,and I refered the office example with basic function. But When I completed codes, I found the event click of button did not work. I have add the stopPropagation function. So how to add click event in the mapbox control?
mapboxgl.accessToken = 'pk.eyJ1IjoieGlhb2thbmciLCJhIjoiY2lqc2d2NXlyMGhkbHU0bTVtcGNiOWxseCJ9.J5qsX13KKNT1slMGS-MOLg';
var map = new mapboxgl.Map({
container: 'map', // container id
style: 'mapbox://styles/mapbox/streets-v9', // stylesheet location
center: [-74.50, 40], // starting position [lng, lat]
zoom: 9 // starting zoom
});
class ToggleControl {
onAdd(map){
this.map = map;
this.container = document.createElement('div');
this.container.className = 'my-custom-control';
const button = this._createButton('monitor_button')
this.container.appendChild(button);
return this.container;
}
onRemove(){
this.container.parentNode.removeChild(this.container);
this.map = undefined;
}
_createButton(className) {
const el = window.document.createElement('button')
el.className = className;
el.textContent = 'toggleControl';
el.addEventListener('click',(e)=>{
e.style.display = 'none'
console.log(e);
// e.preventDefault()
e.stopPropagation()
},false )
return el;
}
}
const toggleControl = new ToggleControl()
map.addControl(toggleControl,'top-left')
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
<title>Display a map</title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.47.0/mapbox-gl.js'></script>
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.47.0/mapbox-gl.css' rel='stylesheet' />
<style>
body { margin:0; padding:0; }
#map { position:absolute; top:0; bottom:0; width:100%; }
</style>
</head>
<body>
<div id='map'></div>
<script>
</script>
</body>
</html>
The problem is that the mapbox container positioning style removes mouse events handling (pointer-events: none;):
.mapboxgl-ctrl-top-left,
.mapboxgl-ctrl-top-right,
.mapboxgl-ctrl-bottom-left,
.mapboxgl-ctrl-bottom-right {
position: absolute;
pointer-events: none;
z-index: 2;
}
So you need to add the class mapboxgl-ctrl (pointer-events: auto;) to the container for catching events:
this.container.className = 'mapboxgl-ctrl my-custom-control';
Or set this CSS-property manually:
.my-custom-control {
pointer-events: auto;
}
[ https://jsfiddle.net/Lkes0ch8/ ]
I have the same problem, stdob-- is correct,
by add 'mapboxgl-ctrl' to className solved my problem.
without this, user can not drag the slider bar.
this._container.className = 'mapboxgl-ctrl mapboxgl-ctrl-group opacityDIV';
Top right corner slider is what I created.
There are 2 way to add mapbox control,
standard way is from mapbox example,
alternative way is works the same
Here is my working code:
I'm using leaflet to put some markers on a map. I have set that, clicking on a marker, a popup will be opened showing an image. Here's a brief example:
var map = L.map('map')
.addLayer(tile)
.setView([initLat, initLon], initZoom);
var m = L.marker([lat, lon])
.bindPopup('<img src="1.jpg"/>')
.addTo(map);
My objective is to load those images ("1.jpg" in the example above) using lazy load, so it's only loaded when I click on the marker.
Does anyone knows how to do this?
Thanks!
You could set the content of the popup when the popup is opened.
Let's create a custom popup with a lazyload option and without content :
var m = L.marker([0, 0])
.bindPopup(L.popup({
lazyload: '<img src="1.jpg"/>'
}))
.addTo(map);
You can then set a global handler to fill your popup when needed:
map.on('popupopen', function(e) {
var popen = e.popup;
if (popen.options.lazyload) {
popen.setContent(popen.options.lazyload);
}
});
And a demo:
var map = L.map('map', {
center: [0, 0],
zoom: 1
});
var m = L.marker([-30, 0])
.bindPopup(L.popup({
lazyload: '<img src="https://i.stack.imgur.com/shfxy.jpg?s=32&g=1" />'
}))
.addTo(map);
map.on('popupopen', function(e) {
var popen = e.popup;
if (popen.options.lazyload) {
popen.setContent(popen.options.lazyload);
}
});
html, body {
height: 100%;
margin: 0;
}
#map {
width: 100%;
height: 150px;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.3.1/leaflet.css"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.3.1/leaflet.js"></script>
<div id='map'></div>
Actually in the case where you fill your popup with a String content (like you did with .bindPopup('<img src="1.jpg"/>'), Leaflet converts it (through innerHTML) to DOM nodes only when the Popup is first opened on a map. Therefore your image will be loaded only at that moment, which is exactly the lazy loading behaviour you are looking for.
So you do not need to do anything extra from what you already have done in your question code:
(make sure you refresh your page / clear your cache to see the image loading pass in the browser network requests)
var map = L.map('map', {
center: [0, 0],
zoom: 1
});
var m = L.marker([-30, 0])
.bindPopup('<img src="https://i.stack.imgur.com/shfxy.jpg?s=32&g=1" />')
.addTo(map);
html, body {
height: 100%;
margin: 0;
}
#map {
width: 100%;
height: 150px;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.3.1/leaflet.css"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.3.1/leaflet.js"></script>
<div id='map'></div>
I'm taking real simple examples from their documentation in one I re-size and re-position a photo. The re-size part works fine but it won't re-position.
Here's my code:
<head>
<meta charset="UTF-8">
<title>animate</title>
<style type="text/css">
#test { width: 100px; height: 100px; background-color: #f72; }
</style>
<!--CDN link for the latest TweenMax-->
**<script src="http://cdnjs.cloudflare.com/ajax/libs/gsap/latest/TweenMax.min.js"></script>**
</head>
<body>
**<div id="test"></div>
<img id="photo" src="Putin.jpg">**
<script>
**var photo = document.getElementById("photo");
TweenLite.to(photo, 2.5, {width:100}); // this works
TweenLite.to(photo, 4, {left:300}); // this does nothing
var thing = document.getElementById('test');
TweenLite.to(thing, 1, {left:200}); // this does nothing
TweenLite.to(thing, 1, {top:100}); // this does nothing**
</script>
</body>
you can run it here: http://www.jimslounge.com/gsap_test/
Updated:
I would always wait until the window has loaded before executing code that relies on a external libraries:
window.onload = function(){
var photo = document.getElementById("photo");
TweenMax.to(photo, 4, {x:300});
}
Secondly, you are loading the TweenMax library, so you need to use TweenMax instead of TweenLite
Thirdly, besides not quite being sure if you need to define your block as position absolute when not animating the padding or margin, you should definitely pass the x instead of left attribute
TweenMax.to(photo, 4, {x:300});
Give it a go and let me know if this helps
See a working example here:
http://jsfiddle.net/Hitbox/QbyCU/1/
Im using nokia maps javascript api, is posible place a grid in the map?
The easiest way to do this would be to use a transparent grid PNG as an overlay.
First create a 256x256 PNG file as shown below.
Then use that as your getTileUrl() function, so it is returned over all of the Map tiles on the map.
var getTileUrl = function (zoom, row, column) {
return "http://i.stack.imgur.com/M1ncK.png";
};
The result is something like this:
An example can be seen below, with your own PNG file, app id and token of course .
/* Set authentication token and appid
*
* please register on http://api.developer.nokia.com/
* and obtain your own developer's API key
*/
nokia.Settings.set("appId", "MY APP ID");
nokia.Settings.set("authenticationToken", "MY TOKEN");
// Get the DOM node to which we will append the map
var mapContainer = document.getElementById("mapContainer");
// Create a map inside the map container DOM node
var map = new nokia.maps.map.Display(mapContainer, {
// initial center and zoom level of the map
center: [52.515, 13.405],
zoomLevel: 14,
components: [
// ZoomBar provides a UI to zoom the map in & out
new nokia.maps.map.component.ZoomBar(),
// We add the behavior component to allow panning / zooming of the map
new nokia.maps.map.component.Behavior()
]
});
var getTileUrl = function (zoom, row, column) {
return "http://i.stack.imgur.com/M1ncK.png";
};
tileProviderOptions = {
getUrl: getTileUrl, // Obligatory function
max:20, // The highest zoom level for the overlay.
min:1, // The lowest zoom level for the overlay.
opacity: 0.5, // Overlay opacity.0 is fully transparent, 1 is fully opaque.
alpha:true // This value tells the renderer to read the alpha channel; required if opacity is used.
},
// Create an overlay by calling the constructor for ImgTileProvider
gridOverlay = new nokia.maps.map.provider.ImgTileProvider(tileProviderOptions);
// Add the overlay to the map
map.overlays.add(gridOverlay);
html {
overflow:hidden;
}
body {
margin: 0;
padding: 0;
overflow: hidden;
width: 100%;
height: 100%;
position: absolute;
}
#mapContainer {
width: 100%;
height: 100%;
left: 0;
top: 0;
position: absolute;
}
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=7; IE=EmulateIE9; IE=EmulateIE10;"/>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<title>Nokia Maps Example: Adding an overlay to the map</title>
<script type="text/javascript" charset="UTF-8" src="http://api.maps.nokia.com/2.2.4/jsl.js?with=all"></script>
<style type="text/css">
</style>
</head>
<body>
<div id="mapContainer"></div>
<div id="uiContainer"></div>
</body>
</html>