Opacity effect works from 1.0 to 0, but not 0 to 1.0 - opacity

I wanted to increase the opacity of a div from 0 to 1.0 on the click of a button. I can decrease opacity from 1.0 to 0.0, but it does not work from 0.0 to 1.0. I also tried using parseInt(element.style.opacity) and parseFloat(element.style.opacity), but none of those work either.
Here's the faulty JavaScript:
function myF(){
var x = document.getElementById("test").style;
x.opacity = parseFloat(x.opacity) + 0.1;
setTimeout(myF(),10);
}
And here's the faulty HTML:
<button onclick="myF()">Click to change opacity</button>
<div style="height:200px; width:200px; background-color:#656b67; opacity:0;" id="test"> </div>
(The following is the javascript and HTML that works for decreasing the opacity)
<body>
<script>
function myF(){
var x = document.getElementById("test").style;
x.opacity = x.opacity - 0.1;
setTimeout(function(){myF();},10);
}
</script>
<button onclick="myF()">Click to resize</button>
<div style="height:200px; width:200px; background-color:#656b67; opacity:1.0;" id="test"></div>
</body>

Change
setTimeout(myF(),10);
to
setTimeout(myF, 10);
You don't want to call the function immediately, you want to pass it to setTimeout.
Also, you have a never-ending loop. The function is called recursively, and there is no end condition. When invoking it immidiately, this will cause your browser to freeze.

function myF(){
var transparent_div = document.getElementById("test");
var opacity = parseFloat(transparent_div.style.opacity);
if (isNaN(opacity)) opacity = 0.1;
else opacity += 0.1;
transparent_div.style.opacity = opacity;
if (opacity < 1.0) setTimeout(function(){myF();},100);
}
If the opacity is set to "" an empty string, you will not be parsing a number, and as such Javascript will return that as a NaN object, which you can test for using isNaN(). I think that is one of your main issues; parseFloat() was the correct thing to use, you just need to check for your return value accordingly.

Related

setTimeout vs requestAnimationFrame

I made an example of 'setTimeout vs requestAnimationFrame' to find out how different they are.
As you can see, the orange box arrives to the destination first. The green box jump some times and slower.
I understand why the green box jump some times. Because the task(calling move function) would not be inserted in macroTaskQueue before repaint some times(this is called jank or frame skip).
This is why I prefer requestAnimationFrame than setTimeout when animate element. Because the move() of requestAnimationFrame(move) is guaranteed to be called right before repaint.
Now, what I'm wondering is that why the green box is slower than orange box
Maybe does it mean that the move() is not called at each 1000/60 ms?
setTimeout is always late.
The way it works is
Register a timestamp when to execute our task.
At each Event loop's iteration, check if now is after that timestamp.
Execute the task.
By this very design, setTimeout() is forced to take at least the amount of time defined by delay. It can (and will often) be more, for instance if the event loop is busy doing something else (like handling user gestures, calling the Garbage Collector, etc.).
Now since you are requesting a new timeout only from when the previous callback got called, your setTimeout() loop suffers from time-drift. Every iteration it will accumulate this drift and will never be able to recover from it, getting away from the wall-clock time.
requestAnimationFrame (rAF) on the other hand doesn't suffer from such a drift. Indeed, the monitor's V-Sync signal is what tells when the event loop must enter the "update the rendering" steps. This signal is not bound to the CPU activity and will work as a stable clock. If at one frame rAF callbacks were late by a few ms, the next frame will just have less time in between, but the flag will be set at regular intervals with no drift.
You can verify this by scheduling all your timers ahead of time, your setTimeout box won't suffer from this drift anymore:
const startBtn = document.querySelector('#a');
const jankBtn = document.querySelector('#b');
const settimeoutBox = document.querySelector('.settimeout-box');
const requestAnimationFrameBox = document.querySelector('.request-animation-frame-box');
settimeoutBox._left = requestAnimationFrameBox._left = 0;
let i = 0;
startBtn.addEventListener('click', () => {
startBtn.classList.add('loading');
startBtn.classList.add('disabled');
scheduleAllTimeouts(settimeoutBox);
moveWithRequestAnimationFrame(requestAnimationFrameBox);
});
function reset() {
setTimeout(() => {
startBtn.classList.remove('loading');
startBtn.classList.remove('disabled');
i = 0;
settimeoutBox.style.left = '0px';
requestAnimationFrameBox.style.left = '0px';
settimeoutBox._left = requestAnimationFrameBox._left = 0;
}, 300);
}
function move(el) {
el._left += 2;
el.style.left = el._left + 'px';
if (el._left > 1000) {
return false;
}
return true;
}
function scheduleAllTimeouts(el) {
for (let i = 0; i < 500; i++) {
setTimeout(() => move(el), i * 1000 / 60);
}
}
function moveWithRequestAnimationFrame(el) {
if (move(el)) {
requestAnimationFrame(() => {
moveWithRequestAnimationFrame(el);
});
} else reset();
}
.grid {
margin: 30px !important;
padding: 30px;
}
.box {
width: 200px;
height: 200px;
display: flex;
align-items: center;
justify-content: center;
position: relative;
color: white;
font-size: 18px;
}
.settimeout-box {
background-color: green;
}
.request-animation-frame-box {
background-color: orange;
}
<div class="ui grid container">
<div class="row">
<button class="ui button huge blue" id="a">Start!</button>
</div>
<div class="row">
<div class="box settimeout-box">
<span>setTimeout</span>
</div>
</div>
<div class="row">
<div class="box request-animation-frame-box">
<span>requestAnimationFrame</span>
</div>
</div>
</div>
Note that Firefox and Chrome actually do trigger the painting frame right after the first call to rAF in a non-animated document, so rAF may be one frame earlier than setTimeout in this demo.
requestAnimationFrame's frequency is relative to the monitor's refresh-rate.
Above example assumes that you run it on a 60Hz monitor. Monitors with higher or lower refresh rate will enter this "update the rendering" step at different frequencies.
Also beware, delay in setTimeout(fn, delay) is a long, this means the value you pass will be floored to integer.
An a last note, Chrome does self correct this time drift in its setInteval() implementation, Firefox and the specs still don't, but it's under (not so active) discussion.

web audio soundcloud crossfade

I'm struggling to get this basic fade-in / fade-out Web Audio code to work with SoundCloud. It appears that the gainNode.gain.linearRampToValueAtTime functions are bypassed (ie, play starts and ends at gain.volume = 1.0.)
Code needs to work with iOS mobile Safari webkit.
CSS included:
<link href='http://fonts.googleapis.com/css?family=Open+Sans:400,600' rel='stylesheet' type='text/css'>
HTML Follows:
<div id="wrapper">
<div id="content">
<div class="post">
<h2>Fading in a Soundcloud Track</h2>
</p>
</div>
</div>
</div>
JS Follows:
<script>
var audioCtx = new (window.AudioContext ||
window.webAudioContext ||
window.webkitAudioContext)();
var audio = new Audio();
var url = 'https://api.soundcloud.com/tracks/179612876/stream' + '?client_id=<MY_ID>';
audio.src = url;
audio.preload = true;
audio.load();
audio.addEventListener('canplay', function(){
var currTime = audioCtx.currentTime;
var duration = 30;
var fadeTime = 6;
var gainNode = audioCtx.createGain();
gainNode.gain.value = 0.0;
var source = audioCtx.createMediaElementSource(audio);
source.connect(gainNode);
gainNode.connect(audioCtx.destination);
// Then fade in
gainNode.gain.linearRampToValueAtTime(0.0, currTime);
gainNode.gain.linearRampToValueAtTime(1.0, currTime + fadeTime);
// Then fade it out.
gainNode.gain.linearRampToValueAtTime(1.0, currTime + duration-fadeTime);
gainNode.gain.linearRampToValueAtTime(0.0, currTime + duration);
//source.connect(audioCtx.destination);
source.mediaElement.play();
},false);
</script>
"gainNode.gain.value = 0.0;" doesn't actually set a schedule point in the scheduler, it just sets the current value. Since there's no start point in the scheduler, it's jumping up when it hits the first schedule point (i.e. at time currTime + fadeTime). Try this:
gainNode.gain.setValueAtTime(0.0, currTime);
gainNode.gain.linearRampToValueAtTime(1.0, currTime + fadeTime);
// Then fade it out.
gainNode.gain.setValueAtTime(1.0, currTime + duration-fadeTime);
gainNode.gain.linearRampToValueAtTime(0.0, currTime + duration);
(and don't bother setting gain.gain.value).

Mobile Page Slider content with dynamic height

I am trying to implement the app that have 4 pages in 4 table. It supposed to be support swipe gesture, and each page contains dynamic data and make the pages have different height.
I tried to use responsive-slider-div-span.source example and integrate the 4 table into the slides.
I would like to set the width and height for the slides dynamically while the document ready, However, The slide will not show if the width and height is not pre set in the the slide div.
May I know any suggestion?
Typically, the size of jssor slider is defined in html code, and you can alter the size grammatically.
Given a slider at size 600x300, you can use javascript to change size before initialization of jssor slider.
<script>
jQuery(document).ready(function ($) {
var options = {};
//retrieve height of the slider, assuming the height should be 200px;
$("#slider1_container").height("200px");
$("#slider1_slides").height("200px");
var jssor_slider1 = new $JssorSlider$("slider1_container", options);
//According to your comment, please add following code
//Handle $EVT_PARK event BEGIN
function OnSliderPark(slideIndex, fromIndex) {
if (slideIndex == 0 || slideIndex == jssor_slider1.$SlidesCount() - 1) {
//do something scroll page to top
}
}
jssor_slider1.$On($JssorSlider$.$EVT_PARK, OnSliderPark);
//Handle $EVT_PARK event END
});
</script>
<div id="slider1_container" style="... width: 600px; height: 300px; ...">
<div u="slides" id="slider1_slides" style="... width: 600px; height: 300px; ...">
...
</div>
</div>

D3 filtering data points

I'm implementing the classic mercator example (https://github.com/mbostock/d3/blob/master/examples/mercator/mercator.html), which I've changed to zoom into Afghanistan and to use only one custom slider. I'm reading in GeoJSON data of places where explosions have happened and the graph maps them all at load. I want to use the slider to view only a month of explosion points at a time but am having trouble filtering the results. I've tried several things based on posts in the Google group but fail to understand how to filter the data read in previously from 'explosions.json'. Thanks for the help!
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<title>IED Attacks in Afghanistan (2004-2009)</title>
<script type="text/javascript" src="../d3.v2.js"></script>
<script type="text/javascript" src="../lib/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../lib/jquery-ui/jquery-ui.min.js"></script>
<style type="text/css">
#import url("../lib/jquery-ui/jquery-ui.css");
body, .ui-widget {
font: 14px Helvetica Neue;
}
svg {
width: 960px;
height: 600px;
border: solid 1px #ccc;
background: #eee;
}
line {
stroke: brown;
stroke-dasharray: 4,2;
}
path {
fill: #ccc;
stroke: #fff;
}
div {
width: 960px;
}
</style>
</head>
<body>
<h3>IED Attacks in Afghanistan (2004-2009)</h3>
<script type="text/javascript">
// Create the Mercator Projection (Map)
var xy = d3.geo.mercator(),
path = d3.geo.path().projection(xy);
// Create the states variable
var states = d3.select("body")
.append("svg")
.append("g")
.attr("id", "states");
// Create the equator variable
var equator = d3.select("svg")
.append("line")
.attr("x1", "0%")
.attr("x2", "100%");
// Create the explosions variable
var explosions = d3.select("svg")
.append("g")
.attr("id","explosions");
// Load in the states & equator data from the file 'world-countries.json'
d3.json("world-countries.json", function(collection) {
states
.selectAll("path")
.data(collection.features)
.enter().append("path")
.attr("d", path)
.append("title")
.text(function(d) { return d.properties.name; });
equator
.attr("y1", xy([0, 0])[1])
.attr("y2", xy([0, 0])[1]);
});
// the variable that holds our translate, center on Afghanistan
var translate = xy.translate(); //create translation to center gride in different area
translate[0] = -1741;
translate[1] = 1487;
xy.translate(translate); // center
xy.scale(12000); //zoom in
// Load in the explosions data from the file 'explosions.json'
d3.json("explosions.json", function(collection) {
explosions
.selectAll("path") //make a path and attach data
.data(collection.features)
.enter().append("path")
.attr("d", path)
.style("stroke","red") //color the path points
.style("stroke-width",2) //size of point stroke
.attr("class","explosionpoint")
.append("title") //title is the 'name' field in the json file
.text(function(d) { return d.properties.name; });
});
</script>
<p></p>
<!-- Slider -->
<div id="scale"></div><p></p>
<script type="text/javascript">
$("#scale").slider({
min: 20040101, //min : 1/1/04
max: 20100101, //max: 1/1/10
value: 20060601, //default slider value
step: 100, // step is the allow increments the slider can move. 100 = one month
slide: function(event, ui) {
/* REMOVE ALL EXPLOSION PATHS EXCEPT FOR A PARTICULAR MONTH OR RELOAD WITH FILTERED RESULTS */
}
});
</script>
You'll need to post part or all of your explosions.json object for a concrete answer. However, something like this will filter a JSON if it's structured like {explosion1:{data1:true, data2:true}, explosion2:{data1:true, data2:false}}:
function filterJSON(json, key, value) {
var result = {};
for (var explosionIndex in json) {
if (json[explosionIndex][key] === value) {
result[explosionIndex] = json[explosionIndex];
}
}
return result;
}
(e.g. filterJSON(myjson, "data1", true) will give all explosions with data1:true)
This is not specific to d3.
Then you could use something like this for the d3-side of things:
explosions.data(myFilteredData).exit().remove(); // remove ones you don't want
explosions.enter().append("path")... // add back ones you do want
If I understand your application, it would actually be better to just toggle the visiblity attribute of the SVG elements.
var sliderrange = [20040101, 20040201]; //replace with code based on your slider
explosions.selectAll(".explosionpoint").attr("visibility", function(d) {
//Replace with the correct date comparison logic
return d.date < sliderrange[1] && d.date > sliderrange[0] ? "visible" : "hidden";
});
D3 does have a very natural way of doing this. I'll assume your data looks something like this:
[{name: explosion1name, day: 20040110,...}, {name: explosion2name, day: 20040111,...}]
...and that you've got some variable, we'll call it explosionsData, to reference the data.
You can then draw your explosions with a function that takes the values from your slider. See the .filter I've added below.
function drawExplosions(startDay, endDay) {
explosions.selectAll("path") //make a path and attach data
.data(collection.features)
.enter().append("path")
.filter( function (d) { return ( (d.day > startDay) && (d.day < endDay) )})
.attr("d", path)
.style("stroke","red") //color the path points
.style("stroke-width",2) //size of point stroke
.attr("class","explosionpoint")
.append("title") //title is the 'name' field in the json file
.text(function(d) { return d.properties.name; });
Just call this function whenever your slider values changes.

iPhone Unlock Slider With Mootools?

I try to make a slider similar to the iPhone unlock Slider, that forwards to a linked site, when complete, and returns to its initial position when the slider wasn't dragged to the end.
This is not meant to be a iPhone webapp, i just want to put this to a general website as a effect.
So far I've tried those two tests, but i'm stuck on both.
The first is:
// First Example
var el = $('slideOne'),
// Create the new slider instance
var sliderOne = new Slider(el, el.getElement('.slider'), {
steps: 20, // There are 35 steps
range: [8], // Minimum value is 8
}).set(20);
Problem here is that i can't fire an event on (0) not on (20) aswell, i tried onComplete but this fires the function immediatly after the page is load!?
The second
$$('.textslider').setStyle('opacity', 0.8);
$('slider1').makeDraggable({
snap: 0,
container: 'slideOne',
droppables: '.slidedrop1',
onDrop: function(element, droppable, event){
if (!droppable);
else console.log(element, 'dropped on', droppable, location = 'index.php/kredite.html', event);
},
});
Problem here is , that the droppable don't work as fine as i hoped, sometimes i move the the slider on the invisible droppable, which indicates if the slider is dragged to the end, and nothing happens, sometimes it works fine, i think this may be due the different position of the cursor on the slider. and i can't get it done that it is only possible to slide horizontal , since it is that drag not the slider function, so i think this won be the proper way.
On both Tests, i didn't figured out who i could return the slider back to its initial position, with a slide Effect.
Are there some mootools cracks around who maybe could help me with this? Thanks already for the great ideas of y'all.
<html>
<head>
<script type="text/javascript"
src="http://demos.mootools.net/demos/mootools.js"></script>
<script type="text/javascript">
window.addEvent('domready', function(){
var el = $('slideOne');
var debug = $('debug');
var ACTIVATE_VALUE = 20;
var mySlider = new Slider(el, el.getElement('.knob'), {
range: [0], // Minimum value
steps: ACTIVATE_VALUE, // Number of steps
onChange: function(value){
if (value == ACTIVATE_VALUE) {
debug.setStyles({color:'green'});
// go to url after delay
(function(){
location.href='http://joecrawford.com/';
}).delay(500);
} else {
debug.setStyles({color:'red'});
// if not activated, reset after 2 second delay
(function(){
value = 0;
mySlider.set(value);
}).delay(3000);
}
debug.set('text', value);
}
});
mySlider.set(0);
});
</script>
<style type="text/css">
div.slider {
width: 200px;
height: 50px;
background: #eee;
}
div.slider div.knob {
background: #000;
width: 50px;
height: 50px;
}
div#debug {
font-family: sans-serif;
font-size: xx-large;
}
</style>
<title>Slider that resets if it does not reach the end</title>
</head>
<body>
<div id="slideOne" class="slider">
<div class="knob"></div>
</div>
<div id="debug">-</div>
</body>
</html>