I have an asp.net app with an iframe in it on a tab in the markup. The content of the iframe is a Leaflet based map display. The markup:
<div id="tabMapDisplay" class="tab-pane row container">
<div id="divMapDisplay" runat="server" class="col-xs-12 col-sm-12 col-md-12 col-lg-12 fieldset-border-bg-defaults">
<div class="embed-responsive embed-responsive-16by9">
<iframe id="ifrMap" runat="server" allowfullscreen="true" class="embed-responsive-item" />
</div>
</div>
</div>
The source url for the Leaflet display is a parameterized url set in the code behind based on data for the overall display. Works great, shows the map with the target as desired. Except if the target is a very large feature on the map it then shows the display and the target feature can stretch beyond the boundary visible in the iframe so that part of the feature is hidden until the user zooms out on the map.
I decided to try having the Leaflet app adjust the zoom level dynamically so that larger features will fit when viewed in an iframe. When viewed straight up in the browser they show just fine. Here's what I've got trying to determine the zoom level so far (I've cut out all the experimental bits I've been attempting all day):
function inIframe() {
try {
return window.self !== window.top;
} catch (e) {
return true;
}
}
function optimalZoomLevel(boundsZoom) {
if (boundsZoom < zl) {
zl = boundsZoom;
}
if (inIframe()) {
zl = zl - 1;
}
return zl;
}
zl is set to a default zoom level value as a starting point. Everything is fine as I said when directly in the browser. But in the iframe (the detection function inIframe works correctly), once this code knows it the page is in an iframe no matter what I do I cannot seem to get the height and width of the containing frame. Everything I've tried comes up either 0, undefined, or the dimensions of the browser window not the iframe. I've tried using a number of different options I've found by searching but so far nothing more than 0 or undefined for the width value I'm looking for. I figure if I can know the width then I can adjust the zoom level to something appropriate so the whole of the larger candidate marker/shapes show in the iframe.
Any suggestions are appreciated.
Related
Im in the process of developing a 'flipbook-style' animation using Skrollr by triggering background image changes when the user scrolls to indicated positions on the page. The issue i'm having is that in browser the image changes are delayed, creating what can only be defined as a 'flicker' of white between the frames.
<div class="section" style="background: url('frame1.png')"
data-560-top="background-image:!url('frame1.png');"
data-440-top="background-image:!url('frame2.png');">
The HTML is simple; it basically states that at 560 pixels from the top of the div (in relation to the browser window), the background should be at frame 1, then as the user scrolls closer to the div (440 pixels from the top of the div) the background image changes to frame 2. I plan to use up to around 20 frames and the images are quite large.
I have created a JSBin here which includes a very simplified sample with images from placehold.it. This includes the Skrollr script and an example layout of a section of my project. The key difference being that the images in my project are of much larger scale.
(function($) {
var cache = [];
// Arguments are image paths relative to the current page.
$.preLoadImages = function() {
var args_len = arguments.length;
for (var i = args_len; i--;) {
var cacheImage = document.createElement('img');
cacheImage.src = arguments[i];
cache.push(cacheImage);
}
};
})(jQuery);
jQuery.preLoadImages(
'http://www.placehold.it/300x200.png',
'http://www.placehold.it/300x200.png'
);
The above snippet seems to be working on Chrome, however the flicker issue remains in Firefox. Based on research, firefox handles cached images differently from Chrome? (e.g Where an image is not considered needed by firefox at a given time, it is trashed?)
I would like to know how I could possibly force all browsers to preload the images efficiently, to potentially avoid the background image flicker upon change. I am still quite new to Javascript/JQuery.
I hope I have provided a clear explanation. All assistance appreciated.
Dan
You can preload images using CSS only, no need for JS. Check out this article for more info. Another interesting way to do it is in the comment section of the article. Basically you assign the background image to a pseudo-element so that is is cached and ready to be used whenever. See this code for an example:
#something:before {
content: url("./img.jpg");
width:0;
height:0;
visibility:hidden;
}
I am using Google's line chart almost exactly as the demo - only the data has changed - inside of this jQuery tab plugin with no modification. Maybe 50% of the time, the chart will load at 400x200 even though it has been specified to load at 700x250. The containing div will have the proper width and height, but the chart as rendered by the API will load inside of that at 400x200.
I suspect this is because the tabs aren't being displayed when the API tries to render. Because of that, it tries to render in something it considers null and therefore forces itself into the smallest default resolution.
My thought is that if the display of the chart can be delayed until the appropriate tab is clicked, it would resolve the problem. Sadly, I have no idea how to do that, and my research hasn't been fruitful. The closest I could find is this thread, but I didn't find any real answers there.
I'd appreciate any advice if you have any, and I'd be glad to follow up with more information if necessary.
Rendering charts in a hidden div (which is what the non-selected tabs of a tab UI most likely are) messes with the Visualization API's ability to detect dimensions, so you want to do one of two things: either render all charts before instantiating tabs, or (as you've caught on to) bind event listeners to draw the charts when a tab is first opened. Setting the height and width in the chart's options is insufficient to solve the problem in all browsers.
I scanned over the easytabs documentation, and it looks like you should be able to do something like this:
// draw chart(s) in your default open tab
// track which tabs you've drawn charts in
var chartsDrawn = {
tab1: true,
tab2: false,
tab3: false
// etc
};
$('#tab-container').bind('easytabs:after', function (e) {
if (e.tab == 'tab-2' && !chartsDrawn.tab2) {
// draw chart(s) in tab 2
chartsDrawn.tab2 = true;
}
else if (e.tab == 'tab-3' && !chartsDrawn.tab3) {
// draw chart(s) in tab 3
chartsDrawn.tab3 = true;
}
// etc
});
change chart options to set the width and height as you need
var options = {
title: 'Company Performance'
,width:900
,height:500
};
This is how I solved using angular-bootstrap https://angular-ui.github.io/bootstrap/
<div class="google-chart" google-chart chart="chartObject1" on-ready="displayGoogleCharts()"></div>
<tab heading="Past Week" select="googleChartSizeFix()">
googleChartSizeFix = function() {
$('svg').parent().css({ opacity:"0" });
$(window).resize();
};
displayGoogleCharts = function() {
$('svg').parent().css({ opacity:"1" });
};
Each time a Tab is selected (the function googleChartSizeFix is triggered) the Google Chart is set to transparent (opacity = 0, so it does not disappear by the use of hide(), but keeps its size since its content is transparent) followed by the window resize is triggered, this forces Google Chart to fit the div that contains it, by the use of width 100% and height 100%:
"options": {
"chartArea": {
"width":'100%',
"height":'100%'
}
}
and finally once the Google Chart is ready (after resize) the displayGoogleCharts function is triggered and the opacity of the google chart is reset to 1, so the content is visible once again.
I stumbled across this "feature" of Bootstrap tabs. When cut-and-pasting multiple tabs in my HTML, I accidentally left the <div class=" tab-pane active"> in the "active" state for all the tabs. The result was that the content for all the tabs displayed sequentially in the first tab, but went away as you switched tabs.
My solution to the hidden tabs is to define them as active and then remove the "active" class from the div after I call chart.draw.
<div class="tab-pane active" id="myid" role="tabpanel">
<script type="text/javascript">
// all the chart stuff
chart.draw(data, options);
$('#myid').removeClass('active');
</script>
</div>
I see that jQuery tabs also use the "active" class. Perhaps this trick will work there too.
I solved this by, leaving off the bootstrap class in the element holding the chart, and then after chart had been loaded, then apply the bootstrap class.
For example lets say we want to setup a collapsible with the chart in it:
<a href="#div-id" data-toggle="collapse">
Expand
</a>
<div id="div-id" class="future-collapse">
<div id="some-chart"></div>
</div>
And then in your script:
/**
* Callback function E.G. google.charts.setOnLoadCallback(drawChart);
*/
function drawChart(){
// Drawing the charts
draw_some_chart();
// Applying the collapse class to our elements with the future-collapse class
$('.future-collapse').attr('class', 'collapse');
}
function draw_some_chart(){
// Draw your charts
}
I am trying to make a flipbook using turn.js that has the same functionality as the example on the website http://www.turnjs.com/samples/magazine/
When looking at how to achieve this I came across these pages
http://www.turnjs.com/docs/Method:_zoom
http://turnjs.com/docs/How_to_add_zoom_to_turn.js
But after following these instructions on the pages my flipbook works nothing like the sample one.
I tried using the sample provided and breaking it down into sections to get mine working but I have not gotten any closer to solving this problem and the sample contains a bunch of other scripts and I am not sure if they are required for the zoom or are used for other things.
Not sure if I am missing something really simple or if my code is really off but my html looks something like this.
Right now all I get when clicking the zoom button is that the book scales up 150%
Was wondering if anyone could tell me what I am missing to get that zoom?
<div class="row">
<div id="zoom-viewport">
<div id="flipbook">
// wordpress loop
<div class="page">
// page contents
</div>
// end loop
</div>
</div>
</div>
and jQuery
//----------------------------
// Initialize
var _width = $('#flipbook-wrap').width(),
_height = Math.round(70.909090909/100*_width),
_winWidth = $window.width(),
_winHeight = $window.height();
$("#flipbook").turn({
width: _width,
height: _height,
autoCenter: true
});
//----------------------------
// Zoom in button
$('.fullscreen').click(function(e){
e.preventDefault();
$("#flipbook").turn("zoom", 1.5);
});
Your code isn't showing everything (e.g. where ".fullscreen" or the "zoom button" is in your HTML), so my answer may not be precise.
Looking at the sample, you should find the code:
$('.magazine-viewport').zoom('zoomIn', pos);
This seems to differ from turn('zoom', ...), and appears to be undocumented. This is a function that will zoom in the element defined as a turn object. I believe, for you, this is your "#flipbook" element, instead of ".magazine-viewport".
The parameters are "zoomIn" and pos, which may be a different functionality that what you're using currently. The "pos" appears to be a JS object that contains "x" and "y" properties, meant to define where you clicked on the magazine. These coordinates are relative to the magazine, not the whole screen, so keep that in mind.
So, I think you need something like this (at least try it at a starting point):
$('#flipbook').click(function(e) {
var pos = {
x: e.pageX - $(this).offset().left,
y: e.pageY - $(this).offset().top
};
$('#flipbook').zoom('zoomIn', pos);
});
Hope this helps!
To get zoom to work with turn.js, there are three things you need to do:
Setup the proper dom structure, zoom won't work without the "container" div to wrap the flipbook.
<div class="magazine-viewport">
<div class="container">
<div class='magazine'>
<div id='p1'><img src='book_1.jpg'></div>
<div id='p2'><img src='book_2.jpg'></div>
</div>
</div>
</div>
Setup the js events
$( document ).ready(function() {
//Initialize the turn.js flipbook
$('.magazine').turn({
width: 1136,
height:734,
pages:100,
autoCenter: false,
when:{
missing: function (e, pages) {
for (var i = 0; i < pages.length; i++) {
$('.magazine').turn('addPage',page[pages[i]],pages[i]);
}
}
}
});
//Initialize the zoom viewport
$('.magazine-viewport').zoom({
flipbook: $('.magazine')
});
//Binds the single tap event to the zoom function
$('.magazine-viewport').bind('zoom.tap', zoomTo);
//Optional, calls the resize function when the window changes, useful when viewing on tablet or mobile phones
$(window).resize(function() {
resizeViewport();
}).bind('orientationchange', function() {
resizeViewport();
});
//Must be called initially to setup the size
resizeViewport();
}
function page(num){
var elem = $('<div />',{}).html('<div><img src="book_'+num+'.jpg></div>');
return elem;
}
function zoomTo(event) {
setTimeout(function() {
if ($('.magazine-viewport').data().regionClicked) {
$('.magazine-viewport').data().regionClicked = false;
} else {
if ($('.magazine-viewport').zoom('value')==1) {
$('.magazine-viewport').zoom('zoomIn', event);
} else {
$('.magazine-viewport').zoom('zoomOut');
}
}
}, 1);
}
function resizeViewport() {
var width = $(window).width(),
height = $(window).height(),
options = $('.magazine').turn('options');
$('.magazine-viewport').css({
width: width,
height: height
}).zoom('resize');
}
Define proper css styles for the elements, the trick here is that the negative coordinates of the magazine class is compensated by the top & left offsets of the container class.
.magazine-viewport .container{
position:absolute;
top:367px;
left:568px;
width:1136px;
height:734px;
margin:auto;
}
.magazine-viewport .magazine{
width:1136px;
height:734px;
left:-568px;
top:-367px;
}
/* Important: the image size must be set to 100%.
* Otherwise the position of the images would be messed up upon zooming.
*/
.magazine img{
width:100%;
height:100%;
}
That should get it to work, if you want to load a larger version of the image upon zooming, take a look at the loadSmallPage() & loadLargePage() functions in the magazine example.
I had the same problem, but I decided to just use a third party zoom plugin (Jack Moore's jQuery zoom). It turns out the example in the site is a lot more complicated, with a json to create diferent regions and images for each paragraph.
It really depends on what you're using turn.js for, but I think the documentation isn't right, or the software itself is missing something. Either way, I do suggest you look into using some other solution for the problem.
turn.js provides an example with zoom. The difficulty to make it work is to gather all the required files. But if you watch the code, it is possible. Say the root is magazine, it goes two folders up to get lib and extras folders where java scripts are laying. In addition, you have to add the "default" and large pages in the pages folder. When you get the sample, there are only the thumbnails in. Say for 1-thumb.jpg, you have to add 1.jpg and 1-large.jpg
There is a very usefull Firefox plugin to get them : CacheViewer.
I have managed to do it with my book, and reorganize the paths in the code to have something cleaner: put lib and extras at the same level than pages. A recursive grep for "/../../" will give you all the locations in html and js code.
What are the Javascript or jQuery or jQuery mobile events involved in pinch zoom in and zoom out? I am trying to capture those events to zoom in and zoom out of an image which is inside a div without affecting the entire layout of the website. Simplest way to detect a pinch works for iPad but not android.
What are the equivalent way to detect the same on Android platform for web?
Any help is appreciated.
EDIT: I have been trying touchy.js and that works for doing zoom-in and zoom-out for images but, zooming into an image is not useful if part of the image is not accessible by finger swipe or something of that sort.
For example, consider the following code:
<div style=" border: 1px solid blue; width: 560px; overflow:scroll;">
<p> </p>
<img id="image" src="images/tux.png" alt="my image" style=" border: 1em solid gray;" />
</div>
I need the image to stay inside the div and the user should be able to move around the image after they zoom in. But with this code, I have to swipe my finger on the empty region (created by the paragraph tag) in order to go to different part of the image horizontally. Same happens vertically (you'll have to swipe your finger on an empty space on the web page in order to see the image length wise). What I am trying to say is, swiping motion inside the image does not have any effect while the users will expect to do that after zooming into the image.
It's very hard to explain without an example and I tried creating http://jsfiddle.net/Debarupa/8peaf/ but it does not work as I would like it to since I cannot edit the meta in head. I needed to add:
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no, minimum-scale=1" />
so that the entire webpage is not zoomable.
You can calculate your own scale by monitoring the user's gesture and tracking the points of contact of their fingers.
Something like:
var tracks = [];
$myElement.on("touchmove", function (event) {
//only run code if the user has two fingers touching
if (event.originalEvent.touches.length === 2) {
//track the touches, I'm setting each touch as an array inside the tracks array
//each touch array contains an X and Y coordinate
tracks.push([ [event.originalEvent.touches[0].pageX, event.originalEvent.touches[0].pageY], [event.originalEvent.touches[1].pageX, event.originalEvent.touches[1].pageY] ]);
}
}).on("touchstart", function () {
//start-over
tracks = [];
}).on("touchend", function () {
//now you can decide the scale that the user chose
//take the track points that are the closest and determine the difference between them and the points that are the farthest away from each other
});
But, if you want to use something pre-made, then I suggest checking-out Touchy: https://github.com/HotStudio/touchy
Greetings.
I am developing an animated homepage for a Flash-HTML hybrid website, and for the sake of standards, my solution is proving difficult. I am not a Javascript pro, so any help is appreciated!
Here is the run-down:
For Flash users, HTML page loads a variable-height AS3 Flash movie that will start at 556 pixels high, and after finishing its animation sequence, tween via Actionscript + JavaScript to 250 pixels high.
To kick off this movie sequence -- (below-left) -- I am attempting to set the initial height of the Flash movie via MooTools, so if users do not have Flash or Javascript enabled, they will see the shorter-height image area with alternative image content and HTML content revealed (below-right).
Element.setStyle sets the height just fine until swfObject runs, at which point the movie collapses since I am not specifying a height via CSS. If users do not have Flash, it defaults to the height of a static image.
So here is my question: Does anyone know how to dynamically pass a height variable to swfobject when it is set up to width/height # 100%? Am I killing myself for no reason trying to work with two page heights?
Image Sequence:
Left - Initial Flash movie with HTML navigation below
Right - Resized movie at the end of the sequence with HTML nav & content below, looks the same as no-Flash version (static image)
alt text http://client.deicreative.com/op/images/twopages.jpg
^^ should land here for users w/o Flash
<script type="text/javascript">
<!--
window.addEvent('domready', function() {
$('flashContent').setStyle('height', 556); // sets height for initial movie
$('homeContent').setStyle('display', 'none'); // hides homepage text + photos below
doSwfObject(); // attempting to start swfObject after setStyle is done
});
function resizePage(h) { // to be called from AS3
var tweenObj = new Fx.Tween('flashContent');
tweenObj.start('height', h);
}
function doSwfObject(){
var flashvars = {};
var params = { scale: "noScale" };
var attributes = { id: "flashContent", name: "flashContent" };
swfobject.embedSWF("swf/homeMovie.swf", "flashContent", "100%", "100%", "9.0.0", false, flashvars, params, attributes);
alert(document.getElementById('flashContent').style.height);
// alerts & shows correct height, but page collapses after hitting 'ok'
}
//-->
</script>
The simplest solution is to embed your SWF in a wrapper DIV. Set the SWF to 100% width/height of the wrapper DIV, then use JS to resize the wrapper DIV, not the <object> itself. Less buggy that way.
Since SWFObject 2 replaces the target DIV with the object, you'll need an additional div in your markup:
<div id="wrapper">
<div id="flashcontent"></div>
</div>
becomes
<div id="wrapper">
<object id="flashcontent" width="100%" height="100%" (etc.) ></object>
</div>
I think the act of posting something on here helps me think through the problem -- after doing so, the answer became more clear. So here is my solution for anyone who stumbles across this later.
To animate the Flash movie's height to its initial, taller state while preserving shorter height for non-Flash users (see images above), I use JavaScript the same way I would to tween the movie's height once sequence is complete. The result resembles a push-down ad on a newspaper website.
In AS3, after preloading is done, I tell Javascript to tween the height of the flash movie container (simplified, obviously -- there is no preloading code):
package {
import flash.display.MovieClip;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.external.ExternalInterface;
public class HomeMovie extends MovieClip {
private var stageHeight:uint;
public function HomeMovie(){
this.stage.scaleMode = StageScaleMode.NO_SCALE;
this.stage.align = StageAlign.TOP_LEFT;
stageHeight = 556;
// Tell javascript the stage needs resizing.
if (ExternalInterface.available) {
ExternalInterface.call("resizePage", stageHeight);
}
}
}
}
In JavaScript (via MooTools):
<script type="text/javascript">
<!--
window.addEvent('domready', function() { // hide content on home-page below movie
$('homeContent').setStyle('display', 'none');
});
function resizePage(h) {
var tweenObj = new Fx.Tween('flashContent', {
property:'height',
duration:500,
transition:Fx.Transitions.Quad.easeOut
});
tweenObj.start(h);
}
//-->
</script>
I will probably take it one step further and check for Flash before hiding the home-page content, so that it will not occur if the user has Javascript but not Flash. Again, this is all for the sake of standards.
Have you tryed SWFForceSize? It's an SWFObject addon and it could help you. Even if you don't use it, you could take a look at the source code to see how they do things.
Btw you don't need SWF object when using Mootools as it has a call called Swiff that does everything SWFObject does and then some! :D