I have an SVG that animates along a path when a range slider is moved: Animating SVG on a curved path in Internet Explorer
However, I'd like the animation to occur when the window loads. Preferably, I'd like it to animate to a percentage of the path (theRange). theRange is a set number which I change in the code (it indicates percentage of people that completed a survey. I'd like to keep some way of tracking the percentage that the avatar has traveled, because I want to trigger popup windows when "perc" reaches 40 and 60. Client requires it to work in IE 10.
Here it is in CodePen: https://codepen.io/mrsgorgon/pen/yLVjaVL
Below is what I have so far. Nothing happens, but I get no errors either.
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Avatar Simple Test 2</title>
<style type="text/css">
svg{overflow:visible; width:100vh; height: 100vh; display:block; margin:0 auto;}
</style>
</head>
<body>
<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 432 254" style="enable-background:new 0 0 432 254;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;stroke:#F1EA0D;stroke-width:5;stroke-miterlimit:10;}
.st1{fill:#FF0000;}
</style>
<path id="road" class="st0" d="M26.56,231.06c0,0,23.33-0.64,47.31,0.24s41.03-7.21,52.94-14.64c31.62-19.74,37.37-42.74-2.11-71.83
c-30.34-22.36-57.72-16.87-86.14-39.07C18.67,90.22,19.1,80.13,37.67,69.35C65.2,53.36,127.5,30.69,177.98,45.37
c48.84,14.21,42.63,26.64,39.96,54.17c-2.66,27.53-7.1,34.63-11.54,53.28s4.52,35.63,15.1,49.73c15.98,21.31,50.16,23.8,71.93,15.1
c8.88-3.55,29.3-15.1,25.75-42.63c-2.98-23.12-13.32-30.19-26.64-47.07s-4.41-22.8,6.22-23.98c15.98-1.78,28.93-1.61,52.39,6.22
c21.31,7.1,47.95,7.99,57.72,3.55c9.77-4.44,0.89-19.54-7.99-28.42s-12.43-15.1-26.64-21.31s-30.19-7.1-47.07-2.66
c-16.87,4.44-24.86,9.77-39.07,12.43s-23.09-8.88-15.98-22.2c7.1-13.32,19.54-24.86,37.3-33.75c3.55-1.78,3.16-1.2,3.16-1.2"/>
<defs>
<circle id="avatar" class="st1" cx="27.5" cy="230.5" r="14"/>
</defs>
<use id="theUse_avatar" transform="translate(-30,-230)" xlink:href="#avatar" />
</svg>
<script type="text/javascript">
let roadlength = road.getTotalLength();
let pos = road.getPointAtLength(0);
let theRange = 70;
theUse_avatar.setAttributeNS(null,"x", pos.x);
theUse_avatar.setAttributeNS(null,"y", pos.y);
function moveit() {
let perc = parseInt(theRange.value);
let leng = 1;
while (leng < roadlength * perc / 100) {
theUse_avatar.setAttributeNS(null, "x", pos.x);
theUse_avatar.setAttributeNS(null, "y", pos.y);
document.getElementById("percentage").textContent = "Completion=" + perc + "%";
leng++;
}
}
window.onload = moveit;
</script>
</body>
</html>
I have tried to modify your above-mentioned code sample as per your said requirements.
Modified code:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Avatar Simple Test 2</title>
<style type="text/css">
svg{overflow:visible; width:100vh; height: 100vh; display:block; margin:0 auto;}
</style>
</head>
<body>
<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 432 254" style="enable-background:new 0 0 432 254;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;stroke:#F1EA0D;stroke-width:5;stroke-miterlimit:10;}
.st1{fill:#FF0000;}
</style>
<path id="road" class="st0" d="M26.56,231.06c0,0,23.33-0.64,47.31,0.24s41.03-7.21,52.94-14.64c31.62-19.74,37.37-42.74-2.11-71.83
c-30.34-22.36-57.72-16.87-86.14-39.07C18.67,90.22,19.1,80.13,37.67,69.35C65.2,53.36,127.5,30.69,177.98,45.37
c48.84,14.21,42.63,26.64,39.96,54.17c-2.66,27.53-7.1,34.63-11.54,53.28s4.52,35.63,15.1,49.73c15.98,21.31,50.16,23.8,71.93,15.1
c8.88-3.55,29.3-15.1,25.75-42.63c-2.98-23.12-13.32-30.19-26.64-47.07s-4.41-22.8,6.22-23.98c15.98-1.78,28.93-1.61,52.39,6.22
c21.31,7.1,47.95,7.99,57.72,3.55c9.77-4.44,0.89-19.54-7.99-28.42s-12.43-15.1-26.64-21.31s-30.19-7.1-47.07-2.66
c-16.87,4.44-24.86,9.77-39.07,12.43s-23.09-8.88-15.98-22.2c7.1-13.32,19.54-24.86,37.3-33.75c3.55-1.78,3.16-1.2,3.16-1.2"/>
<defs>
<circle id="avatar" class="st1" cx="27.5" cy="230.5" r="14"/>
</defs>
<use id="theUse_avatar" transform="translate(-30,-230)" xlink:href="#avatar" />
</svg>
<script type="text/javascript">
var roadlength = parseInt(road.getTotalLength());
var pos = road.getPointAtLength(0);
var theRange = 70;
theUse_avatar.setAttributeNS(null, "x", pos.x);
theUse_avatar.setAttributeNS(null, "y", pos.y);
function moveit()
{
var i;
for (i = 1; i <=theRange; i++)
{
var perc = i;
var myval= roadlength * perc / 100;
var path= road.value;
pos1 = road.getPointAtLength(myval);
task(i, myval, pos1);
}
}
function task(i,myval, pos1)
{
setTimeout(function()
{
theUse_avatar.setAttributeNS(null, "x", pos1.x);
theUse_avatar.setAttributeNS(null, "y", pos1.y);
document.getElementById("percentage").textContent = "Completion=" + i + "%";
}, 100 * i);
}
window.onload = moveit();
</script>
</body>
</html>
Output in the IE 11(document mode: IE 10):
Further, you can try to modify the code sample as per your own requirements.
The Goal
I'm trying to implement this…
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<script src="https://d3plus.org/js/d3.js"></script>
<script src="https://d3plus.org/js/d3plus.js"></script>
<style>
html {
height: 100%;
}
body {
margin: 0;
height: 100%;
background: linear-gradient(to top, #ddfdff, #6DD5FA, #2980B9);
}
svg {
font-family: "Helvetica", "Arial", sans-serif;
height: 100%;
width: 100%;
background: transparent;
}
.type {
fill: #888;
text-anchor: middle;
}
.shape {
fill: red;
stroke: black;
}
.invis {
fill: transparent;
stroke: transparent;
}
.title {
fill: #ffebeb;
}
</style>
</head>
<body>
<svg>
<path id="Union" fill-rule="evenodd" clip-rule="evenodd" d="M584.924 352C566.379 596.253 442.233 717.371 312.762 721.625C314.849 722.912 315.945 724.404 315.439 725.873C314.85 727.582 313.363 728.819 311.349 729.634C313.835 731.14 315.947 732.306 317.185 732.541C324.33 733.901 329.242 736.83 328.72 740.738C326.639 756.297 285.436 758.859 279.246 744.483C277.43 740.263 282.545 736.546 290.185 734.22C291.876 733.706 291.976 731.183 291.936 728.476C288.699 727.054 286.268 725.043 285.663 722.579C285.504 721.933 285.607 721.353 285.928 720.839C157.97 709.163 31.5609 584.211 2.92421 352C-23.4665 138 133.209 0 293.924 0C454.639 0 600.034 153 584.924 352Z" fill="#C80E0E"/>
<!-- 'd3plus' uses this circle as a text mask. -->
<!-- Honestly, I don't fully understand how this works; -->
<!-- Changing the circle's radius yields strange effects. -->
<circle class="shape invis" r="15px" cx="0px" cy="0px"></circle>
<text id="circleResize" class="wrap title" x="0px" y="110px" font-size="2rem">
Why is it so difficult to center text in a shape like this while specifying curved outer bounds?
</text>
</svg>
<script>
// Wrap text in a circle, and size the text to fit.
d3plus.textwrap()
.container(d3.select("#circleResize"))
.width(620)
.height(1000)
.resize(true)
.draw();
</script>
</body>
</html>
…in Svelte.
The Problem
I can't seem to get d3plus to work with Svelte.
First I tried using <svelte:head> to house the <script src="https://d3plus.org… lines. I don't recall what happened when I tried that, but my hunch is that <svelte:head> only works with CSS, or other files whose content doesn't need to be parsed by Svelte. ¯_(ツ)_/¯?
At any rate, my next approach is represented (in part) below. I first saved d3.js and d3plus.js in src, then, as shown, I import the symbols directly.
In this second scenario, though, I keep getting this console error:
Uncaught TypeError: Cannot read property 'document' of undefined
at d3.js:8
at d3.js:9553
at createCommonjsModule (index.mjs:1328)
at index.mjs:1328
at main.js:8
Presumably what's happening here is that the d3 source is getting run before the app's had a chance to load, and so document remains undefined? Regardless, I'm stuck!
Here's the (broken) code, fwiw:
<script>
import d3 from './d3.js';
import d3plus from './d3plus.js'
d3plus.textwrap()
.container(d3.select("#circleResize"))
.resize(true)
.draw();
</script>
<style>
svg {
font-family: "Helvetica", "Arial", sans-serif;
height: 100%;
width: 100%;
background: transparent;
}
.type {
fill: #888;
text-anchor: middle;
}
.shape {
fill: red;
stroke: black;
}
.invis {
/* Fill will be transparent in final outlay */
fill: #10ef3394;
stroke: transparent;
stroke-width: .1rem;
}
.title {
fill: #ffebeb;
}
</style>
<svg>
<path id="Union" fill-rule="evenodd" clip-rule="evenodd" d="M584.924 352C566.379 596.253 442.233 717.371 312.762 721.625C314.849 722.912 315.945 724.404 315.439 725.873C314.85 727.582 313.363 728.819 311.349 729.634C313.835 731.14 315.947 732.306 317.185 732.541C324.33 733.901 329.242 736.83 328.72 740.738C326.639 756.297 285.436 758.859 279.246 744.483C277.43 740.263 282.545 736.546 290.185 734.22C291.876 733.706 291.976 731.183 291.936 728.476C288.699 727.054 286.268 725.043 285.663 722.579C285.504 721.933 285.607 721.353 285.928 720.839C157.97 709.163 31.5609 584.211 2.92421 352C-23.4665 138 133.209 0 293.924 0C454.639 0 600.034 153 584.924 352Z" fill="#C80E0E"/>
<circle class="shape invis" r="15px" cx="0px" cy="0px"></circle>
<text id="circleResize" class="wrap title" x="0px" y="110px" font-size="2rem">
Why is it so difficult to center text in a shape like this while specifying curved outer bounds?
</text>
</svg>
How can I get this working in Svelte??? 🥴
Working code
(With 👏 to #CD.. here on S.O., and #primos on Discord for their help!)
📝 The range slider and bound variables are just a bit of reactive fun to test moving the text and balloon together.
/public/index.html
<!doctype html>
<html>
<head>
<meta charset='utf8'>
<meta name='viewport' content='width=device-width'>
<title>Svelte app</title>
<link rel='icon' type='image/png' href='/favicon.png'>
<link rel='stylesheet' href='/global.css'>
<link rel='stylesheet' href='/bundle.css'>
<script src="https://d3plus.org/js/d3.js"></script> <!-- 👈 -->
<script src="https://d3plus.org/js/d3plus.js"></script> <!-- 👈 -->
<script defer src='/bundle.js'></script>
</head>
<body>
</body>
</html>
App.svelte
<script>
import { onMount } from 'svelte'; // 👈
onMount(() => { // 👈
d3plus.textwrap()
.container(d3.select("#circleResize"))
.resize(true)
.draw();
});
export let name;
let i = 0;
const minX = 293;
let windowWidth;
let skyHeight;
</script>
<svelte:window bind:innerWidth={windowWidth}/>
<style>
svg {
font-family: "Helvetica", "Arial", sans-serif;
height: 90%;
width: 100%;
background: transparent;
}
.type {
fill: #888;
text-anchor: middle;
}
.shape {
fill: red;
stroke: black;
}
.invis {
fill: transparent;
stroke: transparent;
stroke-width: .1rem;
}
.title {
fill: #ffebeb;
}
</style>
<label>
<input type="range" bind:value={i} max={windowWidth - (2 * minX)}>
</label>
<div>{i}</div>
<svg>
<path id="Union" fill-rule="evenodd" clip-rule="evenodd" transform="translate({i},0)" d="M584.924 352C566.379 596.253 442.233 717.371 312.762 721.625C314.849 722.912 315.945 724.404 315.439 725.873C314.85 727.582 313.363 728.819 311.349 729.634C313.835 731.14 315.947 732.306 317.185 732.541C324.33 733.901 329.242 736.83 328.72 740.738C326.639 756.297 285.436 758.859 279.246 744.483C277.43 740.263 282.545 736.546 290.185 734.22C291.876 733.706 291.976 731.183 291.936 728.476C288.699 727.054 286.268 725.043 285.663 722.579C285.504 721.933 285.607 721.353 285.928 720.839C157.97 709.163 31.5609 584.211 2.92421 352C-23.4665 138 133.209 0 293.924 0C454.639 0 600.034 153 584.924 352Z" fill="#C80E0E"/>
<circle class="shape invis" r="280px" cx="{minX}" cy="300px"></circle>
<text id="circleResize" class="wrap title" x="0px" y="110px" font-size="2rem" transform="translate({i},0)">
Why is it so difficult to center text in a shape like this while specifying curved outer bounds?
</text>
</svg>
I tried to adapt a codepen thing for waves with svgs.
Works just fine in Chrome, Safari and Edge, but not in Firefox (and IE, but I don't care too much about that).
I suspect some Syntax problem with the svg. The animation works just fine, but the svgs are not displayed correctly. In Firefox it's just a straight line instead of waves.
Anyone out there, that has an idea about that?
Thanks a lot in advance.
.waves {
width: 100%;
height: 7em;
position: relative;
overflow: hidden;
background-color: #f6f9fc;
}
.wave
{
width:calc( 100% + 4em );
height:100%;
position:absolute;
left:-2em;
background:bottom center repeat-x;
animation-iteration-count:infinite;
animation-timing-function:linear;
}
/* Individual wave layers */
.wave_1
{
animation-name:wave_1;
animation-duration:3400ms;
animation-delay:-1200ms;
z-index:2;
opacity: 1;
background-image:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="600" height="2000" viewBox="0 0 600 2000"><path fill-rule="evenodd" clip-rule="evenodd" fill="#fff" d="M600 2000c-100.8 0-141.6-39.892-240-39.892S98.4 2000 0 2000V0h6000v2000z"/></svg>');
background-position:bottom left;
background-color: #e0e7f1;
top: -3em;
}
.wave_2
{
z-index:1;
opacity: 1;
background-image:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="600" height="2000" viewBox="0 0 600 2000"><path fill-rule="evenodd" clip-rule="evenodd" fill="#e0e7f1" d="M600 2000c-100.8 0-141.6-39.892-240-39.892S98.4 2000 0 2000V0h6000v2000z"/></svg>');
background-position:bottom left;
background-color: #245aa6;
top: 0em;
}
#keyframes wave_1
{
from { transform: rotate(0deg) translatey(-0.61em) rotate(0deg) ; }
to { transform: rotate(360deg) translatey(-0.61em) rotate(-360deg) ; }
}
<div class="waves">
<div class="wave wave_1"></div>
<div class="wave wave_2"></div>
</div>
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>
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.