I want to do an animation assembled from multiple gifs loaded in a web page.
So, I will put a gif on top of another to make that.
In order for that to work the gifs will need to load at the exact same time.
How do I do this in web programming?
My fiddle https://jsfiddle.net/baz3ynt1/9/ is an answer using javascript to do the image loading asynchronously, but then adding them to the DOM at the same time in order to start their animation synchronously. I don't think you can force the browser to finish loading an image at a certain time, as the browser can't know how long it will take to load a resource.
Each Gif gets loaded using
gif = new Image();
gif.src = 'image url';
gif.onload = handleLoading();
and the handleLoading() function triggers a startAnimation() function as soon as all Gifs triggered their onload event:
function handleLoading()
{
// numLoadedGifs is a counter previously initialized as zero
// gifUrls is an array of the urls to load
numLoadedGifs++;
if (numLoadedGifs === gifUrls.length)
{
// now all images are completely loaded
startAnimation();
}
};
Then the startAnimation() function appends the previously created img elements (stored in an array) as children onto a <div id="animation">, but in order to make them run at the same time their src attribute gets reset and set again:
function startAnimation()
{
var animationDiv = document.getElementById('animation');
for (var index in gifList)
{
var img = animationDiv.appendChild(gifList[index]);
img.classList.add('cloth');
img.src = '';
img.src = gifUrls[index];
}
};
I tested it in Firefox and IE 11 (resetting the src is what makes it work in IE 11).
Edit: Apparently IE isn't always fast enough to append the images and then reset their src's in one step, so https://jsfiddle.net/baz3ynt1/10/ splits the two tasks:
function startAnimation()
{
var animationDiv = document.getElementById('animation');
for (var index in gifList)
{
var img = animationDiv.appendChild(gifList[index]);
img.classList.add('cloth');
}
for (var index in gifUrls)
{
gifList[index].src = '';
gifList[index].src = gifUrls[index];
}
};
the gifs will need to load at the exact same time
There is a technique called CSS Spriting.
Instead of loading 4 100x100 pixel GIFs (or PNGs), you load a single 200x200 pixel GIF and then in a series of 100x100 pixel divs, you reposition the background-image, so that it shows only the part of the 200x200 pixel image that you want to display:
.box {
float: left;
width: 100px;
height: 100px;
margin: 6px 12px 6px 0;
background-image: url(http://placehold.it/200x200);
}
.top-left {
background-position: 0 0;
}
.top-right {
background-position: -100px 0;
}
.bottom-left {
background-position: 0 -100px;
}
.bottom-right {
background-position: -100px -100px;
}
.original {
clear: left;
width: 200px;
height: 200px;
}
<div class="box top-left"></div>
<div class="box top-right"></div>
<div class="box bottom-left"></div>
<div class="box bottom-right"></div>
<div class="box original"></div>
Related
I trying to experiment with single page websites. However I have come to a point where I'm stuck.
I use Anchors and :target Pseudo-classes to get a website appearing as normal website. I do this by using div's that are switched to display: block/none as needed.
My cut down code to show the issue:
function showIndex() {
document.getElementById("Index").style.display = "block";
}
function hideIndex() {
document.getElementById("Index").style.display = "none";
}
#nav, #content {
padding: 10px;
margin: 0 0 20px 0;
}
.navButton {
float: left;
width: 50px;
background-color: blue;
padding: 5px;
margin: 0 10px 0 0;
color: white;
}
.contentBox {
float: clear;
width: 400px;
border: 1px solid blue;
padding: 5px;
}
#A, #B, #C {
display: none;
}
#A:target, #B:target, #C:target {
display: block;
}
<div id="nav">
Index</div>
<div class="navButton">Page A</div>
<div class="navButton">Page B</div>
<div class="navButton">Page C</div>
</div>
<div id="content">
<div id="Index" class="contentBox">Here is the Page: Index</div>
<div id="A" class="contentBox">Here is the Page: A</div>
<div id="B" class="contentBox">Here is the Page: B</div>
<div id="C" class="contentBox">Here is the Page: C</div>
</div>
Everything workign fine and as intended as long as the side is opned through index.html. However if I open the side through its anchor / pseudo-url like index.html#A, both divs (Index + A) will be shown instead of just A.
I'm aware why both are shown. If I hide Index by default, the user will get an empty page at start. I cant use .htaccess to redirect to the very same page like Redirect index.html index.html#Index and neither is declaring index.html#Index as startpage an option for different reasons.
Does anyone know a solution to hide Index Div if the page is opened through an anchor url?
One way to do accomplish this is with the hashchange event. Of course, with this, you will also want to remove the show and hide inline event listeners.
window.addEventListener("hashchange", function (e) {
let hash = location.hash.slice(1) || "Index";
document.querySelectorAll(".contentBox").forEach((el) => {
el.style.display = el.id === hash ? "block" : "none";
});
});
Just add that inside script tags. It will run once on load, and then every time the hash changes. If the hash is empty, it will show index. Otherwise, it will try and show whatever element has the id matching whatever the hash is. Only problem with this is that if the target is to "#V" and you don't have a .contentBox with the id of V, it won't show anything. You can work around this easily enough by testing if there are any visible .contentBox after the loop, but I'll leave that for you to figure out.
Edit: I would've thought this would catch page refreshes as well, but in the case that you want to cover every single base, you could do this:
function hideHash(){
let hash = location.hash.slice(1) || "Index";
document.querySelectorAll(".contentBox").forEach((el) => {
el.style.display = el.id === hash ? "block" : "none";
});
}
window.addEventListener('load',function(){
hideHash();
window.addEventListener("hashchange",hideHash);
});
This will add the event listener for the hashChange during the load event, after firing once during the load event. Doing it this way prevents it from accidentally firing twice on page load, which would probably cause some flickering. Note - if you notice flickering on page load, you can wrap the second event listener in a setTimeout function, because hashChange fires after load, and it's theoretically possible that it will still get called during load without introducing a delay.
I am working on front end part of a loading page in an Angular project. I want to show loading with three dots starting from one dot then two and then three to create a sense of loading. But when I add the dots the text of loading, it gets pushed to the left and as dots reduces to one the loading text is moving to the right.
The code is written in angular
Here is the code:
For HTML file:
<div class="textCamel">Loading<span id="loader-loading-dots"></span></div>
For CSS file:
.textCamel {
position:absolute;
width: 100%;
text-align: center;
font-size: 18px;
margin: 0 auto;
}
For type script file
export class LoaderComponent implements OnInit {
ngOnInit() {
// TODO: start CSS animation
this.initLoadingDots();
}
// This method initializes the loading dots animation
initLoadingDots() {
let x=0;
setInterval(function() {
let dots = "";
x++;
for (let y=0; y <= x%3; y++) {
dots+=".";
}
$("#loader-loading-dots").text(dots);
} , 500);
}
}
I really appreciate if anyone can offer some tips to fix this issue.
You can use text-align:left instead and put everything inside a container that you align center and use fixed width to always have the same behavior.
Simply be sure the width you use will contain the maximum text (loading + the 3 dots) to avoid overflow even if it's not a big issue as by default the overflow is shown unless you have another style that hide it :
.textCamel {
/*position:absolute; removed this to show the result of the 3 divs */
width: 100%;
text-align: center;
font-size: 18px;
margin: 0 auto;
}
.load {
display: inline-block;
text-align: left;
width: 80px;
}
<div class="textCamel">
<div class="load">Loading<span id="loader-loading-dots"></span></div>
</div>
<div class="textCamel">
<div class="load">Loading<span id="loader-loading-dots">.</span></div>
</div>
<div class="textCamel">
<div class="load">Loading<span id="loader-loading-dots">..</span></div>
</div>
<div class="textCamel">
<div class="load">Loading<span id="loader-loading-dots">...</span></div>
</div>
based on this thread
I am trying to use images in the HTML from the above link. Fiddle is here
body {
margin: 0;
padding: 0;
}
.main {
background: yellow;
overflow: hidden;
width: 100%;
}
.columns {
background: red;
-webkit-column-fill: auto;
-webkit-column-width: 300px;
-webkit-column-gap: 40px;
-moz-column-fill: auto;
-moz-column-width: 300px;
-moz-column-gap: 40px;
height: 120px;
padding: 0 20px;
width: auto;
overflow-x: auto;
}
.columns img{
height:none;
display: block;
}
.columns > p:last-of-type {
margin-right: 20px;
}
Horizontal scrolling works great, but the image gets divided into columns as well. I didn't know that this is even possible. I like it to stay in one part with the height of the column and auto width not with the column width. So that the columns coming after it gets shifted.
I think I find a possible way to realize what I wanted.
Now it uses a bit JS and Jquery. Here is the fiddle.
Main point is to check page.offsetHeight < page.scrollHeight to see if the textfield has overflow. When it has create a new div.
Here is the JS:
$( document ).ready(function() {
$( ".element2" ).each(function( i,obj ) {
if(this.tagName == "IMG"){
$("#paginatedText").append(obj);
}else{
paginateText(obj);
}
console.log(this.tagName);
});
function paginateText(element) {
//console.log(element);
var text = $(element).html(); // gets the text, which should be displayed later on
//console.log(text);
var textArray = text.split(" "); // makes the text to an array of words
createPage(); // creates the first page
for (var i = 0; i < textArray.length; i++) { // loops through all the words
//$( ".element" ).last().append(textArray[i]);
var success = appendToLastPage(textArray[i]); // tries to fill the word in the last page
if (!success) { // checks if word could not be filled in last page
createPage(); // create new empty page
appendToLastPage(textArray[i]); // fill the word in the new last element
}
}
}
function createPage() {
var page = document.createElement("div"); // creates new html element
page.setAttribute("class", "page"); // appends the class "page" to the element
document.getElementById("paginatedText").appendChild(page); // appends the element to the container for all the pages
}
function appendToLastPage(word) {
var page = document.getElementsByClassName("page")[document.getElementsByClassName("page").length - 1]; // gets the last page
var pageText = page.innerHTML; // gets the text from the last page
page.innerHTML += word + " "; // saves the text of the last page
if (page.offsetHeight < page.scrollHeight) { // checks if the page overflows (more words than space)
page.innerHTML = pageText; //resets the page-text
return false; // returns false because page is full
} else {
return true; // returns true because word was successfully filled in the page
}
}
});
I'm trying to make a normal HTML5 <button> that has an animated radial timer as a background.
My use case will be a button that refreshes a view. You can click it to refresh (thereby also restarting the timer), but the view will automatically refresh once every two minutes. This timer in the background of the button will serve as an indicator of how long it has been since it last refreshed and how long it will be until it automatically refreshes again.
I only need it to work in reasonably recent versions of Chrome, Firefox, and Safari. Don't sweat IE.
I managed to do what I wanted using SVG and a <polygon> that had its points recalculated using requestAnimationFrame, but it didn't work well in Firefox and it caused my MBP's fan to kick on. I'm sure I could do this in a <canvas>, but isn't there some way to do this using only CSS?
I know that the effect may be hard to visualize with my description above, so here are some examples that are close to what I'm trying to achieve.
These two use <canvas>, but you should be able to get the idea. I'm not looking for anything that fancy, though. A solid color is fine.
This one comes very close, but it uses SVG. Even though the animation is achieved with a CSS transition, the SVG is still taxing my CPU.
One final note is that I'm trying to make a background, not an overlay. Text (or in my case a fontawesome glyph) will sit on top of the background.
See if you can do anything with these classes and script.
var myCounter = new Countdown({
seconds: 120, // number of seconds to count down
onUpdateStatus: function (sec) {
}, // callback for each second
onCounterEnd: function () {
} // final action
});
function Countdown(options) {
var timer,
instance = this,
seconds = options.seconds,
updateStatus = options.onUpdateStatus,
counterEnd = options.onCounterEnd;
function decrementCounter() {
updateStatus(seconds);
if (seconds === 0) {
counterEnd();
instance.stop();
}
seconds--;
}
this.start = function () {
clearInterval(timer);
timer = 0;
seconds = options.seconds;
timer = setInterval(decrementCounter, 1000);
};
this.stop = function () {
clearInterval(timer);
};
}
myCounter.start();
.circle {
position: relative;
margin: 7em auto;
width: 16em; height: 16em;
border-radius: 50%;
background: black;
}
.arc {
overflow: hidden;
position: absolute;
top: 0em; right:50%; bottom: 50%; left: 0em;
transform-origin: 100% 100%;
transform: rotate(90deg) skewX(30deg);
}
.arc:before {
box-sizing: border-box;
display: block;
border: solid 8em grey;
width: 200%; height: 200%;
border-radius: 50%;
transform: skewX(-30deg);
content: '';
}
<div class="circle">
<div class="arc"></div>
</div>
I'm trying add a simple text watermark that I want to appear for each page that it will get printed on and look reasonable on Firefox, IE and Chrome.
I've gone through all the related threads that I could find and have applied the suggested answers, but to no avail. Either it appears fine on every page, but doesn't show on the first page (Firefox). Or it only appears on the first page (Chrome). Or doesn't show at all.
I was wondering, is there a standard way to do css watermarks that works for all browsers that I may have missed somehow?
For those curious as to what my html/css looks like at the moment:
<div class="watermark">This is a watermark!</div>
#media print {
.watermark {
display: inline;
position: fixed !important;
opacity: 0.25;
font-size: 3em;
width: 100%;
text-align: center;
z-index: 1000;
top:700x;
right:5px;
}
}
Any help is much appreciated!
Edit: This isn't just for watermarking images, otherwise as suggested I should use an image editor. This is for watermarking pages of document content (sections of text of various sizes).
The real problem is that you need a .watermark at the bottom of each printed page, but CSS has no concept of these printed pages.
The best you could probably do is to use the page-break-after CSS attribute to force a page break at certain points, then you could position your watermark just before that.
Something like (untested):
#media all {
.watermark {
display: none;
background-image: url(...);
float: right;
}
.pagebreak {
display: none;
}
}
#media print {
.watermark {
display: block;
}
.pagebreak {
display: block;
page-break-after: always;
}
}
<body>
some content for page 1...
<div class="watermark"></div>
<div class="pagebreak"></div>
some content for page 2...
<div class="watermark"></div>
<div class="pagebreak"></div>
</body>
Really I think those 2 classes could just be the same element, but this seemed more understandable in code.
The down side here of course is that you need to manually specify where each page break happens, and realistically, if someone prints your webpage on a 4"x6" notecard, its going to be radically different than standard size paper. But still, it's a step in the right direction.
You can't do this in css, simply because it won't work.
Think of this, the user just removes your css, gets your image URLs and copies the images, without the watermark. Right click 'save image url' will also bypass css.
There are two good ways to add watermarks that are fail-safe.
Edit the actual images
If you have control over the images, such as if you are building a photography portfolio, just batch process them in your image editor and add the watermarks before you upload them to the web.
This is a good idea because then your images are ready watermarked regardless of where you use them, so they're social media / promo pack ready etc.
Do it on request
Set up an .htaccess rule that intercepts any image requests and redirects them via some server side code that uses an image processing library to add the watermark and return the binary image data. You can cache a watermarked image with a hash code and check for a watermarked version existing first that will allow you to bypass the processing.
This means that any image request, regardless of whether it comes from css, HTML, or a direct URL will serve a watermarked image. Do use some logic to skip any images used for the decoration of your site, otherwise you'll get watermarked in unexpected places!
The advantage here is that the original image is untouched, if you update your watermark, perhaps as part of a rebranding, you won't need to update all your images.
Another advantage of this approach is that you can apply it to any images, even if you don't create them - for example, if you have users uploading images to your site. Care should be taken with this however, before you watermark, make sure you have the right to watermark the image.
issue reason.
print not support background-image.
This is my solution.
1.Absoluted position for Main elements(need to print div).
2.add element
<style>
.mainContend{
position: absolute;
top: 0;
}
.watermark{
opacity: .8;
}
</style>
<script>
var addWatermark = function () {
var bodHeight = document.body.scrollHeight;
//imge size is 1000*400px
var imgNum = Math.floor(bodHeight/400) ;
var template = '<img src="../img/icon/watermark.png" class="watermark">';
var innerHTML;
//create image number
for(var i = 0;i < imgNum;i++){
innerHTML +=template;
}
// innerHTML.appendTo("#reportContent);
$("#reportContent").append(innerHTML);
}
window.onload = addWatermark;
</script>
<div id="reportContent">
<div class="mainContend" id="mainContend">
content reportContentreportContentreportContent
</div>
</div>
Here is how I successfully managed to use watermark on every page in print preview
HTML:
<!-- place this only once in page -->
<div style="opacity: .5; filter: alpha(opacity=50);" class="watermark"></div>
<!-- place this in your table thead -->
<div style="opacity: .5; filter: alpha(opacity=50);" class="watermark_print"></div>
CSS:
div.watermark_print{
display: none;
width: 100%;
height: 100%;
background: url("{{{watermark}}}") no-repeat;
background-position: center;
z-index: 99999999;
border: none !important;
background-size: 400px !important;
}
div.watermark {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: url("{{{watermark}}}") no-repeat;
background-position: center;
z-index: 99999999;
border: none !important;
background-size: 400px !important;
}
table {
width: 100%;
table-layout: fixed;
border-spacing: 0;
}
#media print {
div.watermark {
display: none;
}
div.watermark_print {
display: block;
position: fixed;
inset: 0;
}
}
That should do the trick, we have two watermark, one in HTML page review and another hidden in normal view but in print preview, we show it and because we are repeating table header in every page so we have this watermark on every page.