带有百分比值的 svg stroke-dashoffset 动画
svg stroke-dashoffset animation with percentage values
我已经成功地为 stroke-dashoffset
设置了动画,其值为 <length>
,如下所示
const svg = document.querySelector("svg");
// variable for the namespace
const svgns = "http://www.w3.org/2000/svg"
//assigning svg element attribute
svg.setAttribute('class', 'layer1');
svg.setAttribute('xmlns', svgns);
svg.setAttribute('viewBox', '0 0 400 200');
//make background
var fill1 = '#e6e6e6';
let bg = document.createElementNS(svgns, 'rect');
bg.setAttribute('class', 'bg');
bg.setAttribute('id', 'bg');
bg.setAttribute('width', '400');
bg.setAttribute('height', '200');
bg.setAttribute('fill', fill1);
svg.appendChild(bg);
//wrapper dimension
var x = 20;
var y = 50;
var width = 200;
var height = 50;
let wrapper = document.createElementNS(svgns, 'rect');
wrapper.setAttribute('class', 'wrapper');
wrapper.setAttribute('id', 'wrapper');
wrapper.setAttribute('x', x);
wrapper.setAttribute('y', y);
wrapper.setAttribute('width', width);
wrapper.setAttribute('height', height);
wrapper.setAttribute('fill', 'none');
wrapper.setAttribute('stroke', 'black');
wrapper.setAttribute('stroke-width', '1');
svg.appendChild(wrapper);
let tube = document.createElementNS(svgns, 'line');
tube.setAttribute('class', 'tube');
tube.setAttribute('id', 'tube');
tube.setAttribute('x1', x);
tube.setAttribute('x2', x + width);
tube.setAttribute('y1', y + height / 2);
tube.setAttribute('y2', y + height / 2);
tube.setAttribute('stroke', 'brown');
tube.setAttribute('stroke-width', '1');
svg.appendChild(tube);
var ln = document.querySelector("#tube");
var path = ln.getTotalLength();
ln.style.setProperty("--off", path + 'px');
var pct = 0.60;
var pxl = path - (path * pct);
ln.style.setProperty('--offset', pxl);
ln.style.setProperty('--v1', (path / svg.viewBox.baseVal.width) * 100 + '%');
ln.style.setProperty('--v2', (pxl / svg.viewBox.baseVal.width) * 100 + '%');
var gridNum = 10;
var gridStart = width / gridNum;
var counter = gridStart;
for (var i = 0; i < gridNum; i++) {
let ln = document.createElementNS(svgns, 'line');
ln.setAttribute('class', 'axisLines' + i);
ln.setAttribute('id', 'axisLines' + i);
var x1 = x + counter;
ln.setAttribute('x1', x1);
ln.setAttribute('x2', x + counter);
ln.setAttribute('y1', y);
ln.setAttribute('y2', y + height);
((gridNum / 2) - 1) == i ? ln.setAttribute('stroke', 'red') : ln.setAttribute('stroke', 'green');
ln.setAttribute('stroke-width', '1.5');
svg.appendChild(ln);
counter = counter + gridStart;
let tl = document.createElementNS(svgns, 'title');
((gridNum / 2) - 1) == i ? tl.textContent = `Middle Coordinate ${x1-x},${y}` : tl.textContent = `Coordinate ${x1-x},${y}`;
svg.appendChild(tl);
ln.appendChild(tl);
}
.tube {
stroke-dasharray: var(--off);
stroke-dashoffset: var(--off);
animation: effect 4s ease-out infinite forwards;
}
@keyframes effect {
100% {
stroke-dashoffset: var(--offset);
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<link rel="stylesheet" href="style.css">
</link>
<svg>
<script href="index.js"></script>
</svg>
</body>
</html>
但是,如果我决定使用 <percentage>
而不是 value
,我想弄清楚如何计算 css 中的确切 %
值。
我从这个 了解到百分比是根据当前视口计算的,我试过
ln.style.setProperty('--v1', (path / svg.viewBox.baseVal.width) * 100 + '%');
和
ln.style.setProperty('--v2', (pxl / svg.viewBox.baseVal.width) * 100 + '%');
但是将上面的内容传递给 CSS 如下不会产生相同的动画
.tube {
stroke-dasharray: var(--v1);
stroke-dashoffset: var(--v1);
animation: effect 4s ease-out infinite forwards;
}
@keyframes effect {
100% {
stroke-dashoffset: var(--v2);
}
}
您需要计算normalised hypotenuse of the width and the height。
const svg = document.querySelector("svg");
// variable for the namespace
const svgns = "http://www.w3.org/2000/svg"
//assigning svg element attribute
svg.setAttribute('class', 'layer1');
svg.setAttribute('xmlns', svgns);
svg.setAttribute('viewBox', '0 0 400 200');
//make background
var fill1 = '#e6e6e6';
let bg = document.createElementNS(svgns, 'rect');
bg.setAttribute('class', 'bg');
bg.setAttribute('id', 'bg');
bg.setAttribute('width', '400');
bg.setAttribute('height', '200');
bg.setAttribute('fill', fill1);
svg.appendChild(bg);
//wrapper dimension
var x = 20;
var y = 50;
var width = 200;
var height = 50;
let wrapper = document.createElementNS(svgns, 'rect');
wrapper.setAttribute('class', 'wrapper');
wrapper.setAttribute('id', 'wrapper');
wrapper.setAttribute('x', x);
wrapper.setAttribute('y', y);
wrapper.setAttribute('width', width);
wrapper.setAttribute('height', height);
wrapper.setAttribute('fill', 'none');
wrapper.setAttribute('stroke', 'black');
wrapper.setAttribute('stroke-width', '1');
svg.appendChild(wrapper);
let tube = document.createElementNS(svgns, 'line');
tube.setAttribute('class', 'tube');
tube.setAttribute('id', 'tube');
tube.setAttribute('x1', x);
tube.setAttribute('x2', x + width);
tube.setAttribute('y1', y + height / 2);
tube.setAttribute('y2', y + height / 2);
tube.setAttribute('stroke', 'brown');
tube.setAttribute('stroke-width', '1');
svg.appendChild(tube);
var ln = document.querySelector("#tube");
var path = ln.getTotalLength();
ln.style.setProperty("--off", path + 'px');
var pct = 0.60;
var pxl = path - (path * pct);
ln.style.setProperty('--offset', pxl);
let normalised_hypotenuse = Math.sqrt(svg.viewBox.baseVal.width ** 2 + svg.viewBox.baseVal.height ** 2) / Math.sqrt(2);
ln.style.setProperty('--v1', (path / normalised_hypotenuse) * 100 + '%');
ln.style.setProperty('--v2', (pxl / normalised_hypotenuse) * 100 + '%');
var gridNum = 10;
var gridStart = width / gridNum;
var counter = gridStart;
for (var i = 0; i < gridNum; i++) {
let ln = document.createElementNS(svgns, 'line');
ln.setAttribute('class', 'axisLines' + i);
ln.setAttribute('id', 'axisLines' + i);
var x1 = x + counter;
ln.setAttribute('x1', x1);
ln.setAttribute('x2', x + counter);
ln.setAttribute('y1', y);
ln.setAttribute('y2', y + height);
((gridNum / 2) - 1) == i ? ln.setAttribute('stroke', 'red') : ln.setAttribute('stroke', 'green');
ln.setAttribute('stroke-width', '1.5');
svg.appendChild(ln);
counter = counter + gridStart;
let tl = document.createElementNS(svgns, 'title');
((gridNum / 2) - 1) == i ? tl.textContent = `Middle Coordinate ${x1-x},${y}` : tl.textContent = `Coordinate ${x1-x},${y}`;
svg.appendChild(tl);
ln.appendChild(tl);
}
.tube {
stroke-dasharray: var(--v1);
stroke-dashoffset: var(--v1);
animation: effect 4s ease-out infinite forwards;
}
@keyframes effect {
100% {
stroke-dashoffset: var(--v2);
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<link rel="stylesheet" href="style.css">
</link>
<svg>
<script href="index.js"></script>
</svg>
</body>
</html>
我已经成功地为 stroke-dashoffset
设置了动画,其值为 <length>
,如下所示
const svg = document.querySelector("svg");
// variable for the namespace
const svgns = "http://www.w3.org/2000/svg"
//assigning svg element attribute
svg.setAttribute('class', 'layer1');
svg.setAttribute('xmlns', svgns);
svg.setAttribute('viewBox', '0 0 400 200');
//make background
var fill1 = '#e6e6e6';
let bg = document.createElementNS(svgns, 'rect');
bg.setAttribute('class', 'bg');
bg.setAttribute('id', 'bg');
bg.setAttribute('width', '400');
bg.setAttribute('height', '200');
bg.setAttribute('fill', fill1);
svg.appendChild(bg);
//wrapper dimension
var x = 20;
var y = 50;
var width = 200;
var height = 50;
let wrapper = document.createElementNS(svgns, 'rect');
wrapper.setAttribute('class', 'wrapper');
wrapper.setAttribute('id', 'wrapper');
wrapper.setAttribute('x', x);
wrapper.setAttribute('y', y);
wrapper.setAttribute('width', width);
wrapper.setAttribute('height', height);
wrapper.setAttribute('fill', 'none');
wrapper.setAttribute('stroke', 'black');
wrapper.setAttribute('stroke-width', '1');
svg.appendChild(wrapper);
let tube = document.createElementNS(svgns, 'line');
tube.setAttribute('class', 'tube');
tube.setAttribute('id', 'tube');
tube.setAttribute('x1', x);
tube.setAttribute('x2', x + width);
tube.setAttribute('y1', y + height / 2);
tube.setAttribute('y2', y + height / 2);
tube.setAttribute('stroke', 'brown');
tube.setAttribute('stroke-width', '1');
svg.appendChild(tube);
var ln = document.querySelector("#tube");
var path = ln.getTotalLength();
ln.style.setProperty("--off", path + 'px');
var pct = 0.60;
var pxl = path - (path * pct);
ln.style.setProperty('--offset', pxl);
ln.style.setProperty('--v1', (path / svg.viewBox.baseVal.width) * 100 + '%');
ln.style.setProperty('--v2', (pxl / svg.viewBox.baseVal.width) * 100 + '%');
var gridNum = 10;
var gridStart = width / gridNum;
var counter = gridStart;
for (var i = 0; i < gridNum; i++) {
let ln = document.createElementNS(svgns, 'line');
ln.setAttribute('class', 'axisLines' + i);
ln.setAttribute('id', 'axisLines' + i);
var x1 = x + counter;
ln.setAttribute('x1', x1);
ln.setAttribute('x2', x + counter);
ln.setAttribute('y1', y);
ln.setAttribute('y2', y + height);
((gridNum / 2) - 1) == i ? ln.setAttribute('stroke', 'red') : ln.setAttribute('stroke', 'green');
ln.setAttribute('stroke-width', '1.5');
svg.appendChild(ln);
counter = counter + gridStart;
let tl = document.createElementNS(svgns, 'title');
((gridNum / 2) - 1) == i ? tl.textContent = `Middle Coordinate ${x1-x},${y}` : tl.textContent = `Coordinate ${x1-x},${y}`;
svg.appendChild(tl);
ln.appendChild(tl);
}
.tube {
stroke-dasharray: var(--off);
stroke-dashoffset: var(--off);
animation: effect 4s ease-out infinite forwards;
}
@keyframes effect {
100% {
stroke-dashoffset: var(--offset);
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<link rel="stylesheet" href="style.css">
</link>
<svg>
<script href="index.js"></script>
</svg>
</body>
</html>
但是,如果我决定使用 <percentage>
而不是 value
,我想弄清楚如何计算 css 中的确切 %
值。
我从这个 ln.style.setProperty('--v1', (path / svg.viewBox.baseVal.width) * 100 + '%');
和
ln.style.setProperty('--v2', (pxl / svg.viewBox.baseVal.width) * 100 + '%');
但是将上面的内容传递给 CSS 如下不会产生相同的动画
.tube {
stroke-dasharray: var(--v1);
stroke-dashoffset: var(--v1);
animation: effect 4s ease-out infinite forwards;
}
@keyframes effect {
100% {
stroke-dashoffset: var(--v2);
}
}
您需要计算normalised hypotenuse of the width and the height。
const svg = document.querySelector("svg");
// variable for the namespace
const svgns = "http://www.w3.org/2000/svg"
//assigning svg element attribute
svg.setAttribute('class', 'layer1');
svg.setAttribute('xmlns', svgns);
svg.setAttribute('viewBox', '0 0 400 200');
//make background
var fill1 = '#e6e6e6';
let bg = document.createElementNS(svgns, 'rect');
bg.setAttribute('class', 'bg');
bg.setAttribute('id', 'bg');
bg.setAttribute('width', '400');
bg.setAttribute('height', '200');
bg.setAttribute('fill', fill1);
svg.appendChild(bg);
//wrapper dimension
var x = 20;
var y = 50;
var width = 200;
var height = 50;
let wrapper = document.createElementNS(svgns, 'rect');
wrapper.setAttribute('class', 'wrapper');
wrapper.setAttribute('id', 'wrapper');
wrapper.setAttribute('x', x);
wrapper.setAttribute('y', y);
wrapper.setAttribute('width', width);
wrapper.setAttribute('height', height);
wrapper.setAttribute('fill', 'none');
wrapper.setAttribute('stroke', 'black');
wrapper.setAttribute('stroke-width', '1');
svg.appendChild(wrapper);
let tube = document.createElementNS(svgns, 'line');
tube.setAttribute('class', 'tube');
tube.setAttribute('id', 'tube');
tube.setAttribute('x1', x);
tube.setAttribute('x2', x + width);
tube.setAttribute('y1', y + height / 2);
tube.setAttribute('y2', y + height / 2);
tube.setAttribute('stroke', 'brown');
tube.setAttribute('stroke-width', '1');
svg.appendChild(tube);
var ln = document.querySelector("#tube");
var path = ln.getTotalLength();
ln.style.setProperty("--off", path + 'px');
var pct = 0.60;
var pxl = path - (path * pct);
ln.style.setProperty('--offset', pxl);
let normalised_hypotenuse = Math.sqrt(svg.viewBox.baseVal.width ** 2 + svg.viewBox.baseVal.height ** 2) / Math.sqrt(2);
ln.style.setProperty('--v1', (path / normalised_hypotenuse) * 100 + '%');
ln.style.setProperty('--v2', (pxl / normalised_hypotenuse) * 100 + '%');
var gridNum = 10;
var gridStart = width / gridNum;
var counter = gridStart;
for (var i = 0; i < gridNum; i++) {
let ln = document.createElementNS(svgns, 'line');
ln.setAttribute('class', 'axisLines' + i);
ln.setAttribute('id', 'axisLines' + i);
var x1 = x + counter;
ln.setAttribute('x1', x1);
ln.setAttribute('x2', x + counter);
ln.setAttribute('y1', y);
ln.setAttribute('y2', y + height);
((gridNum / 2) - 1) == i ? ln.setAttribute('stroke', 'red') : ln.setAttribute('stroke', 'green');
ln.setAttribute('stroke-width', '1.5');
svg.appendChild(ln);
counter = counter + gridStart;
let tl = document.createElementNS(svgns, 'title');
((gridNum / 2) - 1) == i ? tl.textContent = `Middle Coordinate ${x1-x},${y}` : tl.textContent = `Coordinate ${x1-x},${y}`;
svg.appendChild(tl);
ln.appendChild(tl);
}
.tube {
stroke-dasharray: var(--v1);
stroke-dashoffset: var(--v1);
animation: effect 4s ease-out infinite forwards;
}
@keyframes effect {
100% {
stroke-dashoffset: var(--v2);
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<link rel="stylesheet" href="style.css">
</link>
<svg>
<script href="index.js"></script>
</svg>
</body>
</html>