function docReady(fn) {
// see if DOM is already available
if (
document.readyState === 'complete' ||
document.readyState === 'interactive'
) {
// call on next available tick
setTimeout(fn, 1);
} else {
document.addEventListener('DOMContentLoaded', fn);
}
}
function escapeRegExp(str) {
return str.replace(/([.*+?^=!:${}()|[]/\])/g, '\$1');
}
function replaceAll(str, find, replace) {
return str.replace(new RegExp(escapeRegExp(find), 'g'), replace);
}
function transformInDataUri(id) {
var svgText = new XMLSerializer().serializeToString(
document.getElementById(id),
);
var raw = svgText;
var encoded = raw.replace(/s+/g, ' ');
// According to Taylor Hunt, lowercase gzips better ... my tiny test confirms this
encoded = replaceAll(encoded, '%', '%25');
encoded = replaceAll(encoded, '> <', '><'); // normalise spaces elements
encoded = replaceAll(encoded, '; }', ';}'); // normalise spaces css
encoded = replaceAll(encoded, '<', '%3c');
encoded = replaceAll(encoded, '>', '%3e');
encoded = replaceAll(encoded, '"', "'");
encoded = replaceAll(encoded, '#', '%23'); // needed for ie and firefox
encoded = replaceAll(encoded, '{', '%7b');
encoded = replaceAll(encoded, '}', '%7d');
encoded = replaceAll(encoded, '|', '%7c');
encoded = replaceAll(encoded, '^', '%5e');
encoded = replaceAll(encoded, '`', '%60');
encoded = replaceAll(encoded, '@', '%40');
var uri = 'url("data:image/svg+xml;charset=UTF-8,' + encoded + '")';
return uri;
}
function getCurrentAnimatePropertyValue(el, propertyName) {
let value = getComputedStyle(el, null).getPropertyValue(propertyName);
return value;
}
function getTimer() {
console.log('ok')
let elapsedTime = 0;
let timer;
function start() {
timer = window.setInterval(function() {
elapsedTime += 100
console.log(elapsedTime)
}, 100)
}
function pause() {
window.clearInterval(timer)
console.log(elapsedTime)
return elapsedTime
}
function reset() {
window.clearInterval(timer)
elapsedTime = 0;
console.log(elapsedTime)
return elapsedTime
}
return {
start: start,
pause: pause,
reset: reset
}
}
function getUpdatedDurations(currentDurations, elapsedTime) {
let animationDurations = currentDurations; // '2s, 1s';
let values = animationDurations.replace(/s/g, "").split(',').map(el => {
let finalEl = parseFloat(el.replace("s", "")) * 1000;
return finalEl;
})
let updatedValues = values.map(duration => duration - elapsedTime )
let updatedValuesAsString = updatedValues.map(duration => {
return (duration/1000).toString(10) + 's';
})
return updatedValuesAsString.toString()
}
// svg, [{ 'dash1': {'dash-offset': '1000px' }}, { 'fill': {'fill-opacity': 1 }}]
function changeAnimationStartKeyFrame(animations) {
for (let index = 0; index <document.styleSheets.length; index++) {
let stylesheet = document.styleSheets[index];
if(stylesheet['title'] === 'svg') {
animations.map(animation => {
let animationName = Object.keys(animation)[0];
let cssRules = stylesheet['cssRules']
let objectWithRules = animation[animationName];
let propertyName = Object.keys(objectWithRules)[0]
let updatedValue = objectWithRules[propertyName];
for (let index = 0; index < cssRules.length; index++) {
let cssRule = cssRules[index];
if(cssRule.type === 7 && cssRule.name === animationName) {
console.log(propertyName)
let CSSKeyframesRule = cssRule;
if(animationName === 'dash1') {
CSSKeyframesRule.deleteRule("0%");
CSSKeyframesRule.appendRule(`0% { ${propertyName}: ${updatedValue}; }`);
}
else {
CSSKeyframesRule.deleteRule("80%");
CSSKeyframesRule.appendRule(`80% { ${propertyName}: ${updatedValue}; }`);
}
}
}
})
}
console.log(stylesheet)
}
}
docReady(function () {
// charset reportedly not needed ... I need to test before implementing
console.log(Array.from(document.styleSheets))
var svgAsBorderSelector = 'svg-as-border';
var svg = document.getElementById(svgAsBorderSelector);
var svgAnimatedSelectors = '.path-1';
var svgElementsToAnimate = svg.querySelectorAll(svgAnimatedSelectors);
let divToBorderWithAnimatedSvg = document.querySelector('.frame-1');
divToBorderWithAnimatedSvg.style.borderImageSource = transformInDataUri(
svgAsBorderSelector,
);
let currentFillOpacity;
let currentStrokeDashOffset;
let currentStrokeDashArray;
let timer = getTimer(), elapsedTime;
divToBorderWithAnimatedSvg.addEventListener('mouseenter', (e) => {
for (var i = 0, max = svgElementsToAnimate.length; i < max; i++) {
let element = svgElementsToAnimate[i];
currentStrokeDashOffset = getCurrentAnimatePropertyValue(
element,
'stroke-dashoffset',
);
currentStrokeDashArray = getCurrentAnimatePropertyValue(
element,
'stroke-dasharray',
);
currentFillOpacity = getCurrentAnimatePropertyValue(
element,
'fill-opacity',
);
document.body.clientHeight
element.style.webkitAnimationName = 'dash1';
timer.start();
element.style.strokeDashoffset = currentStrokeDashOffset;
element.style.strokeDasharray = currentStrokeDashArray;
element.style.fillOpacity = currentFillOpacity;
element.style.animationPlayState = 'running, running';
}
divToBorderWithAnimatedSvg.style.borderImageSource = transformInDataUri(
svgAsBorderSelector,
);
});
divToBorderWithAnimatedSvg.addEventListener('mouseleave', (e) => {
for (var i = 0, max = svgElementsToAnimate.length; i < max; i++) {
let element = svgElementsToAnimate[i];
currentStrokeDashOffset = getCurrentAnimatePropertyValue(
element,
'stroke-dashoffset',
);
currentStrokeDashArray = getCurrentAnimatePropertyValue(
element,
'stroke-dasharray',
);
currentFillOpacity = getCurrentAnimatePropertyValue(
element,
'fill-opacity',
);
let currentAnimationTime = getCurrentAnimatePropertyValue(element, 'animation-duration');
elapsedTime = timer.pause();
let updatedAnimationTime = getUpdatedDurations(currentAnimationTime, elapsedTime)
element.style.animationPlayState = 'paused, paused';
element.style.webkitAnimationName = 'none';
element.style.strokeDashoffset = currentStrokeDashOffset;
element.style.strokeDasharray = currentStrokeDashArray;
element.style.fillOpacity = currentFillOpacity;
element.style.animationDuration = updatedAnimationTime;
changeAnimationStartKeyFrame([{ 'dash1': {'stroke-dashoffset': currentStrokeDashOffset }}, { 'fill': {'fill-opacity': currentFillOpacity }}])
}
divToBorderWithAnimatedSvg.style.borderImageSource = transformInDataUri(
svgAsBorderSelector,
);
});
});
.frame-1 {
border: 22px solid;
border-image-slice: 41;
border-image-width: 32px;
border-image-outset: 0;
border-image-repeat: stretch;
}
.blockquote-container blockquote, .blockquote-container blockquote p {
color: #a17c4a;
}
.blockquote-container blockquote {
padding: .5em;
}
<div class="blockquote-container">
<blockquote class="frame-1">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec placerat ex enim, nec tempus nisl commodo a. Nullam eu odio ut neque interdum mollis quis ac velit. Etiam pulvinar aliquam auctor.</p>
</blockquote>
</div>
<svg id='svg-as-border' class='svg-frame-1' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 337 198'>
<g fill='none' fill-rule='evenodd'>
<style title="svg">
.path-1 {
stroke: #BEA757;
fill-opacity: 0;
stroke-width: 1;
stroke-dasharray: 1948px;
stroke-dashoffset: 1948px;
animation-name: dash1, fill;
animation-duration: 2s, 1s;
animation-fill-mode: forwards;
animation-delay: 0s, 0s;
animation-play-state: paused, paused;
}
@keyframes dash1 {
0% {
stroke-dashoffset: 1948px;
}
100% {
stroke-dashoffset: 0;
}
}
@keyframes fill {
80% {
fill-opacity: 0;
}
100% {
fill-opacity: 1;
}
}
</style>
<path class='path-1' fill='#BEA757'
d='M22.68,176.6 L315.68,176.6 L315.68,22.6 L22.68,22.6 L22.68,176.6 Z M331.596839,180.6 L332.68,180.6 L332.68,193.6 L319.68,193.6 L319.68,180.6 L3