I have problem with Firefox6 (don't know if it also concerns earlier versions).
I want to embed Google Map on page, and when page has scrollbars (is longer than viewport) mouse wheel not only zooms map but also scrolls page. I tried to catch mousewheel event and stop propagation but this event isn catchable when cursor os over map. When cursor is over map controls (zoom control, google logo, etc) i can catch event and stop propagation.
What is more strange it not happens always. Sometimes page srolls and after few scrolls it stops and mousewheel only zooms map (as expected). Sometimes page doesn't scroll and sometimes it scrolls with zoom all the time. Can't find pattern.
Source code is simple:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>test</title>
<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?sensor=false"></script>
<script type="text/javascript">
window.onload = function(){
var latlng = new google.maps.LatLng(52.25, 21.01);
mapOptions = {
zoom: 12,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP,
streetViewControl: false,
zoomControl:true,
mapTypeControl:false
};
map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
}
</script>
</head>
<body>
<p style="height:500px;">-lot of text-</p>
<div id="map_canvas" style="width:500px; height:500px;"></div>
<p style="height:500px;">-lot of text-</p>
</body>
</html>
Your problem is also described on code.google.com, this problem is only in Firefox, but it isn't a Firefox bug:
http://code.google.com/p/gmaps-api-issues/issues/detail?id=3652
http://code.google.com/p/gmaps-api-issues/issues/detail?id=1605
Have also found out a workaround, that is not re-scrolling or re-zooming and works fine:
A new ScrollInterceptOverlay derived from google.maps.OverlayView, prepending a div on MapPanes.overlayMouseTarget:
Version with jQuery
// Ensure to have google.maps loaded:
// var gmap = new google.maps.Map($googlemap[0], mapOptions);
// Define a ScrollInterceptOverlay function
var ScrollInterceptOverlay = function (gmap) {
if (!(this instanceof ScrollInterceptOverlay)) return;
var $div;
var $mapDiv;
var initialize = function () {
$div = $('<div />').css({
position: 'absolute', top: 0, left: 0,
display: 'inline-block'
});
var div = $div[0];
if (div && div.addEventListener) {
// Internet Explorer, Opera, Google Chrome and Safari
div.addEventListener("mousewheel", mouseScrollStop);
// Firefox
div.addEventListener("DOMMouseScroll", mouseScrollStop);
div.addEventListener("MozMousePixelScroll", mouseScrollStop);
}
else if (div && div.attachEvent) { // IE before version 9
div.attachEvent("onmousewheel", mouseScrollStop);
}
this.setMap(gmap);
};
var mouseScrollStop = function (e) {
if (e && e.preventDefault) e.preventDefault();
};
this.onAdd = function () {
$div.prependTo(this.getPanes().overlayMouseTarget);
};
this.onRemove = function () {
var div = $div[0];
if (div && div.addEventListener) {
// Internet Explorer, Opera, Google Chrome and Safari
div.addEventListener("mousewheel", mouseScrollStop);
// Firefox
div.addEventListener("DOMMouseScroll", mouseScrollStop);
div.addEventListener("MozMousePixelScroll", mouseScrollStop);
}
else if (div && div.attachEvent) { // IE before version 9
div.attachEvent("onmousewheel", mouseScrollStop);
}
$div.detach();
};
this.draw = function () {
if ($mapDiv && $mapDiv.length === 1) {
$div.css({
width: $mapDiv.outerWidth(),
height: $mapDiv.outerHeight()
});
}
};
var base_setMap = this.setMap;
this.setMap = function (map) {
$mapDiv = $(map.getDiv());
base_setMap.call(this, map);
};
initialize.call(this);
};
// Setup prototype as OverlayView object
ScrollInterceptOverlay.prototype = new google.maps.OverlayView();
// Now create a new ScrollInterceptOverlay OverlayView object:
var mapScrollInterceptor = new ScrollInterceptOverlay(gmap);
This workaround is using jQuery, required for calculating outerWidth and outerHeight, but also for better reading.
Version with pure javaScript
Tested live: http://fiddle.jshell.net/fhSMM/7/
// Ensure to have google.maps loaded:
// var gmap = new google.maps.Map(googlemap, mapOptions);
// Define a ScrollInterceptOverlay class function
var ScrollInterceptOverlay = function () {
if (!(this instanceof ScrollInterceptOverlay)) return;
var div;
// private instance function
var mouseScrollStop = function (e) {
if (e && e.preventDefault) e.preventDefault();
};
// public instance function
this.onAdd = function () {
div = document.createElement('div');
div.style.display = 'inline-block';
div.style.position = 'absolute';
div.style.top = div.style.left = 0;
if (div.addEventListener) {
// Internet Explorer, Opera, Google Chrome and Safari
div.addEventListener("mousewheel", mouseScrollStop);
// Firefox
div.addEventListener("DOMMouseScroll", mouseScrollStop);
div.addEventListener("MozMousePixelScroll", mouseScrollStop);
}
else if (div.attachEvent) { // IE before version 9
div.attachEvent("onmousewheel", mouseScrollStop);
}
var pane = this.getPanes().overlayMouseTarget;
var firstChild = pane.firstChild;
if (!firstChild) {
pane.appendChild(div);
}
else {
pane.insertBefore(div, firstChild);
}
};
// public instance function
this.onRemove = function () {
if (div) {
if (div.removeEventListener) {
// Internet Explorer, Opera, Google Chrome and Safari
div.removeEventListener("mousewheel", mouseScrollStop);
// Firefox
div.removeEventListener("DOMMouseScroll", mouseScrollStop);
div.removeEventListener("MozMousePixelScroll", mouseScrollStop);
}
else if (div.detachEvent) { // IE before version 9
div.detachEvent("onmousewheel", mouseScrollStop);
}
var parent = div.parentNode;
parent.removeChild(div);
}
// do not delete div var'iable
div = undefined;
};
// public instance function
this.draw = function () {
var map = this.getMap();
if (map) {
var mapDiv = map.getDiv();
if (mapDiv) {
var rect = mapDiv.getBoundingClientRect();
div.style.width = rect.width + 'px';
div.style.height = rect.height + 'px';
}
}
};
};
// Setup prototype as OverlayView object
ScrollInterceptOverlay.prototype = new google.maps.OverlayView();
// Now create a new ScrollInterceptOverlay OverlayView object:
var mapScrollInterceptor = new ScrollInterceptOverlay();
mapScrollInterceptor.setMap(gmap);
Please visit also http://metadea.de/V/ about what (real) javaScript class functions are, and why I like jQuery :)
Works now for me.
Also in Firefox, the map is zooming on mousescroll, but no more scrolling the document.
Edit: Updated support for MozMousePixelScroll, refined jS
For now it looks like firefox bug. Will close question when bug will be fixed.
I had the same issue.
You could try to start Firefox with a brand new profile (e.g. by starting the Profile Manager - executing 'firefox -P' on windows systems - and choosing 'Create...') and see if the problem persists.
I had several old but seemingly empty user profiles lying around in the VMs I used to verify if this was a bug in FF 6 and obviously installing only the new binaries didn't help. On the other hand, creating a blank profile did, so I can only think of this being a migration glitch. If major versions of FF are going to be released on a bi-monthly basis, though, a lot of people are going to suffer from similar issues.
Why not take UI control of zooming? This works well for me.
<!DOCTYPE html>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?sensor=false"></script>
</head>
<body>
<div class="canvas" style="width:600px;height:400px;"></div>
<script>
// Load event
$(function() {
var myOptions = {
zoom: 8,
center: new google.maps.LatLng(-34.397, 150.644),
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map($('.canvas')[0], myOptions);
var overlay = new google.maps.OverlayView();
overlay.draw = function() {};
overlay.setMap(map);
// Only a Mozilla bug
if($.browser.mozilla) {
// Wait for the map DOM to be ready
google.maps.event.addListenerOnce(map, 'idle', function() {
$('.canvas > div > div:first-child > div').bind('DOMMouseScroll', function(e) {
// setTimeout needed otherwise the return false has no effect
setTimeout(function() {
// Calculate new center
var offset = $('.canvas').offset();
var pos = overlay.getProjection().fromContainerPixelToLatLng(new google.maps.Point(e.pageX-offset.left, e.pageY-offset.top));
// Calculate new zoom level
var zoom = map.getZoom();
if(e.detail < 0) zoom++;
else if(e.detail > 0) zoom--;
map.setCenter(pos);
map.setZoom(zoom);
}, 1);
// Stop propagation (prevent default)
return false;
});
});
}
});
</script>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
</body>
</html>
Related
Following my previous question:Load json map into aframe by aframe-geo-projection-component created by earthlinginteractive
Now, I am trying to find a way to show different geometries (country or city) in AFrame each with a different color,
looking for something like this.
I do not mind which library or approach are used, Found this but not sure how to convert this D3.js to Aframe. However as the community bot asked me to provide more details, I have put the code that I am working on below. Not sure which part I need to modify to have such a color coded map but I am working on that. Again, any working example works for me even if someone can show what I need to modify in the below code.
<!-- https://github.com/EarthlingInteractive/aframe-geo-projection-component
https://earthlinginteractive.github.io/aframe-geo-projection-component/ -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>A-Frame Geo Projection Component - U.S. Population 2017 (est.)</title>
<meta name="description" content="Visualization of estimated U.S. population by state in 2017"></meta>
<script src="https://aframe.io/releases/0.7.1/aframe.min.js"></script>
<script src="//cdn.rawgit.com/donmccurdy/aframe-extras/v3.12.4/dist/aframe-extras.min.js"></script>
<script src="https://unpkg.com/super-hands#2.1.0/dist/super-hands.min.js"></script>
<script src="https://d3js.org/d3.v4.js"></script>
<script src="https://d3js.org/d3-queue.v3.js"></script>
<script src="https://earthlinginteractive.github.io/aframe-geo-projection-component/dist/aframe-geo-projection-component.min.js"></script>
</head>
<body>
<script>
AFRAME.registerComponent('geo-extrude-population-renderer', {
dependencies: ['geo-projection'],
schema: {
maxExtrudeHeight: {
default: 2
}
},
init: function () {
this.system = this.el.sceneEl.systems['geo-projection'];
this.geoProjectionComponent = this.el.components['geo-projection'];
this.geoJsonReady = this.geoJsonReady.bind(this);
// Wait for geoJson to finish loading to avoid race conditions
this.el.addEventListener('geo-src-loaded', this.geoJsonReady);
},
update: function (oldData) {
if (!this.geoProjectionComponent.geoJson) {
return;
}
if (this.data.maxExtrudeHeight !== oldData.maxExtrudeHeight) {
this.geoJsonReady();
}
},
geoJsonReady: function () {
// Now kick off loading the data
d3.queue()
.defer(d3.csv, 'https://cdn.glitch.global/c153e3cf-7430-444d-9897-4e97f1ef8d35/us-population-2017.csv?v=1657704183925', function (d) {
return {
state: d.state,
population: +d.population
}
})
.defer(d3.csv, 'https://cdn.glitch.global/c153e3cf-7430-444d-9897-4e97f1ef8d35/us-state-county-geocodes-v2016.csv?v=1657704190160')
.await(this.onDataLoaded.bind(this));
},
onDataLoaded: function(error, populationData, geocodes) {
if (error) throw error;
var stateFips = geocodes.filter(function (row) {
return row['Summary_Level'] === '040'
});
var maxPopulation = d3.max(populationData, function (d) {
return d.population;
});
var populationByFipsCode = populationData.reduce(function (accum, d) {
var fipsForState = stateFips.find(function (fipsRow) { return fipsRow['Area_Name'] === d.state; });
var fipsCode = fipsForState['State_Code_FIPS'];
accum[fipsCode] = d.population;
return accum;
}, {});
this.render(populationByFipsCode, maxPopulation, this.data.maxExtrudeHeight);
},
render: function (populationByFipsCode, maxPopulation, maxExtrudeHeight) {
if (!populationByFipsCode) return;
var material = [];
var extrudeGeometry = null;
var stateOutlineVertices = [];
// Split the geoJson into features and render each one individually so that we can set a different
// extrusion height for each based on the population.
this.geoProjectionComponent.geoJson.features.forEach(function (feature) {
var population = populationByFipsCode[feature.id];
var extrudeAmount = (population / maxPopulation) * maxExtrudeHeight;
var material="#999999";
const extrudeSettings = {
amount: extrudeAmount,
bevelEnabled: false
};
//Math.floor(Math.random()*16777215).toString(16);
var mapRenderContext = this.system.renderToContext(feature, this.geoProjectionComponent.projection);
const stateShapes = mapRenderContext.toShapes();
// Gather the outline of the state and set the height of the outline to the extrude level
// so that the top of the state is outlined
stateOutlineVertices = stateOutlineVertices.concat(mapRenderContext.toVertices(extrudeAmount));
// Merge all the extruded feature geometries together for better rendering performance
// Need to use ExtrudeGeometry here instead of ExtrudeBufferGeometry because the latter doesn't merge properly
// in this version of Three.js
var extrudedFeatureGeometry = new THREE.ExtrudeGeometry(stateShapes, extrudeSettings);
if (!extrudeGeometry) {
extrudeGeometry = extrudedFeatureGeometry;
} else {
extrudeGeometry.merge(extrudedFeatureGeometry);
}
}.bind(this));
// Convert the extrude geometry into a buffer geometry for better rendering performance
var extrudeBufferGeometry = new THREE.BufferGeometry();
extrudeBufferGeometry.fromGeometry(extrudeGeometry);
var sideMaterial = new THREE.MeshStandardMaterial( { color: 0xaaafff } );
var extrudedMap = new THREE.Mesh(extrudeBufferGeometry, [material, sideMaterial]);
this.el.setObject3D('map', extrudedMap);
var stateOutlineGeometry = new THREE.BufferGeometry();
stateOutlineGeometry.addAttribute('position', new THREE.Float32BufferAttribute(stateOutlineVertices, 3));
var stateOutlineMaterial = new THREE.LineBasicMaterial( { color: 0xcccaaa } );
var stateOutlines = new THREE.LineSegments(stateOutlineGeometry, stateOutlineMaterial);
this.el.setObject3D('lines', stateOutlines);
}
});
</script>
<a-scene>
<a-assets>
<a-asset-item id="json-us" src="https://unpkg.com/us-atlas#1/us/10m.json" />
</a-assets>
<a-sky color="#ECECEC"></a-sky>
<a-entity id="map"
rotation="-90 0 0"
material="color: #123456;"
topojson-loader="src: #json-us; topologyObject: states;"
geo-projection="
projection: geoIdentity;
height: 6;
width: 10;"
geo-extrude-population-renderer
>
</a-entity>
<a-locomotor>
<a-entity hand-controls="left" super-hands></a-entity>
<a-entity hand-controls="right" super-hands></a-entity>
</a-locomotor>
</a-scene>
</body>
</html>
<!--material="color: #123456;"-->
getting this error as well if I use aframe 1.3.0:
Uncaught TypeError: extrudeBufferGeometry.fromGeometry is not a function
at i.render ((index):104:29)
at i.onDataLoaded ((index):66:12)
at Queue._call (d3-queue.v3.js:43:54)
at maybeNotify (d3-queue.v3.js:120:7)
at d3-queue.v3.js:91:12
at Object.<anonymous> (d3.v4.js:11470:86)
at Dispatch.call (d3.v4.js:792:72)
at XMLHttpRequest.respond (d3.v4.js:11395:13)
I'm simply trying to replace the lat long coords to use the browsers geolocation yet I'm getting no result...
Code for the geolocation is;
<script> var coords = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
function initAutocomplete() {
var map = new google.maps.Map(document.getElementById('map'), {
center: coords,
zoom: 13,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
The rest of the code points to the simple places api service;
// Create the search box and link it to the UI element.
var input = document.getElementById('pac-input');
var searchBox = new google.maps.places.SearchBox(input);
map.controls[google.maps.ControlPosition.TOP_LEFT].push(input);
// Bias the SearchBox results towards current map's viewport.
map.addListener('bounds_changed', function() {
searchBox.setBounds(map.getBounds());
});
var markers = [];
// Listen for the event fired when the user selects a prediction and retrieve
// more details for that place.
searchBox.addListener('places_changed', function() {
var places = searchBox.getPlaces();
if (places.length == 0) {
return;
}
// Clear out the old markers.
markers.forEach(function(marker) {
marker.setMap(null);
});
markers = [];
// Create a marker for each place.
markers.push(new google.maps.Marker({
map: map,
icon: icon,
title: place.name,
position: place.geometry.location
}));
if (place.geometry.viewport) {
// Only geocodes have viewport.
bounds.union(place.geometry.viewport);
} else {
bounds.extend(place.geometry.location);
}
});
map.fitBounds(bounds);
});
}
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(success);
} else {
error('Geo Location is not supported');
}
</script>
I cannot for the life of me find any reliable tutorials on-line...
this is my simple test code for lazy load
http://codepen.io/kevkev/pen/bVVGdE
it works so far .. but the thing is that hidden images in an onclick function for buttons etc. doesnt work!
(watch through my code and scroll to end and push the button)
you can see in the network feedback that it already had load the images.
i could figure out that the problem is "display:none"
.pop {
display:none;
z-index:99;
position:absolute;
width:100%;
height:auto;
background:inherit;
}
Because display: none; elements are unknown in position. And the lazyloader doesn't know, when and if you change this. Therefore it decides to eager load it. If you want a lazyloader that automatically detects this use https://github.com/aFarkas/lazysizes/.
As alternative I would recommend justlazy, because it's more lightweight and don't uses jQuery.
1. Define placeholder (similar to that what you have done):
<span data-src="path/to/image" data-alt="alt" data-title="title"
class="placeholder">
</span>
2. Initialize lazy loading after your button click:
$(document).ready(function () {
$("#art").click(function () {
$("#art_pop").fadeIn(300);
Justlazy.registerLazyLoadByClass("placeholder", {
// image will be loaded if it is 300 pixels
// below the lower display border
threshold: 300
});
});
// other code ..
});
thanks guys! but I also got a working solution on this:
http://codepen.io/kevkev/full/meebpQ/
$(document).ready(function () {
$("#art").click(function () {
$("#art_pop").fadeIn(300);
});
$(".pop > span, .pop").click(function () {
$(".pop").fadeOut(600);
});
});
;(function($) {
$.fn.unveil = function(threshold, callback) {
var $w = $(window),
th = threshold || 0,
retina = window.devicePixelRatio > 1,
attrib = retina? "data-src-retina" : "data-src",
images = this,
loaded;
this.one("unveil", function() {
var source = this.getAttribute(attrib);
source = source || this.getAttribute("data-src");
if (source) {
this.setAttribute("src", source);
if (typeof callback === "function") callback.call(this);
}
});
function unveil() {
var inview = images.filter(function() {
var $e = $(this);
if ($e.is(":hidden")) return;
var wt = $w.scrollTop(),
wb = wt + $w.height(),
et = $e.offset().top,
eb = et + $e.height();
return eb >= wt - th && et <= wb + th;
});
loaded = inview.trigger("unveil");
images = images.not(loaded);
}
$w.on("scroll.unveil resize.unveil lookup.unveil", unveil);
unveil();
return this;
};
})(window.jQuery || window.Zepto);
/* OWN JAVASCRIPT */
$(document).ready(function() {
$("img").unveil(200, function() {
$(this).load(function() {
this.style.opacity = 1;
});
});
});
I have a problem that the code below works in : IE 10, Firefox, Safari, Mac Chrome, but not for Windows Chrome.
$(function () {
var video_dom = document.querySelector('#v');
var canvas_draw = document.querySelector('#c');
var draw_interval = null;
video_dom.addEventListener('play', function () {
video_dom.width = canvas_draw.width = video_dom.offsetWidth;
video_dom.height = canvas_draw.height = video_dom.offsetHeight;
var ctx_draw = canvas_draw.getContext('2d');
draw_interval = setInterval(function () {
ctx_draw.drawImage(video_dom, 0, 0, video_dom.width, video_dom.height);
var dataURL = canvas_draw.toDataURL();
document.getElementById('canvasImg').src = dataURL;
}, 3500)
}, false);
})();
Also I get this error in console like: Uncaught TypeError: object is not a function.
Why is the canvas is working in the Mac version, but not the Windows version of Chrome?
I don't see why you're using a dollar sign ($) in front of your function when you're not using jQuery.
window.onload = function () {
var video_dom = document.querySelector('#v');
var canvas_draw = document.querySelector('#c');
...
};
Should be clear of errors.
I've spent 3 solid days trying to resolve this issue. Very quickly, the Youtube player does not fire the onReady and onStateChange event in both IE8 and IE10. I tested it on Firefox and it works. Basically, I am developing a Windows 8 metro app that uses WebView to host the html, but it also doesnt work in WebView.
The video loads and the onYouTubeIframeAPIReady is called but that's about it. Below is the html code.
The alert message in onPlayerReady and onPlayerStateChange functions doesnt get displayed in IE8 and IE10 but is displayed in Firefox.
Please help.....
<!DOCTYPE html>
<html>
<body>
<div id="player"></div>
<script>
alert('LOADING');
alert(GetUserAgent());
var tag = document.createElement('script');
tag.src = "http://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
var player;
function onYouTubeIframeAPIReady()
{ player = new YT.Player('player', { height: '315', width: '560',
videoId: 'CreKbwMTZA8', playerVars: {'autoplay': 1},
events: { 'onReady': onPlayerReady, 'onStateChange': onPlayerStateChange } });
alert('onYouTubeIframeAPIReady');
}
function onPlayerReady(event)
{
event.target.playVideo();
alert('onPlayerReady');
}
function onPlayerStateChange(event)
{
alert('onPlayerStateChange');
if (event.data == YT.PlayerState.PLAYING) { window.external.notify('PLAYING');}
else if (event.data == YT.PlayerState.ENDED) {window.external.notify('ENDED');}
}
function setSize(width, height)
{ player.setSize(width, height);
}
function GetUserAgent()
{
return navigator.userAgent;
}
</script>
</body>
</html>