I'm trying to generate large png screenshots of web pages using PhantomJS, which is built on webkit. I have the application generating screenshots just fine (using their raster.js example.) But, I want the text to be larger (rather than 12-16px) - I don't care about the images becoming grainy. I thought that I could simply scale/zoom the webpage doing something like:
document.documentElement.style.webkitTransform = "scale(2.0)";
But that causes the content of the page to escape the viewport. You can see this if you evaluate that line of code in Chrome. Is it possible to scale a whole web page (duplicating "Ctrl +" functionality of the browser) in JavaScript/Phantom.js?
My current phantom.js script looks like:
var page = new WebPage(),
address, output, size;
if (phantom.args.length < 2 || phantom.args.length > 3) {
console.log('Usage: rasterize.js URL filename');
phantom.exit();
} else {
address = phantom.args[0];
output = phantom.args[1];
page.viewportSize = { width: 1280, height: 1024 };
page.open(address, function (status) {
if (status !== 'success') {
console.log('Unable to load the address!');
} else {
page.evaluate(function () {
document.body.style.webkitTransform = "scale(2.0)";
});
window.setTimeout(function () {
page.render(output);
phantom.exit();
}, 200);
}
});
}
Try
page.zoomFactor=2.0;
The webkitTransform CSS property is not going to do what you want, with or without setting the origin. For one thing, it does not change the dimensions of elements (ie, no relayout occurs, the element(s) are zoomed within their current bounding boxes).
Update
You forgot to set the CSS transform-origin property, so your content expands half up and half down (the default is 50% 50%) and the upper part escapes.
So set it to 0% 0% to get the transform happen only down and right:
document.body.style.webkitTransformOrigin = "0% 0%";
You will also have to set the body width to 50% to avoid it ending twice as large as your viewport:
document.body.style.width = "50%";
Old answer - disregard
This resolves only vertical alignment
Ok, the scaling goes up and down, but the viewport extends only down. The fix fortunately is easy: move your content down of half its height.
Use this as your doubling function and you'll be fine:
page.evaluate(function() {
var h = $('body').height();
$('body').css('position', 'relative');
$('body').css('top', h/2 + 'px');
$('body').css('-webkit-transform', 'scale(2.0)');
});
Be aware anyway that getBoundingClientRect() and page.clipRect behaves weirdly when dealing with this transform.
Related
I'm wondering if it's possible to use only CSS to create a parallax scrolling background that meets the following specifications.
It works on an element that sits inside an otherwise static layout (i.e. my whole page layout isn't a group of parallaxing items)
The background isn't entirely fixed in place; it moves, just not as fast as the rest of the page.
I've looked up tons of tutorials for parallaxing backgrounds, and have found some seemingly great tutorials, but they all have one of the following problems.
They rely on the whole page being a parallax group so that you're actually scrolling over a container via an "overflow: auto" specification
The background is totally fixed in place
they use JavaScript.
Sooo, I can accomplish what I want with JavaScript fairly easily. Here's a full working example on JSFiddle that you can try out.
CSS
.parallax-row {
background-image: url(http://lorempixel.com/output/nature-q-c-781-324-3.jpg);
background-size: auto 150%;
}
JavaScript
/**
* Update the parallaxing background img to partially scroll
*/
jQuery(document).ready(function($) {
$(window).on('scroll', function() {
$('.parallax-row').each(function(index, el) {
var $el = $(el);
var fromTop = $el.offset().top + ($el.outerHeight() / 2) - $(window).scrollTop();
var windowHeight = $(window).height();
var percent = (fromTop * 100 / windowHeight);
$el.css('background-position', '0 ' + percent + '%');
});
});
});
Is it possible to accomplish that same effect with just CSS?
Let me start with i am sorry for the long post.
I'm attempting to use the bootstrap carousel and unfortunately the pictures i have been given are NOT uniform. for example some are 100x200, doe are 150x100, etc. The aspect ratios are different, letter vs landscape. Ive attempted a number of things, including the using the following helper function on load of each of my images in the Carousel:
function ScaleImage(srcwidth, srcheight, targetwidth, targetheight, fLetterBox) {
var result = { width: 0, height: 0, fScaleToTargetWidth: true };
if ((srcwidth <= 0) || (srcheight <= 0) || (targetwidth <= 0) || (targetheight <= 0)) {
return result;
}
// scale to the target width
var scaleX1 = targetwidth;
var scaleY1 = (srcheight * targetwidth) / srcwidth;
// scale to the target height
var scaleX2 = (srcwidth * targetheight) / srcheight;
var scaleY2 = targetheight;
// now figure out which one we should use
var fScaleOnWidth = (scaleX2 > targetwidth);
if (fScaleOnWidth) {
fScaleOnWidth = fLetterBox;
}
else {
fScaleOnWidth = !fLetterBox;
}
if (fScaleOnWidth) {
result.width = Math.floor(scaleX1);
result.height = Math.floor(scaleY1);
result.fScaleToTargetWidth = true;
}
else {
result.width = Math.floor(scaleX2);
result.height = Math.floor(scaleY2);
result.fScaleToTargetWidth = false;
}
result.targetleft = Math.floor((targetwidth - result.width) / 2);
result.targettop = Math.floor((targetheight - result.height) / 2);
return result;
}
function OnImageLoad(evt) {
var img = evt.currentTarget;
// what's the size of this image and it's parent
var w = $(img).prop('naturalWidth');
var h = $(img).prop('naturalHeight');
//var tw = $(img).parent().width();
//var th = $(img).parent().height();
var tw = $(img).parent().parent().parent().parent().width();
var th = $(img).parent().parent().parent().parent().height();
// compute the new size and offsets
var result = ScaleImage(w, h, tw, th, true);
// adjust the image coordinates and size
img.width = result.width;
img.height = result.height;
$(img).css("left", result.targetleft);
$(img).css("top", result.targettop);
}
and using the following for each of my images for the carousel
<img src="~/Images/Img1_Tall.jpg" alt="Tall" id="firstImage" onload="OnImageLoad(event);" />
and for the FIRST image in the carousel it works great, but each one after that they seem to just end up their natural size and are horizontally centered but are just against the top boarder of the carousel.
I've even changed the "onload" to pass the values of the length and width of the image but that didn't work either, in debug it seems only the first image kicks off the "onload" event.
the effect i am going for is if the ratio of the container is 3:4 and the ratio of the image is 1:2, the image stretch to meet the left and right edges and would center vertically and have letter box above and below, but the container does not change so that the navigation buttons of the carousel do not move. if the image is 2:1, the image would stretch to meet the top and bottom centered horizontally with letterboxes on the right and left, again keeping the navigation buttons unmoved.
any help would be appreciated... including:
what you are trying to do is crazy
do you want to do something like http://jsbin.com/zotelasa/1 . With that code I can get the active items w,h or any other variables you used in your code to run scale image. Because of parent.parent codes it applies to carousels main divs but you can set your own container.
The quick and dirty solution would be to resize the images using an image editor, and save the properly-sized images to a folder named eg carousel_images. Then whenever you get new content you simply run the image through your editor. With a carousel you're most likely dealing with a number of images in the several to dozens range and not hundreds or thousands.
A more complicated solution is explain to your image provider that you need everything one size. The images aren't going to look right if you're stretching and skewing them on the fly, and you can show them an image with the aspect ratios wrong to explain what you mean.
Finally, as a technical solution, I would try to find out why your image resizer is only being run on the first image. From the sound of it, other images just aren't being run through your function. I think that the technical solution should be a last resort in this case because, like I said, the end results are just not going to be as good. You should at a minimum, if possible, handle each image by hand to make sure the result is adequate.
...And the answer is a little long too...
• I assume that the width’s image’s parent is a constant, and while you don’t change the width’s viewport that must remain.
A-. Get the width’s image’s parent…
(Because the id attribute I took the grand parent’s parameter, that is (must be) the same than the parent’s one).
B-. With the below value deduce the height’s image’s parent, including the preferred ratio (in this case 16x9…
C-. … And with this, set the images’ parents height collection (all the elements with class=”item”).
D-. In order to conserve your carousel’s responsive characteristic, you must add the $F_getAdjustImagesParents function to the window resize event.
E-. Set the slide’s images position to absolute (Note: That must be via JQuery because if you do it in Css the bootstrap carousel will not display correctly. I did it with a new class for the images ('myCarouselImgs').
• Bootstrap carousel’s event 'slide.bs.carousel' and 'slid.bs.carousel'.
As you know, after the ‘click’ event, the slide.bs.carousel event is one of the firsts events that imply the change from the present slide to the next one; while the 'slid.bs.carousel' one is the end of the process.
F-. In the first one (slide.bs.carousel event), using the ‘relatedTarget’ variable of the Bootstrap’s plugin, the item’s id attribute and a item’s data attribute, get the number of the next item (ensure that these last ones -id attribute and data attribute- be present).
G-. In the second one, 'slid.bs.carousel', get the image’s size. For that you need to identify the implied image. I gave an id to each one. With this and the value obtained in previus step, it can do it.
H-. Well, now you already have the four values required for the ScaleImage function. You can call it…
I-. … And apply the result with some effect
var $parentImgW = ' '
var $parentImgH = ' ';
var $myCarousel = $('#myCarousel')
var $carouseItems = $('.item');
function $F_getAdjustImagesParents(){
$parentImgW = $myCarousel.width(); // A
$parentImgH = ($parentImgW*9)/16; // B
$carouseItems.height($parentImgH+'px').css('max-height',$parentImgH+'px'); //C
console.log('$parentImgW ====> '+$parentImgW);
console.log('$parentImgH ====> '+$parentImgH)
};
$F_getAdjustImagesParents();
$(window).on('resize',function(){ // D
$F_getAdjustImagesParents();
});
$('.myCarouselImgs').css('position','absolute'); // E
$myCarousel.on('slide.bs.carousel', function(event) {// The slide’s change process starts
var $slideNum = $("#"+event.relatedTarget.id).data('slide_num'); // F
console.log('$lideNum ====> '+$slideNum)
$myCarousel.on('slid.bs.carousel', function(event) {//The slide’s change process ends
var $imgW = $('#myCarouselSlideImage'+$slideNum).width(); //G
var $imgH = $('#myCarouselSlideImage'+$slideNum).height(); //G
console.log('$imgW ====> '+$imgW);
console.log('$imgH ====> '+$imgH);
var $result = '';
$result = ScaleImage($imgW, $imgH, $parentImgW, $parentImgH, true); //H
console.log('$result.width ====> '+$result.width);
console.log('$result.height ====> '+$result.height);
console.log('$result.targetleft ====> '+$result.targetleft);
console.log('$result.targettop ====> '+$result.targettop);
$('#myCarouselSlideImage'+$slideNum).animate({ // I
width:$result.width+'px',
height:$result.height+'px',
left:$result.targetleft+'px',
top:$result.targettop+'px' },
300);
});
});
See it runnig at https://jsfiddle.net/nd90r1ht/57/ or at https://jsfiddle.net/omarlin25/nd90r1ht/59/
I have few pages that I show from my main page inside iframe.
I got a background image in the main page, when I click the button to change the page inside the frame the frame background color is becoming white somtimes until the page is visible.
I added background-color:transpert to the pages themselves and to the main page CSS.
I checked the site with FireFox and IE and it look fine (the background of the frame doesn't change) but with Chrome it somtimes rendering fine like I wanted it to be and other times the iframe background goes White.
Can i do anything that will fix that?
As this is browser behavior I doubt it can be really "fixed".
One workaround is to hide the frame while it's loading (only for Chrome) - here is the code:
var isChrome = (navigator.userAgent.indexOf("Chrome") >= 0);
function LoadFrame(url) {
var oFrame = document.getElementById("myframe");
if (isChrome) {
oFrame.style.visibility = "hidden";
oFrame.onload = function() {
oFrame.style.visibility = "visible";
};
}
oFrame.src = url;
}
Live test case. (Reloading same frame there but the concept is the same)
I used very similar attitude. This approach works only in case the page inside your iFrame is under your controll.
The change is that the page inside iframe finds the iframe in parent window and makes it visible again:
<iframe style="visibility: hidden;" id="iframe_id" src="my_page.html" />
// inside my_page.html:
window.onload = function() {
// make sure the parent iframe is visible
if (window.parent)
{
var nodeIframe = window.parent.document.getElementById(window.name);
if (nodeIframe)
{
nodeIframe.style.visibility = "visible";
}
}
};
I'm using code mirror to display, highlight and edit xml in a web page but I am having a problem with the cursor position being offset from the insert position so that if you delete a character from where the blinking cursor is, a character before the one you would expect gets deleted instead. I am assuming its a css clash with my current page because it works well outside my page, but cant find the clash anywhere. Has anyone had similar issues or know what to do?
Further investigation shows that the page had padding set on all divs embedded in fieldsets which was the cause of the problem.
The following lines fixed the issue for me:
.CodeMirror pre {
white-space: pre-wrap;
word-break: break-all;
word-wrap: break-word;
}
I'm using lineWrapping: true in my CodeMirror configuration. Setting that to false works as well.
Be careful using zoom in your CSS with CodeMirror.
I used zoom in body and removing that worked for me.
This issue often happened to me after resizing a parent container. What helped was:
editor.setSize("100%", "100%");
editor.focus();
in the end of a resize event handler.
Sometimes, also, below italic or bold -containing lines (depending on your OS and browser), cursor has a wrong vertical position up to 90% of a line. It can be easily fixed by setting, e.g.
.CodeMirror pre {
height:15px;
}
anywhere in your CSS stylesheets. This also provides you with a way to control line height, if you find lines of code showing too close to each other.
For some reason the white spaces when indention is enabled were not treated correctly when calculating the line size. Replacing measureLine function with the following in codemirror.js did the trick for me:
function measureLine(cm, line) {
// First look in the cache
var cached = findCachedMeasurement(cm, line);
if (cached) return cached.measure;
// Failing that, recompute and store result in cache
var measure = measureLineInner(cm, line);
var origL;
var origR;
var lastR ="";
for (var mes in measure) {
origL = measure[mes].left;
origR = measure[mes].right;
if (lastR != "") {
measure[mes].left = lastR;
measure[mes].right = lastR + (origR - origL);
}
if (origL == origR) {
measure[mes].right = measure[mes].right + 8;
}
lastR = measure[mes].right;
}
var cache = cm.display.measureLineCache;
var memo = {
text: line.text,
width: cm.display.scroller.clientWidth,
markedSpans: line.markedSpans,
measure: measure,
classes: line.textClass + "|" + line.bgClass + "|" + line.wrapClass
};
if (cache.length == 16) cache[++cm.display.measureLineCachePos % 16] = memo;
else cache.push(memo);
return measure;
}
How can I load images to cover the whole background like some websites, using CSS. Not the usual background-image property but I want to load the images quickly.
Examples:
http://www.marinayachting.it/
http://alexandraowen.co.nz/
background-image is the only way to place images in CSS. If you want it to be vary large put it on the body element or a container div that fills the entire viewport.
body {
margin: 0;
padding: 0;
width: 100%;
background-image: url('my_big_image.jpg') norepeat;
}
If you use a container div you can set position:fixed; top:0; left:0 and the image will remain stationary when the page scrolls.
There's no magic to it. As far as getting it to load quickly I don't think there's much you can do if it doesn't repeat. If it does repeat then make sure your image is the size of one module. This can be as little as one pixel tall or wide depending on the content.
There is no magic to making a background image load quickly, you just:
Have a fast server.
Compress the image as much as possible.
Make your page HTML small so that the rest can start loading as soon as possible.
Don't have many other images that also has to load.
Don't have a lot of scripts and other external files that has to load.
I found this tutorial helpful. ->
http://css-tricks.com/perfect-full-page-background-image/
Bing is loading a normal background image with a fixed size. It´s not particularly fast (for me...), but perhaps it seems fast because the image is cached after the first time you load it.
You can set the style inline so that the image can start downloading without waiting for any css file to be ready.
If you set an image let's say a picture as a background you need to make it large enough to accommodate large screen sizes. You don't want the experience on your site to be, that your picture repeats multiple times on the screen. Probably at the least width should be 1260px. If background is just a simple gradient, you can cut a small part of it in photoshop and apply it on the body like this:
body {
margin:0;
padding:0;
background:#fff url(your/image/location.jpg) repeat-x scroll 0 0;
}
This method could be applied to divs too, Good luck.
In your second example site, alexandraowen.co.nz, if you took a second to look at the JS they use, you would have seen the following:
// backgrounds --------------------------------------------------------------//
var Backgrounds = {};
Backgrounds.init = function()
{
$('body').each
(
function()
{
var imgsrc = $(this).css('background-image');
if(imgsrc != 'none')
{
imgsrc = imgsrc.slice( imgsrc.indexOf('(') + 1 , -1);
$(this).css('background-image', 'none');
$(this).prepend('');
if($.browser.msie)
{
// ie 7 is the slow kid and we have to strip out quote marks ffs!
$(this).find('div.bg img').attr('src', imgsrc.split('"').join(''));
}
else
{
$(this).find('div.bg img').attr('src', imgsrc);
}
}
}
);
Backgrounds.resizeHandler();
$(window).resize(Backgrounds.resizeHandler);
$('div.bg img').load(Backgrounds.resizeHandler);
}
Backgrounds.resizeHandler = function()
{
var w = $(window).width();
var h = $(window).height();
$('div.bg img').each
(
function()
{
var wr = w / $(this).width();
var hr = h / $(this).height();
var r = Math.max(wr, hr);
var imgw = Math.round($(this).width() * r);
var imgh = Math.round($(this).height() * r);
$(this).width( imgw );
$(this).height( imgh );
var l = Math.round((w/2) - (imgw/2));
$(this).css('margin-left', l+'px');
}
);
}
As well as the HTML on the page:
<body style="background-image: none; ">
If you dig into their scripts a bit more, you can see what they did. But I guarantee you it's nothing faster than just setting the background-image property.
<img id="foo" src="bar" alt=""> with #foo { width: 100%; height: 100%; }(use position: absolute; / position: relative; & z-index for layering as desired)
Here's an old example.