I want to programmatically hide and show my embedded aframe scene. The scene is hidden when the website is loaded, however I only get it to work with a delay like this:
window.onload = function () {
setTimeout(function() { document.getElementById("scene-page").setAttribute("hidden", ""); }, 500);
}
When I don't add this delay, the scene remains hidden, even after setting it to 'visible' again. Specifically, the size of the canvas seems to be resized to 0px:
<canvas class="a-canvas a-grab-cursor" data-aframe-canvas="true" width="0" height="0" style="width: 0px; height: 0px;"></canvas>
The only way to make it visible then is to resize the browser window, which then seems to resize the canvas.
Is there a better way to hide the scene without the delay?
From what i see (posts like here, or here), if you set display: none before the entire canvas loads, the canvas / renderer / camera properties won't set up properly.
I tried waiting for the a-scene's loaded/renderstart event, window.onload, and the internal entities, still it seems to mess up the canvas settings.
The reason why it's working when you resize the window is because the scene has a listener for resize which updates all of these accordingly with the canvas width / height. I'm not sure if its possible to call the resize manually.
Check it out here -> just search for this.resize, there are 3 hits, one in the a-scene.
It seems easier and safer to place a blank <div> if front of the a-frame canvas with a fixed position, which will be switched from display: none to block. live fiddle here !
Once the scene is up and running, You can toggle its display all you want though! live fiddle here !
Related
First, I'm sorry for my bad english ^^
I'm working on my web site and I would like to put my canvas animation (created with easelJS framework) in my div background.
I tried something like this :
.canvas-bg {
background: -webkit-canvas(animation);
}
var ctx = document.getCSSCanvasContext('2d', 'animation', 300, 300);
It work on safari (but the animation is paused when I refresh the page) and not working at all on chrome...
So, have you any way to make an animated canvas as div background ?
Like the blue banner of this web site for example : http://www.createjs.com/easeljs
Thanks a lot !
Julien.
You can include the canvas in your DIV, and then set it's position as absolute. Other content in the DIV will sit on top.
#canvas {
position: absolute;
display: inline;
}
Here is a quick sample:
http://jsfiddle.net/obcv1rex/1/
You can add text to the first DIV to see it scroll. I set the size to 1000x1000, but to make it more dynamic you would want to size the canvas with JavaScript (using CSS will scale the contents).
I have a <div> containing a leaflet map. Upon certain events the height of the <div> will be altered. I'd like for the map to resize to the new dimensions of its surrounding <div> so that the old center is centered in the resized smaller or larger map. I tried using the invalidateSize() function, but it doesn't seem to work at all. How can I resize and center the map after that map-container-resize event?
$mapContainer.on('map-container-resize', function () {
map.invalidateSize(); // doesn't seem to do anything
});
Edit to give more context:
The map container is styled initially as
#map-container {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
transition: height 0.5s ease-in-out;
}
After a user clicks a certain button, another panel shows at the bottom of the page and the map-container's height will be reduced to something less than 100% (say 80%).
Upon click on this button, the map-container-resize event is triggered so that I can make the map resize and center on its old (i.e. before the resizing happened) center. The map itself should then also be resized to 80% of its initial height.
The APi doc for invalidateSize seemed to be what I wanted:
"Checks if the map container size changed and updates the map if so
[...]"
But having a look with the output of the getSize function before and after the call to invalidateSize, nothing is different, the map remains at its old size.
The problem is that the resizing of the #map-container div is done via a css transition. The transition hasn't started yet, let alone ended, when the call to invalidateSize happens so the leaflet map cannot recognize any change of dimensions of its surrounding div.
Triggering the map-container-resize event with a delay solved the problem. This way :
setTimeout(function(){ map.invalidateSize()}, 400);
L.Map.invalidateSize() only informs leaflet map object that its container size has been changed, and therefore is should draw less or more map tiles. It does not actually change any dimensions, e.g. of its containing <div>, and does not move the map. You should do it yourself.
I came across this question today and wanted to provide an updated answer based on 2020 Browser API. This example uses the Browser's ResizeObserver to monitor the size of the div that Leaflet is mounted too. Assuming the following HTML Snippet:
<div id="map" />
With the following JavaScript:
const mapDiv = document.getElementById("map");
const map = L.map(mapDiv).setView([51.505, -0.09], 13);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
const resizeObserver = new ResizeObserver(() => {
map.invalidateSize();
});
resizeObserver.observe(mapDiv);
This should monitor the map div, and call the invalidateSize() method on the Leaflet map when the map div size changes. This approach allows you to handle the resizing "closer" to the map code, rather than trying to rely on window resize events or listening for changes triggered elsewhere in the application.
Obviously the CSS for the map div itself will need to ensure that it resizes in whatever way you want it to. This code snippet will ensure the Leaflet is appropriately updated when that happens.
You can use below code after resize that
map.invalidateSize()
https://github.com/Leaflet/Leaflet/issues/690
the accepted answer is a bit hacky in that it relies on the sleep being longer than the transition.
I have found this to work well:
$("body").on($.support.transition.end, '#main-navbar .nav-collapse', function(event){
console.log("end of the animation");
});
Just call resize window event rather than timing the map to load.
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
window.dispatchEvent(new Event('resize'));
// Triggers a window resize
// Thus your map automatically triggers invalidateSize().
Ran into this problem running VueJS, Leaflet 1.2.0. The resizing didn't appear complete as others mentioned above. My solution within VueJS was to call the nextTick function:
var vm = this
var container = vm.$refs.container
vm.mapStyle.width = `${vm.getElementContentWidth(container)}px`
vm.mapStyle.height = `${vm.getElementContentHeight(container)}px`
vm.$nextTick(() => {
if (vm.map) vm.map.invalidateSize()
if (vm.layerBase) vm.layerBase.redraw()
})
I believe pure javascript would be
A canvas styled with visibility: hidden; is supposed to appear window-sized after one second with this code, right?
var canvas = document.getElementById("myCanvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// draw on canvas.getContext("2d") ...
window.setTimeout(function() {
canvas.style.visibility = "visible";
}, 1000);
It works with IE11, but not with Chrome32 (running on Windows7).
(Phew, I never though I would find something that works with IE but not with Chrome!)
I tried using display: none; and canvas.style.display= "block"; to hide and show the canvas and got the same behavior.
Here is a test: http://jsfiddle.net/CX49R/
Oddly, in jsfiddle with Chrome, the canvas (and its drawn content) appears after you move the mouse over the document area (after the function triggered by setTimeout is called, of course). But it never appears if the same HTML+CSS+JS code runs in a single Chrome tab/window (unless you open "Development tools" through "Inspect element", or click on the document area).
What am I missing here? I tried to reduce the code to the minimum of my original scenario.
It seems like it's somehow related to the canvas element. Creating a hidden parent div and showing that instead of the canvas element seems to solve the issue:
http://jsfiddle.net/CX49R/2/
<div id="wrapper">
<canvas id="myCanvas">Your browser does not support canvas.</canvas>
</div>
I don't have enough reputation to comment, so I'll give you an answer instead. The issue is not the setTimeout, the issue is with canvas.style.visibility = "visible";. I set up an alert in your timeout and it fired after a second, no problem. My only guess is that canvas.style.visibility is waiting on a mouse event to trigger itself.
I have a page with an embedded youtube video, and I'm trying to implement a custom overlay where you can define areas using a resizable and draggable <div> (using JQuery UI).
When dragging the <div> in other areas of the screen, it's perfectly responsive, but when over the video (embedded using the IFrame API, incase it matters), if you move the mouse at anything other than a crawl, it will regularly 'lose its grip' on the resize handles or the move handle. This is the case in both IE and Chrome.
JSFiddle here: http://jsfiddle.net/MfZes/1/ (draggable box is below the youtube frame)
Does anyone know why this is, or if it's avoidable?
Thanks in advance.
I've done this before.
You can hook onto the dragstart, resizestart, dragstop and resizestop events of jquery ui's resizeable and draggable plugins.
Put the video in a container div. Alongside the video, insert another div which will act as an overlay. Set the width and height to 100%, position it absolutely and set the display to hidden.
When the resize/drag start events fire, show the overlay div. When they stop, hide it. (You need to hide it as you still want to be able to interact with the video when you're not resizing or dragging.
I had the same problem but with hover on canvas:
$('.DraggableDiv').draggable({
start : function() {
var d = document.createElement('div');
$(d).addClass('canvas_shadow');
$('.canvasContainer').append(d);
},
stop : function() {
$( ".canvas_shadow" ).remove();
});
add css for .canvas_shadow:
.canvas_shadow {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
opacity: 0.1;
z-index: 80;
}
I am using amCharts (which uses Raphaƫl behind the scenes) to render some charts as SVG; and have noticed that if the SVG is rendered in an initially-invisible div, the browser does not immediately render the image when the div becomes visible. If I modify the display however, e.g. by resizing the browser or Ctrl-mousewheel zooming, the SVG image is then rendered as expected when the page is redrawn.
The exact method of div visibility switching is via Bootstrap's tabbed navbar.
I admit to not being very experienced with SVG - is this an issue with the browsers' rendering, or amCharts' SVG markup, or am I required to explicitly call some sort of repaint method when I can tell the visibility of an SVG has changed?
Here's a jsFiddle which illustrates the problem; if you switch to Section 2 (in Chrome, Firefox) the chart isn't visible initially. Resizing the display causes it to appear.
I've found the reason for both the initial behaviour and the workaround - and it's all amCharts specific (nothing to do with SVG per se) so I'm rephrasing the title accordingly.
What happens is that when amCharts creates the SVG, it needs to (or at least, decides to) define the width and height in absolute terms. These are based on the size of the target div, obtained via the offsetWidth and offsetHeight properties.
The inactive tab has the display: none property set, and as a result this part of the DOM is not even rendered, so returns zero for both size properties. This ultimately leads to amCharts creating a 0x0 SVG chart when chart.write is called for the hidden div.
Resizing fixes things because each chart registers a listener to the onresize window event, which calls the chart's handleResize method. This forces a recalculation of the width and height based on the div's new (current) dimensions.
So in conclusion I think there are two alternative ways to handle this:
Call chart.write for a chart when and only when its tab becomes visible.
Call each chart's handleResize method when the tabs change.
(The first option avoids the initial hit of rendering an invisible chart, but then does a full redraw every time the tabs are changed. The latter takes a hit up-front but is likely quicker thereafter. For bonus marks, the best solution would be to render each chart exactly once between each resize, the first time it becomes visible, but that's a lot more complex as it would involve interfering with the default event listeners, amongst other things.)
Update: There's further complications with rendering an invisible chart; in particular, I found issues with the height calculations not taking into account the space required by the domain axis and so stretching the chart out of its div. This wasn't fixed by calling handleResize - calling measureMargins beforehand looked like it should work but didn't. (There's probably another method one could call after this to make it work such as resetMargins but at this point it started to feel very flaky...)
As such I don't think it's practical to render a chart for the first time on a non-visible div, so I went with some combination of the bullets above. I listen for when a chart's tab becomes visible for the first time and then call chart.write for the appropriate chart object - and whenever the tabs change, all previously-rendered charts are told to handle the resize.
* Edited *
Here is a updated fiddle. The Canvas will only be rendered once the tab is shown.
I store the chartdiv ids in an array and check whether there are in it or not.
* Edited *
The only solution I found was to show the Graph after the specific tab is shown.
As you see in this jsFiddle.
var tabs = $('.tabbable').tab()
tabs.on('shown', function(e){
id = $(e.target).attr('href');
chartdiv_id = $(id).find('.chartdiv').attr('id');
doChart(chartdiv_id, true);
});
I guess it isn't exactly what you are looking for, but i hope it helps for the moment.
I had the same problem, but my solution it's alternative to display:none, you can use this class in the css
.hidden {
position: absolute !important;
top: -9999px !important;
left: -9999px !important;
}
this dissapear of the screen but visible for the amchart, so the resolution of the chart never lose the size!!!!
I completely agree with Andrzej Doyle.
Issuing handleresize on the chart when clicking on the selected div (tab) works for me on cs-cart with custom tabs (not jquery ones).
The following works while cart beeing globally defined.
function refreshchart(){
chart.handleResize();
};
I also ran into the issue and fixed it by making the initializer a function. Working fiddle.
$("#button").click(function(){
$("#chartdiv").toggle();
makeChart();
});
function makeChart() {
var chart = AmCharts.makeChart("chartdiv", {
//all the stuff
});
}
This Might help you to resolve issue . I have my amchart showing in different tab pan . SVG Component does not allow them to show that div due to resizing issue .
$(window).resize(function() {
setTimeout(function() {
chart.write("chartdiv1");
}, 300);
});
resize again your window while you create your charts ..
Show me charts
<div class="charts_div" style="display:hidden;">
some charts here
</div>
<script>
$(document).on('click', '.show_charts', function(){
$('.charts_div').toggle();
//just redraw all charts available on the page
for(var i = 0; i < AmCharts.charts.length; i++) {
AmCharts.charts[i].validateData();
}
});
</script>
var chart = null;
AmCharts.ready(function () {
chart = AmCharts.makeChart('chart', .....);
});
$(document).ready(function(){
$("#view_chart").click(function(){
chart.validateSize();
});
});
<button type="button" id="view_chart">View Chart</button>
<div style="display:none;" id="chart"></div>
Another work around would be
drawTransactionTypeChart();
setTimeout(function(){hidePieCharts();},1);
Initially set display:inline to div which is chart container, it gets rendered .
Then set display:none using setTimeout() after 1ms.
Hope this helps...
I have two amcharts on different tabs.
A stock chart to be place on #chartdiv and a pie chart to be placed on #chartdivpie.
This is how I solved my problem.
My custom css - to overwrite bootstrap -
#chartdivpie { width: 1138px; height: 500px; }
.tab-content .tab-pane {
position: absolute;
top: -9999px;
left: -9999px;
display: inline;
}
.tab-content .tab-pane.active {
position: inherit !important;
}
JQuery call
$('#myTab a').click(function (e) {
e.preventDefault()
$(this).tab('show');
chart.invalidateSize();
chart.write('chartdiv');
})