SVG animation paused while webpack is loading dynamic Vue component - animation

I am creating a Vue application where the root component is dynamically loaded from the main App.vue component (via import('') directive).
In my App.vue component I placed a component containing the infinite animating SVG (via <animate> tags) and the async loaded control. The idea is that the SVG should be animating until the dynamically loaded control is loaded and then I will hide it.
However this does not happen. SVG is permanently frozen in first frame until the dynamic component .js file is loaded and parsed. After that the SVG starts to animate but by then it is too late.
Here is the App.vue:
<template>
<div style="height: 100%; width: 100%;">
<loading v-if="loadingDisplayed" ></loading>
<app-root #hook:mounted="onAppMounted"></app-root>
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import Loading from './Components/Loading.vue'
//import AppRoot from './Components/AppRoot.vue'
const AppRoot = () => import(/* webpackChunkName: "root" */ './Components/AppRoot.vue').then(m => m.default);
#Component({
components: { AppRoot, Loading }
})
export default class App extends Vue {
loadingDisplayed: boolean = true;
onAppMounted() : void {
this.loadingDisplayed = false;
}
}
</script>
Here is the loading control:
<template>
<div class="loader">
<div style="flex-basis: 20%;">
My title
</div>
<div>
{{txt_loading}}
</div>
<div style="flex-basis: 80%;">
<svg width="100%" height="100%" viewBox="0 0 44 44" xmlns="http://www.w3.org/2000/svg" stroke="#fff">
<g fill="none" fill-rule="evenodd" stroke-width="2">
<circle cx="22" cy="22" r="1" stroke="black">
<animate attributeName="r"
begin="0s" dur="1.8s"
values="1; 20"
calcMode="spline"
keyTimes="0; 1"
keySplines="0.165, 0.84, 0.44, 1"
repeatCount="indefinite" />
<animate attributeName="stroke-opacity"
begin="0s" dur="1.8s"
values="1; 0"
calcMode="spline"
keyTimes="0; 1"
keySplines="0.3, 0.61, 0.355, 1"
repeatCount="indefinite" />
</circle>
<circle cx="22" cy="22" r="1" stroke="black">
<animate attributeName="r"
begin="-0.9s" dur="1.8s"
values="1; 20"
calcMode="spline"
keyTimes="0; 1"
keySplines="0.165, 0.84, 0.44, 1"
repeatCount="indefinite" />
<animate attributeName="stroke-opacity"
begin="-0.9s" dur="1.8s"
values="1; 0"
calcMode="spline"
keyTimes="0; 1"
keySplines="0.3, 0.61, 0.355, 1"
repeatCount="indefinite" />
</circle>
</g>
</svg>
</div>
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
#Component
export default class Loading extends Vue {
txt_loading : "Please wait"
}
</script>
<style lang="scss" scoped>
.loader {
height: 100%;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
font-size: 2em;
font-weight: bold;
}
</style>
Is this normal behaviour or is there a way to have SVG animating while the browser is loading the .js file?

Related

Animating SVG on a curved path in Internet Explorer

I'm trying to animate along a path based on this post: move SVG group on path trail based on percentage of whole path trail
It works beautifully in all browsers but Internet Explorer. I've read lots of posts about the lack of support in IE but I still have enough users that use it that I need to consider it. Can I convert this to another method?
Here is my code (simplified icon here, more complex icon in CodePen):
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Jeep Test 5</title>
<style type="text/css">
#carRight{visibility: visible;}
#carLeft{visibility: hidden;}
#carRightIsoBack {visibility: hidden;}
#carRightIsoFront {visibility: hidden;}
#carLeftIsoBack {visibility: hidden;}
#carLeftIsoFront {visibility: hidden;}
</style>
<script src="../SiteAssets/js/jquery-1.8.1.min.js"></script>
</head>
<body>
<input type="range" id="theRange" value="0"/>
<div id="percentage"></div>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 459 257" style="enable-background:new 0 0 459 257;" xml:space="preserve">
<style type="text/css">
#percentage{border:1px solid red; padding: 5px;}
svg{border:1px solid;overflow:visible; width:95vh; display:block; margin:1em auto;}
.st0{fill:none;stroke:#F1EA0D;stroke-width:5;stroke-miterlimit:10;}
.st1{fill:#1A1A1A;}
.st2{fill:#FF0000;}
</style>
<defs>
<g id="carRight" transform="translate(-90, -240)">
<circle class="st3" cx="134.5" cy="215.2" r="12"/>
</g>
</defs>
<path id="path" class="st0" d="M20.5,249.5c0,0,27,0,54,1s47.36-5,61-13c40.32-23.66,50.1-50.05,3-82c-35.12-23.83-65-19-97-44
c-22.4-17.5-21.92-28.85-1-41c31-18,101.15-43.54,158-27c55,16,48,30,45,61s-8,39-13,60s5.09,40.12,17,56c18,24,56.49,26.8,81,17
c10-4,33-17,29-48c-3.36-26.03-15-34-30-53s-4.97-25.67,7-27c18-2,32.57-1.81,59,7c24,8,54,9,65,4s1-22-9-32s-14-17-30-24
s-34-8-53-3s-28,11-44,14s-26-10-18-25s22-28,42-38c4-2,9-4,9-4"/>
<use id="theUse_car_right" transform="translate(0,20)" xlink:href="#carRight" />
</svg>
<script type="text/javascript">
let pathlength = path.getTotalLength();
let pos = path.getPointAtLength(0);
theUse_car_right.setAttributeNS(null,"x", pos.x);
theUse_car_right.setAttributeNS(null,"y", pos.y);
document.getElementById("percentage").textContent = "Completion=0%";
theRange.addEventListener("input", ()=>{
let perc = parseInt(theRange.value);
let leng = pathlength * perc/100;
pos = path.getPointAtLength(leng);
theUse_car_right.setAttributeNS(null,"x", pos.x);
theUse_car_right.setAttributeNS(null,"y", pos.y);
document.getElementById("percentage").textContent = "Completion=" + perc + "%";
})
</script>
</body>
</html>
Demo'd here: https://codepen.io/mrsgorgon/pen/ExNbEPN
The issue of your code is in the JavaScript.
Arrow function => is not supported in IE. You need to use the traditional function expression.
The input event on input range won't be triggerrd in IE. You need to use change event to monitor the change of the input range. But change event won't be triggered in other modern browsers, so we need to combine the two event handlers.
I define the function as moveit and combine the two event handlers like this:
<input type="range" id="theRange" value="0" oninput="moveit()" onchange="moveit()" />
The complete sample code is like this:
let pathlength = path.getTotalLength();
let pos = path.getPointAtLength(0);
theUse_car_right.setAttributeNS(null, "x", pos.x);
theUse_car_right.setAttributeNS(null, "y", pos.y);
document.getElementById("percentage").textContent = "Completion=0%";
function moveit() {
let perc = parseInt(theRange.value);
let leng = pathlength * perc / 100;
pos = path.getPointAtLength(leng);
theUse_car_right.setAttributeNS(null, "x", pos.x);
theUse_car_right.setAttributeNS(null, "y", pos.y);
document.getElementById("percentage").textContent = "Completion=" + perc + "%";
}
#carRight {
visibility: visible;
}
#carLeft {
visibility: hidden;
}
#carRightIsoBack {
visibility: hidden;
}
#carRightIsoFront {
visibility: hidden;
}
#carLeftIsoBack {
visibility: hidden;
}
#carLeftIsoFront {
visibility: hidden;
}
#percentage {
border: 1px solid red;
padding: 5px;
}
svg {
border: 1px solid;
overflow: visible;
width: 95vh;
display: block;
margin: 1em auto;
}
.st0 {
fill: none;
stroke: #F1EA0D;
stroke-width: 5;
stroke-miterlimit: 10;
}
.st1 {
fill: #1A1A1A;
}
.st2 {
fill: #FF0000;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<input type="range" id="theRange" value="0" oninput="moveit()" onchange="moveit()" />
<div id="percentage"></div>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 459 257" style="enable-background:new 0 0 459 257;" xml:space="preserve">
<defs>
<g id="carRight" transform="translate(-90, -240)">
<circle class="st3" cx="134.5" cy="215.2" r="12" />
</g>
</defs>
<path id="path" class="st0" d="M20.5,249.5c0,0,27,0,54,1s47.36-5,61-13c40.32-23.66,50.1-50.05,3-82c-35.12-23.83-65-19-97-44
c-22.4-17.5-21.92-28.85-1-41c31-18,101.15-43.54,158-27c55,16,48,30,45,61s-8,39-13,60s5.09,40.12,17,56c18,24,56.49,26.8,81,17
c10-4,33-17,29-48c-3.36-26.03-15-34-30-53s-4.97-25.67,7-27c18-2,32.57-1.81,59,7c24,8,54,9,65,4s1-22-9-32s-14-17-30-24
s-34-8-53-3s-28,11-44,14s-26-10-18-25s22-28,42-38c4-2,9-4,9-4" />
<use id="theUse_car_right" transform="translate(0,20)" xlink:href="#carRight" />
</svg>

d3 svg attrtween each by each

demo
The demo as you can see, I want to do the effect that the box rotates by itself like the red boxes below (div version).
I try to use svg to rewrite it, but svg version seems to rotate all svg
How can I let them rotate by themselves like the div version???
Here is the svg version's main logic:
d3.selectAll('g')
.each(function (data, index) {
d3.select(this)
.transition('t3')
.delay(800)
.duration(2500)
.styleTween('transform', function () {
return d3.interpolateString('rotateY(0deg)', 'rotateY(360deg)');
})
})
Add the following to get the SVG elements to transform around their centres.
g {
transform-origin: center center;
transform-box: fill-box;
}
E.g.
d3.selectAll('g')
.each(function (data, index) {
d3.select(this)
.transition('t3')
.delay(800)
.duration(2500)
.styleTween('transform', function () {
return d3.interpolateString('rotateY(0deg)', 'rotateY(360deg)');
})
})
d3.selectAll('div.box')
.each(function (data, index) {
d3.select(this)
.transition('t3')
.delay(800)
.duration(2500)
.styleTween('transform', function () {
return d3.interpolateString('rotateY(0deg)', 'rotateY(360deg)');
})
})
rect {
fill:rgb(121,0,121);
stroke-width:1;
stroke:rgb(0,0,0);
}
.section {
display: flex;
}
.box {
margin: 10px;
width: 50px;
height: 50px;
background-color: red;
}
g {
transform-origin: center center;
transform-box: fill-box;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<h3>still trying: </h3>
<div>
<svg width="800" height="100">
<g>
<rect x="10" y="30" width="50" height="50"></rect>
</g>
<g>
<rect x="70" y="30" width="50" height="50"></rect>
</g>
<g>
<rect x="130" y="30" width="50" height="50"></rect>
</g>
<g>
<rect x="190" y="30" width="50" height="50"></rect>
</g>
</svg>
</div>
<h3>expected: </h3>
<div class="section">
<div class="box">A</div>
<div class="box">B</div>
<div class="box">C</div>
<div class="box">D</div>
</div>

Why does simple animation cause a very long update layer tree?

Paste this code on any site with a heavy interface (twitter for example) and run a performance test:
<div style="position: absolute; contain: strict; width: 100vw; height: 100vh; z-index: 2000; top: 0; left: 0; background: white; backface-visibility: hidden;">
<svg viewBox="0 0 100 100" height="40px">
<rect width="40" height="40" x="93.5319">
<animate attributeName="x" dur="1000ms" repeatCount="indefinite" from="0" to="100"></animate>
</rect>
</svg>
</div>
For incomprehensible reasons to me, the "update layer tree" takes several ms on the core i7 4770k:
example on twitter.com
And if you insert the same code on an empty page, then everything works very quickly. Why is this happening and how to fix it?

animated svg mask doesn't work in firefox

h1 everyone, i'm trying to make a cross-browser animation based on svg mask for svg elements. At first, I caught a bug with css, in firefox mask doesn't work with css 'width' and 'height', only with inline properties. So, next question - how to animate mask for firefox, nothing harder that 'width resize'. https://codepen.io/flyby/pen/KmYOgb
<div id='cont'>
<svg>
<defs>
<mask id='rectMask' maskUnits='userSpaceOnUse' maskContentUnits='userSpaceOnUse' transform='scale(1)'>
<rect x='0' y='0' id='maskRect' width='700' height='850'/>
</mask>
</defs>
<path id='maskedPath' d='m 0,0 l 650,0 -100,850 -550,0 z' mask='url(#rectMask)'/>
<path id='riverPath' d='m 653,0 l -100,850' mask='url(#rectMask)'/>
<path id='notMaskedPath' d='m 655,0 l 650,0 0,850 -750,0 z'/>
</svg>
</div>
CSS:
body {
margin:0;
padding:0;
overflow:hidden;
}
#cont {
width:100vw;
height:100vh;
background-color:rgb(50,50,50);
}
svg {
width:100%;
height:100%;
}
#maskedPath {
stroke:none;
fill:rgb(230,230,230);
}
#notMaskedPath {
stroke:none;
fill:rgb(230,230,230);
}
#riverPath {
stroke:rgb(50,160,240);
stroke-width:8;
fill:none;
}
#maskRect {
width:0px;
height:850px;
fill:white;
stroke:none;
animation: resize 3s linear infinite;
}
#-moz-keyframes resize {
50% {width: 700px !important;}
0%,100% {width: 0px !important;}
}
Like you have discovered, your can't (yet) set geometric properties, like width and height of SVG elements in Firefox. It's not a bug. It's just an SVG 2 thing that Firefox has not implemented yet, but Chrome has.
The solution is to use the built-in SVG ("SMIL") animation elements, instead of CSS animation.
body {
margin:0;
padding:0;
overflow:hidden;
}
#cont {
width:100vw;
height:100vh;
background-color:rgb(50,50,50);
}
svg {
width:100%;
height:100%;
}
#maskedPath {
stroke:none;
fill:rgb(230,230,230);
}
#notMaskedPath {
stroke:none;
fill:rgb(230,230,230);
}
#riverPath {
stroke:rgb(50,160,240);
stroke-width:8;
fill:none;
}
#maskRect {
fill:white;
stroke:none;
}
<!--this animation doesn't work in FIREFOX, and not tested in IE11 ad Edge YET, WILL BE FIXED SOON (I HOPE)-->
<div id='cont'>
<svg>
<defs>
<mask id='rectMask' maskUnits='userSpaceOnUse' maskContentUnits='userSpaceOnUse' transform='scale(1)'>
<rect x='0' y='0' width="0" height="850" id='maskRect'>
<animate attributeName="width"
keyTimes="0; 0.4; 0.5; 1"
values="0; 670; 670; 0"
dur="4s" repeatCount="indefinite"/>
</rect>
</mask>
</defs>
<path id='maskedPath' d='m 0,0 l 650,0 -100,850 -550,0 z' mask='url(#rectMask)'/>
<path id='riverPath' d='m 653,0 l -100,850' mask='url(#rectMask)'/>
<path id='notMaskedPath' d='m 655,0 l 650,0 0,850 -750,0 z'/>
</svg>
</div>

CSS3 Transform Issues in IE10/IE11

I'm having trouble getting this svg to display correctly in IE10/IE11.
It works fine in Chrome and Firefox.
Here is a CodePen with my situation.
Any thoughts?
Start with a simplified test:
<!doctype html>
<head>
<style>
.rack-edit { transform: rotateY(140deg); }
.figure { display: block; width: 500px; height: 300px; }
</style>
</head>
<div class="rack-edit">
<figure class="back">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="444" height="294">
<rect stroke="black" stroke-width="10" width="10" height="10" />
</svg>
</figure>
</div>
Get that working the same in all three browsers, then go from there.

Resources