How to stop a Velocity animation using "promise-style" - velocity.js

I'm using Velocity with promise (Without jQuery...):
var Velocity = require('velocity-animate');
var animation = Velocity(document.getElementById('some-id'), { opacity: 0 });
How can I arbitrary stop this animation since animation returns a promise ?

You can stop any running animation on a dom element using utility function, all you need to do is pass dom element as first parameter and "stop" as second parameter, Velocity(document.getElementById('some-id'),"stop").
See this working example
var a = Velocity(document.getElementById('rect'),{opacity:0},3000);
setTimeout(function(){
Velocity(document.getElementById('rect'),"stop");
},1000);
#rect{
background-color:green;
height:100px;
width:100px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>
<div id="rect">
</div>
As you can see promise a is not used to stop animation.

Related

Touch events are wrong for transformed SVG elements

In the process of experimenting with scaling/panning an inline SVG image by applying a matrix transform I have discovered a rather peculiar thing. After loading the image I am attaching a touchstart event listener to some of the elements in the SVG image and the event fires right away when the object is touched. However, after applying a transform
document.getElementById('mysvg').setAttribute('transform''matrix(a b c d e)')
which has the effect of scaling and/or translating the entire SVG image touching the same object no longer triggered the expected touch event. After some experiment I found that the event could still be triggered by the touch location on screen had no bearing to the actual new placement of the object on the screen. I then proceeded to first removeEventListener followed by addEventListener for the object after issuing the matrix transform and lo & behold the touch event handling was back to normal.
Quite apart from the fact that I would like to avoid the rather expensive operations of removing & then reassigning the same event listener after each pan/zoom I would like to understand just why this is happening. It is like the browser is locating the pixel location of the object at the addEventListener stage and then holds on to that somewhere in its memory blissfully ignorant of any object displacements that might have occurred later.
Can anyone here tell me what is going on here and how I can go about retaining the utility of the touch event after pan & zoom in a more efficient manner?
I've set up a similar issue:
There is a <circle> element, with a transform attribute inside an <svg>.
The 'touchstart' event fires only at the first tap on the <circle>. After that it doesn't trigger the 'touchstart' event anymore.
I have found a strange workaround: Add a 'touchstart' eventListener to the <svg> element with a noop handler:
document.querySelector('svg').addEventListener('touchstart', () => {});
After this the <circle> triggers the 'touchstart' events perfectly.
You can test it with the folllowing snipet:
let debugLines = [];
let lines = 0;
function writeDebug(...t) {
let d = document.getElementById('debug');
debugLines.unshift(`${lines++}: ${t.join(' ')}`);
debugLines.splice(5);
d.innerHTML = debugLines.join('<br />');
}
document.querySelectorAll('circle')[0].addEventListener('touchstart', writeDebug);
/* remove comment from the line below to test workaround */
// document.querySelector('svg').addEventListener('touchstart', () => {});
<!doctype html>
<html>
<head>
<style>
svg { background: #f0f0f0; width: 200px; float: left; }
</style>
</head>
<body>
<div id="wrap">
<svg viewBox="-50, -50, 100, 100" class="b-circular-slider-svg">
<circle cx="0" cy="0" r="8"
stroke="#ccc" fill="#fafafa"
transform="translate(0, -10)"></circle>
</svg>
</div>
<strong>debug:</strong>
<div id="debug"></div>
</body>
</html>

svg convert to canvas - can't generate multi pages pdf

I have 12 graphs and I want to generate pdf with 2 pages each page has 6 graphs.
However, when I convert svg to canvas, then the jspdf can only see part of both sub-dives.
$('#downloadx2').click(function() {
var svgElements = $("#body_id").find('svg');
//replace all svgs with a temp canvas
svgElements.each(function() {
var canvas, xml;
// canvg doesn't cope very well with em font sizes so find the calculated size in pixels and replace it in the element.
$.each($(this).find('[style*=em]'), function(index, el) {
$(this).css('font-size', getStylex(el, 'font-size'));
});
canvas = document.createElement("canvas");
canvas.className = "screenShotTempCanvas";
//convert SVG into a XML string
xml = (new XMLSerializer()).serializeToString(this);
// Removing the name space as IE throws an error
xml = xml.replace(/xmlns=\"http:\/\/www\.w3\.org\/2000\/svg\"/, '');
//draw the SVG onto a canvas
canvg(canvas, xml);
$(canvas).insertAfter(this);
//hide the SVG element
////this.className = "tempHide";
$(this).attr('class', 'tempHide');
$(this).hide();
});
var doc = new jsPDF("p", "mm");
var width = doc.internal.pageSize.width;
var height = doc.internal.pageSize.height;
html2canvas($("#div_pdf1"), {
onrendered: function(canvas) {
var imgData = canvas.toDataURL(
'image/png', 0.1);
doc.addImage(imgData, 'PNG', 5, 0, width, height/2,'','FAST');
doc.addPage();
}
});
html2canvas($("#div_pdf2"), {
onrendered: function(canvas2) {
var imgData2 = canvas2.toDataURL(
'image/png', 0.1);
doc.addImage(imgData2, 'PNG', 5, 0, width, height/2,'','FAST');
doc.save('.pdf');
}
});
});
<body id="body_id">
<div id="div_pdf1" >
<svg></svg>
<svg></svg>
<svg></svg>
</div>
<div id="div_pdf1" >
<svg></svg>
<svg></svg>
<svg></svg>
</div>
</body>
When I run this code, the generated pdf will view two pages with same canvas the first one (div_pdf1) div. So how to get both of them appearing in pdf as two pages.
You seem to be trying to run 2 parts in sequence but that's not how javascript works and actually runs your code.
No big deal, just a small misunderstanding between your mental model and the engine that executes the code.
A quick temporary debugging tool to see what's going on and verify that there is a discrepancy is to add console.log to key points and check the sequence of their printout once you run the code.
console.log('[1] just before: svgElements.each');
svgElements.each(function() {
console.log('[2] just after: svgElements.each');
And also around this part of the code:
console.log('[3] just before html2canvas-div_pdf1');
html2canvas($("#div_pdf1"), {
console.log('[4] just after html2canvas-div_pdf1');
Finally around this part of the code:
console.log('[5] just before html2canvas-div_pdf2');
html2canvas($("#div_pdf2"), {
console.log('[6] just after html2canvas-div_pdf2');
I suspect you'll see the code doesn't print the log lines in the order you think they will.
Next, you can try wrapping the 2 calls to html2canvas with one setTimeout function and force a delay in the execution of that code by an arbitrary amount of milliseconds.
Note that this is not the recommended final production quality solution but it will make the code output what you want.

Google Earth Plugin, embedded in Blogger, producing 2 maps

Curious problem whilst embedding a Google Earth network link into Blogger.
The code I'm using is as shown below, but I'm getting two instances of GE on the same page, one above the other.
They must be getting generated seperately, as if I stick a border into the divs style on the page it only affects one instance.
<div id="map3d" style="border: 4px solid silver; height: 768px; width: 1024px;"></div>
However, if I remove this code from the page entirely. both instances vanish.
Other than that I've got it functioning as I'm wanting. (Eventually)
This is the code I've got in the head section
<!-- Earth -->
<script src="//www.google.com/jsapi?key=mykey"></script>
<script type="text/javascript">
var ge;
google.load("earth", "1", {"other_params":"sensor=false"});
function init() {
google.earth.createInstance('map3d', initCB, failureCB);
}
function initCB(instance) {
ge = instance;
ge.getWindow().setVisibility(true);
ge.getNavigationControl().setVisibility(ge.VISIBILITY_SHOW);
var href = 'http://urltomykmz';
google.earth.fetchKml(ge, href, function(kmlObject) {
if (kmlObject)
ge.getFeatures().appendChild(kmlObject);
if (kmlObject.getAbstractView() !== null)
ge.getView().setAbstractView(kmlObject.getAbstractView());
});
}
function failureCB(errorCode) {
}
google.setOnLoadCallback(init);
</script>
<!-- Earth -->
Grateful to anyone who can point to what's causing the second instance. Thanks.
You have to remove either the call to init() in your onload handler or the call to google.setOnLoadCallback(init), otherwise a map will be added every time you call the init function.

Reinitialize SVGweb for ajax

I have no problem using SVGweb when page is simply loaded (opened).
How is it possible to reinitialize SVGweb in order to redraw all SVG on the page?
Anotherwords I need SVGweb to rescan and rerender everything on the page.
source (from this):
<script type="image/svg+xml">
<svg>
...
</svg>
</script>
to this (like SVGweb si doing that when simply open the page):
<svg>
...
</svg>
I need this because I change the SVG graphics using ajax and need to rerender it on the page.
I needed the same capability and figured out how to do this properly without modifying the svgweb source or calling the _onDOMContentLoaded() handler manually. In fact, it is supported natively.
The trick is to (re)attach your SVG elements to the DOM using window.svgweb.appendChild() which causes the node to be processed by svgweb, as is documented within the svgweb manual.
Example, using jQuery:
// Iterate over all script elements whose type attribute has a value of "image/svg+xml".
jQuery('body').find('script[type="image/svg+xml"]').each(function () {
// Wrap "this" (script DOM node) in a jQuery object.
var $this = jQuery(this);
// Now we use svgweb's appendChild method. The first argument is our new SVG element
// we create with jQuery from the inner text of the script element. The second
// argument is the parent node we are attaching to -- in this case we want to attach
// to the script element's parent, making it a sibling.
window.svgweb.appendChild(jQuery($this.text())[0], $this.parent()[0]);
// Now we can remove the script element from the DOM and destroy it.
$this.remove();
});
For this to work properly I suggest wrapping all SVG script tags with a dedicated div, so that when attaching the SVG element it is attached to a parent element containing no other nodes. This removes the possibility of inadvertently reordering nodes during the process.
After the DOM is changed with a new SVGweb code (through Ajax)
<script type="image/svg+xml">
<svg>
...
</svg>
</script>
need to execute this:
svgweb._onDOMContentLoaded();
But before need to comment a line in the core source of SVGweb svg-uncompressed.js or svg.js
svg-uncompressed.js
from
if (arguments.callee.done) {
return;
}
to
if (arguments.callee.done) {
//return;
}
svg.js: find and delete this:
arguments.callee.done=true;
or replace with
arguments.callee.done=false;
EDIT:
One more fix to work for IE9:
for svg.js
from
var a=document.getElementById("__ie__svg__onload");if(a){a.parentNode.removeChild(a);a.onreadystatechange=null}
to
var IEv=parseFloat(navigator.appVersion.split("MSIE")[1]);if(IEv<9){var a=document.getElementById("__ie__svg__onload");if(a){a.parentNode.removeChild(a);a.onreadystatechange=null;a=null;}}
for svg-uncompressed.js
from
// cleanup onDOMContentLoaded handler to prevent memory leaks on IE
var listener = document.getElementById('__ie__svg__onload');
if (listener) {
listener.parentNode.removeChild(listener);
listener.onreadystatechange = null;
listener = null;
}
to
// cleanup onDOMContentLoaded handler to prevent memory leaks on IE
var IEv=parseFloat(navigator.appVersion.split("MSIE")[1]);
if (IEv<9) {
var listener = document.getElementById('__ie__svg__onload');
if (listener) {
listener.parentNode.removeChild(listener);
listener.onreadystatechange = null;
listener = null;
}
}

JQuery Cycle Plugin - Delay Interval Between Slides Question

I'm using jQuery Cycle Plugin for an image slider. What I'm looking for is something like this:
image1.jpg >> fadeout >> hold on the blank frame for a second >> fadein image2.jpg >> repeat
How can I control the delay before the next fade animation starts, or the interval between 2 slide transitions?
I mean when the first slide image completely fades out, I need it to pause for 1 or 2 seconds before the second image actually begins its fadein animation.
** I need to get this to work during when I'm changing slides with the pager or next/prev links.
I've tried turning sync: 0 to stop simultaneous fading transition between 2 slides but not quite what I was looking for.
Any advice will be appreciated, thanks.
You can define a custom transition which fades out the current slide, waits, and then fades in the next slide.
For a more complete example than below, see: http://jsfiddle.net/QGRv9/1/
$.fn.cycle.transitions.fadeOutWaitFadeIn = function($cont, $slides, opts) {
opts.fxFn = function(curr, next, opts, after) {
$(curr).fadeOut(opts.fadeSpeed, function() {
$(next).delay(opts.delayBetweenFades).fadeIn(opts.fadeSpeed, function() {
after();
});
});
};
};
$(function() {
$('#slideshow').cycle({
fx: 'fadeOutWaitFadeIn',
fadeSpeed: 500,
delayBetweenFades: 2000,
//The timeout value includes the fade speed (twice) and delay between fades.
//e.g. For a 3000 ms timeout, use 3000 + 500 * 2 + 2000 = 6000.
timeout: 6000
});
});
Note that I'm probably doing something wrong here. The timeout shouldn't have to include the other values. There's also one small issue: The first slide gets shown for 6000ms instead of 3000ms.
One way is to insert a blank slide after each image. You can then use the timeoutFn option to give a different timeout value depending on whether the slide is an image or a blank slide.
Here's an example where the images are displayed for 5 seconds and blank slides are displayed for 2 seconds:
http://jsfiddle.net/7jJe3/
<div id="slideshow">
<img src="image1.jpg" />
<span></span>
<img src="image2.jpg" />
<span></span>
<img src="image3.jpg" />
<span></span>
</div>
function timeoutfn(currSlideElement, nextSlideElement, options, forwardFlag) {
var imgtime = 5000;
var blanktime = 2000;
if ($(currSlideElement).is('img'))
return imgtime;
return blanktime;
};
$(function() {
$('#slideshow').cycle({
fx: 'fade',
speed: 400,
timeoutFn: timeoutfn
});
});

Resources