d3 svg attrtween each by each - d3.js

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>

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>

SVG animation paused while webpack is loading dynamic Vue component

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?

svg hover overlapping elements in Firefox

I have a svg with some circles that should get bigger on hover, here is a snippet
!This will not work in Firefox
var svgRoot = $('.svg-root')[0];
$('.bubble').mouseover(function (e) {
svgRoot.append(e.currentTarget);
});
circle{
transition: all 200ms;
}
circle:hover{
stroke: black;
fill: white;
transform: scale(3);
}
.svg-root svg{
overflow: visible;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<svg class="svg-root">
<svg class="bubble" x="50" y="50">
<circle r="10"></circle>
</svg>
<svg class="bubble" x="70" y="70">
<circle r="10"></circle>
</svg>
<svg class="bubble" x="90" y="50">
<circle r="10"></circle>
</svg>
</svg>
To avoid the other circles overlapping the one the mouse is currently hovering over, I used the append trick. That solves the z-index Problem, but it causes a different one. It seems that after appending the node, Firefox does not recognize the hover state of the cursor. The circles will not scale on hover in Firefox, but they will in Chrome.
I need them to scale on hover and to have the highest z-index while doing so.
Any solutions?

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>

firefox 35.0.1: svg mask animation doesn't work

after my firefox update to version 35.0.1 my svg animations doesn't work in firefox, but it was working in previous versions and it still works in firefox beta (36), nightly (37.0a2) and other browsers (opera, chrome, safari, modern ie):
html:
<svg version="1.1" id="logo-svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="55px" height="53.758px" viewBox="-1061.986 3038.43 55 53.758" enable-background="new -1061.986 3038.43 188.279 53.758" xml:space="preserve">
<g id="logo-mask" >
<rect id="sygnet" fill="#FFFFFF" x="-1100" y="3038" width="100" height="50"/>
</g>
<g id="logo-black">
<rect id="sygnet" fill="#000000" x="-1100" y="3038" width="100" height="50"/>
</g>
</svg>
<div id="button">Click me!</div>
css:
body{
background-color: #777777;
}
#button{
margin-right: 100px;
display: block;
width: 100px;
height: 20px;
float: right;
background-color: #fff;
cursor: pointer;
text-align: center;
line-height: 20px;
}
js (using snap.svg):
$(document).ready(function(){
var s = Snap(),
svg = Snap.select('#logo-svg'),
logo = Snap.select('#logo-mask'),
logoBlack = Snap.select('#logo-black'),
mask = svg.rect(-1100, 2830, 280, 100).attr({
fill: 'white',
id: 'maska-logo'
});
logoBlack.attr({'mask': mask, 'opacity': 1});
});
$(document).on('click', '#button', function(){
var maska = Snap.select('#maska-logo');
maska.animate({
transform: 'T'+[0,200]
}, 500);
});
simple example: http://jsfiddle.net/7yq14L0f/2/
any idea, why? :(
It was caused by a change in the Firefox code which was not completely correct and which was then fixed. Bug 932771 caused it and bug 1127507 which was backported as far as Firefox 36 fixed it.

Resources