Creating in img file (bmp,jpg,png) from html elements - javascript

I have a page that includes a number of canvas elements each with its own shape (rec,line etc...) and also css3 properties (rotate,deg,transform etc...).
i need to take that html element or page and render it as an image file including all the child elements and their styling.
html2canvas.js has a lot of problems rendering css3 properties so that option is off the table.
and the elements i want to convert to an image are an array of html elements (div,canvas,p,video etc...) so a screenshot of a canvas element want do.
is there a solution for this problem???
i must convert it to an img i dont have any other alternative !!!

You can use PhantomJS for this.
Here is an example in node:
var page = require('webpage').create();
page.open('http://example.org/', function() {
var clipRect = page.evaluate(function () {
return document.getElementById('myID').getBoundingClientRect();
});
page.clipRect = {
top: clipRect.top,
left: clipRect.left,
width: clipRect.width,
height: clipRect.height
};
page.render('myCapture.png');
phantom.exit();
});
This will go to example.org and take a screenshot of everything inside #myID

Related

How to prevent a background image flickering on change

I'm applying a repeated background image from a canvas to a div via javascript like this:
var img_canvas = document.createElement('canvas');
img_canvas.width = 16;
img_canvas.height = 16;
img_canvas.getContext('2d').drawImage(canvas, 0, 0, 16, 16);
var img = img_canvas.toDataURL("image/png");
document.querySelector('#div').style.backgroundImage = 'url(' + img + ')';
I have to update it quite frequently. The problem is it flickers upon change, it doesn't appear to happen in Chrome but it's really bad in Firefox and Safari. Is it possible to stop this? I didn't think it would happen since it's a dataurl and therefore doesn't need to be downloaded.
Solution:
// create a new Image object
var img_tag = new Image();
// when preload is complete, apply the image to the div
img_tag.onload = function() {
document.querySelector('#div').style.backgroundImage = 'url(' + img + ')';
}
// setting 'src' actually starts the preload
img_tag.src = img;
Try to preload the image resource to the device storage by including the image in DOM like in the following HTML-Code. Maybe the error comes up because the image resource need to be loaded which takes some time (flickering).
<img src="imageToPreload.png" style="display:none;" alt="" />
You may prefer to use sprites-images. By using sprites your application will need less HTTP-Requests to load all ressources into your page. Also add the following CSS styles if you are using css animations. It will prevent background flickering on mobile devices:
-webkit-backface-visibility: hidden;
-moz-backface-visibility: hidden;
-ms-backface-visibility: hidden;
Preload your image like this, no need to include a <img> with display: none
<link rel="preload" href="/images/bg-min.png" as="image">
Try adding this css to your background element:
-webkit-backface-visibility: hidden;
-moz-backface-visibility: hidden;
-ms-backface-visibility: hidden;
It should help with flickering..
You can also "force" hardware acceleration by adding this to your background element:
-webkit-transform: translate3d(0, 0, 0);
Another option is to use image instead of DIV and change only the image url.
I struggled with this for a bit, tried preloading, appending the image to the document, etc.
In the end, I resaved the JPEG without the "Progressive" option.
That fixed the rolling flicker when the img src was swapped.
In my case changing height: 1080px; (background height) to height: fit-content;
I think that preloading all the images is essential in any case. What I found is that the way the browsers behave while changing the background image dynamically is different from one another. In Firefox for example it flickers when the change is frequent however in Chrome and Safari it doesn't.
The best solution I came up with so far is drawing the image inside a child canvas that fills the space of the whole parent div.
In all cases, the images you are using must be optimized as it affects the rendering performance.
My javascript code that works now, looks like this
const pic = new Image();
const pic2 = new Image();
pic.src="../images/settings_referrals_anim.gif";
pic2.src="../images/settings_referrals_still.png";
I don't actually reference that code in the query, for example, i use
document.querySelector(".button_Settings_referrals").addEventListener("mouseover", function() {
myDiv.style.backgroundImage = "url('../images/settings_referrals_anim.gif')";
But it seems to work. If I replace the long URL with const pic for example it doesn't work, and if I include the image object declaration and location at first time in the assignment, then the flickering stops.
This does not address all of the specifics noted by the OP, but might be useful for others. Tested in Chrome 97, Firefox 96, Android 11, iOS 15.
I have a div that includes these CSS parameters...
#div_image {
background-image: url( [Path to low-res image] );
background-size: cover;
}
I have a corresponding class that looks like this...
.div_image_highres {
background-image: none !important;
}
The corresponding class has a pseudo-element defined as follows:
.div_image_highres::before {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
content: " ";
background-image: url( [Path to highres image] );
background-repeat: no-repeat;
background-position: 50% 0;
background-size: cover;
opacity: 1;
display: block;
}
I have an img element that also points to the high-res image...
<img id="img_highres_preload" src=" [Path to high-res image ] ">
The img element has a corresponding style which allows the image to be displayed (ensuring that image file loads) but not seen...
#img_highres_preload {
width: 1px;
height: 1px;
}
Two notes: (1) I realize a lot of people use other methods of pre-loading (e.g., programmatically), but I have a personal preference for this method. (2) See the addendum about the reliability of the load event.
Last but not least, I have some Javascript (jQuery) that adds the "high-res" class to "div_image" once the high-res file is loaded...
$(document).ready(function() {
$("#img_highres_preload").off().on("load", function() {
$("#div_image").addClass("div_image_highres");
});
});
This could easily be vanilla JS, but since I use jQuery throughout my code, I like having a consistency.
Here's a summary of what's happening...
Presumably, the low-res image is loaded first and becomes the background image for the div. Even if that does not occur, everything will work as intended (i.e., the high-res image will be displayed).
When the high-res image loads into the img element (i.e., Javascript confirms that the high-res file is loaded), the "div_image_highres" class is applied to "div_image".
As result, the div switches to the high-res image without flashing. In my experience, if anything, it shifts a little to the left; but that often doesn't occur and, if it does, it's not inelegant.
And here's the primary reason I use this approach when required: In my application, there are multiple panels the user can navigate, which results in one panel sliding out of view and the new one into view. If I don't use a pseudo-element (as described above) for displaying a high-res image, the image flickers when its div is hidden and re-displayed. With the above-described technique, I can slide the div in and out of view without any flickering.
Regarding the Load Event
You can't depend on the load event firing. For instance, it typically does not fire when the browser has cached an image. So to make a long post even longer, here's the enhancement I have in my code to accommodate that reality...
I modify the document.ready event (shown above) to look like this:
$(document).ready(function() {
positionOnPage(true);
$("#img_highres_preload").off().on("load", function() {
checkImage();
});
});
checkImage = function() {
var image = $("#img_highres_preload")[0];
if (!image.complete || (typeof image.naturalWidth != "undefined" && image.naturalWidth == 0)) {
console.log("Waiting for high-res image.");
}
else if (!$("#div_home").hasClass("div_home_highres")) {
$("#div_home").addClass("div_home_highres");
$("#img_highres_preload").remove();
}
}
The checkImage function examines the image element to see whether an image has in fact been loaded. In this code example, it is a little redundant — that is, the img element has confirmed the load, so there's usually no need to check it (unless there is some reason to believe the file is being misloaded).
I might do it as shown because I also call checkImage from other places in my code, so if I have more of a programmatic response (unlike the simple version shown), I want all of that code in the same place and written just once. The checkImage function might be called when triggered by a timer or when the section displaying the intended image is about to be displayed. Perhaps something like this...
if (sectionName == "[whatever]" && $("#img_highres_preload").length === 1) {
checkImage();
}
In this example, I look for the presence of the preload img element because I know that my previous function removes the element after it has fulfilled its purpose.
This post has a stripped-down version to illustrate the concept. As written above, it only accommodates a single known img element, so the code could be extended to call checkImage with some parameters (e.g., the name of an image or the element itself) and checkImage could look for the existence of the preload element, so that check occurs in one place. It can be fairly fancy, so I went with the simplest example for this post.
In many cases, this stripped-down version is all I need because typically I only use a high-res photo for a window background image. I either start with the display of a low-res image and switch it out as soon as the high-res file is loaded, or I have some animation that gets triggered after I confirm the presence of the high-res image.
A good case for a more generalized version is when I need a series of images loaded at the outset and don't want to start until all of them are ready. In those cases, the web page might begin with some welcome text that stays displayed until all images have been confirmed.
Hey Guys I know this has been an older question but if you are still flickering after all this you can simply put the final version behind you background div. That flicker is seeing behind the image you currently have so if its the final image it will be smooth.

Layout difference in SVG when added dynamically

I basically wanted to add an SVG element under a div once the div is added to the page(by firing a custom event using jQuery trigger). When I tried to do this like below:
css:
.full-size {
width: 100%;
height: 100%;
}
js:
var div = $("<div/>").css({'width': '100px', 'height': '100px'});
div.on(<customEvent>, function() {
var svg = $("<svg/>").addClass("full-size");
svg.appendTo(div);
});
the SVG size remains 0px x 0px. But when I add the SVG through d3(shown below) it gets the entire div's width and height.
js:
var div = $("<div/>").attr("id", "div").css({'width': '100px', 'height': '100px'});
div.on(<customEvent>, function() {
var svg = d3.select("#div").append("svg:svg").attr("class", "full-size");
});
Could someone throw some light on why this happens?
The problem is that JQuery isn't properly recognizing the svg element as an svg element. Instead, it gets added as an "HTMLUnknownElement", which will basically default to a "span".
Test case: http://fiddle.jshell.net/9jt2n/
Check the svg properties in the DOM inspector.
A quick google suggests that JQuery doesn't have any native way of telling it to create an element as something other than HTML, but as this article nicely explains, you can create the element with plain Javascript, then use JQuery for the rest.
i.e., use code like:
var svg = $(document.createElementNS('http://www.w3.org/2000/svg', "svg"));
svg.attr({"class":"full-size"});
svg.appendTo(div);
Updated example: http://fiddle.jshell.net/9jt2n/2/
In contrast, d3 methods already know all the svg element names, and automatically add them within the appropriate namespace.

How to get zoom working with turn.js

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.

Add Transparent Image on top of other Images with JavaScript

I need to add a Transparent image on top of all images on a page. The goal is if a user were to do a simple right click and save of an image, they would save the transparent image.
I do realize this is not a guaranteed method and that none exist to prevent image theft but simply a measure that a client wants added to prevent your average non tech person from saving images.
Using JavaScript I would like to find all images or all images within a certain Div.
Apply a new image overlay on top of these images that will have the same width and height of the image they are covering
I am not sure how to do this with JavaScript and was hoping someone would have a quick fix or example. I was unable to find anything so far on Google or SO. Appreciate any help
I have this JS which gets all images on a page so far...
// Get all images on a Page
function checkimages() {
var images = document.images;
for (var i=0; i<images.length; i++){
var img =images[i].src;
// Add new transparent image on top of this image
alert(img);
}
}
I would advise you to work with jQuery (or similar library) to keep things easier. I would even write a small jquery extension to make it easy to recycle the code, and apply it on any div (or other wrapper), wich child images you want to be overlayed.
My code would look something like this:
// jquery plugin to create overlays
// src is the url of the overlay image
// apply to any container that contains images to be overlayed
$.fn.overlayImages = function(src) {
// loop trough the images
$(this).find('img').each(function() {
// cache some variables
var $img = $(this);
var $parent = $img.parent();
// make the parent relative, if not yet absolute or fixed, for easy positioning
if ($parent.css('position') !== 'fixed' && $parent.css('position') !== 'absolute') {
$parent.css('position', 'relative');
}
// get the position of the image
var position = $img.position();
// clone the image
var $overlay = $img.clone();
// set the styling, based on the img, for exact positioning
$overlay.css({
top: position.top,
left: position.left,
position: 'absolute',
width: $img.width(),
height: $img.height()
});
// change the src attribute for the overlay
$overlay.attr('src', src);
// insert the overlay to the DOM
$overlay.insertAfter($img);
});
}
// when the DOM is loaded (not just ready, the images need to be there to copy their position and size)
$(window).load(function() {
// apply the overlay plugin to the wrapper of the images
$('#replace-images').overlayImages("http://www.riptideinnovations.com/images/watermark.png");
});
I added the step by step explanation inside the code as comments, but do feel free to ask if you want any further explanation.
I set up a small fiddle to demonstrate: http://jsfiddle.net/pP96f/6/
I don't know if this would help, but you could make your images all div's with backgrounds like this:
<div style="background-image: url('<your_image>');"></div>

Flot graph does not render when parent container is hidden

I was having an issue where a flot graph would not render in a tabbed interface because the placeholder divs were children of divs with 'display: none'. The axes would be displayed, but no graph content.
I wrote the javascript function below as a wrapper for the plot function in order to solve this issue. It might be useful for others doing something similar.
function safePlot(placeholderDiv, data, options){
// Move the graph place holder to the hidden loader
// div to render
var parentContainer = placeholderDiv.parent();
$('#graphLoaderDiv').append(placeholderDiv);
// Render the graph
$.plot(placeholderDiv, data, options);
// Move the graph back to it's original parent
// container
parentContainer.append(placeholderDiv);
}
Here is the CSS for the graph loader div which can be placed
anywhere on the page.
#graphLoaderDiv{
visibility: hidden;
position: absolute;
top: 0px;
left: 0px;
width: 500px;
height: 150px;
}
Perhaps this is better solution. It can be used as a drop in replacement for $.plot():
var fplot = function(e,data,options){
var jqParent, jqHidden;
if (e.offsetWidth <=0 || e.offetHeight <=0){
// lets attempt to compensate for an ancestor with display:none
jqParent = $(e).parent();
jqHidden = $("<div style='visibility:hidden'></div>");
$('body').append(jqHidden);
jqHidden.append(e);
}
var plot=$.plot(e,data,options);
// if we moved it above, lets put it back
if (jqParent){
jqParent.append(e);
jqHidden.remove();
}
return plot;
};
Then just take your call to $.plot() and change it to fplot()
The only thing that works without any CSS trick is to load the plot 1 second after like this:
$('#myTab a[href="#tabname"]').on("click", function() {
setTimeout(function() {
$.plot($(divChartArea), data, options);
}, 1000);
});
or for older jquery
$('#myTab a[href="#tabname"]').click (function() {
setTimeout(function() {
$.plot($(divChartArea), data, options);
}, 1000);
});
The above example is applied to Bootstrap tags for Click funtion. But should work for any hidden div or object.
Working example: http://topg.org/server-desteria-factions-levels-classes-tokens-id388539
Just click the "Players" tab and you'll see the above example in action.
This one is a FAQ:
Your #graphLoaderDiv must have a width and height, and unfortunately, invisible divs do not have them. Instead, make it visible, but set its left to -10000px. Then once you are ready to show it, just set it's left to 0px (or whatever).
OK, I understand better now what you're actually saying... I still think your answer is too complicated though. I just tried this out using a tabbed interface where the graph is in a hidden tab when it's loaded. It seems to work fine for me.
http://jsfiddle.net/ryleyb/dB8UZ/
I didn't have the visibility:hidden bit in there, but it didn't seem necessary...
You could also have visibility:hidden set and then change the tabs code to something like this:
$('#tabs').tabs({
show: function(e,ui){
if (ui.index != 2) { return; }
$('#graphLoaderDiv').css('visibility','visible');
}
});
But given the information provided, none of that seems particularly necessary.
I know this is a bit old but you can also try using the Resize plugin for Flot.
http://benalman.com/projects/jquery-resize-plugin/
It is not perfect because you'll sometimes get a flash of the non-sized graph which may be shrunk. Also some formatting and positioning may be off depending on the type of graph that you are using.

Categories

Resources