gpt4 book ai didi

javascript - d3 按路径设置动画组

转载 作者:行者123 更新时间:2023-12-03 07:05:37 26 4
gpt4 key购买 nike

这是我要加强的下一个问题 original question .

所以我正在尝试的是沿填充路径设置三 Angular 形标记和文本工具提示的动画。

var chart = d3.select("#speedometer");

const arc = d3
.arc()
.outerRadius(120)
.innerRadius(90)
.startAngle(-Math.PI / 2);

chart
.append("path")
.datum({
endAngle: Math.PI / 2
})
.attr("transform", "translate(160, 180)")
.attr("class", "background")
.style("fill", "#495270")
.attr("d", arc);

const mainGroup = chart.append('g')
.datum({
endAngle: -Math.PI / 2
});

const triangle = mainGroup
.append('path')
.attr("d", "M3.937,0,7.873,14H0Z")
.datum({
endAngle: -Math.PI / 2
})

const text = mainGroup.append('text')
.text('hello there')
.attr('transform', 'rotate(180)')
.datum({
endAngle: -Math.PI / 2
})
.transition()
.duration(3000)
.attrTween("transform", function(d) {
const topVal = (300 / 2 - 16);
const interpolate = d3.interpolate(d.endAngle, newAngle);
return function(t) {
const angleRadians = interpolate(t);
const angleDegrees = 360 * angleRadians / (2 * Math.PI);
return `
rotate(${angleDegrees})
`;
};

});

const newAngle = (70 / 100) * Math.PI - Math.PI / 2;

const foreground = chart
.append("path")
.datum({
endAngle: -Math.PI / 2
})
.style("fill", "rgb(50, 188, 228)")
.attr("transform", "translate(160, 180)")
.attr("d", arc);

foreground
.transition()
.duration(3000)
.attrTween("d", function(d) {
const interpolate = d3.interpolate(d.endAngle, newAngle);
return function(t) {
d.endAngle = interpolate(t);
return arc(d);
};
});

mainGroup
.transition()
.duration(3000)
.attrTween("transform", function(d) {
const topVal = (300 / 2 - 16);
const interpolate = d3.interpolate(d.endAngle, newAngle);
return function(t) {
const angleRadians = interpolate(t);
const angleDegrees = 360 * angleRadians / (2 * Math.PI);
return `
translate(158 176)
rotate(${angleDegrees + 180} 3.5 7)
translate(0 ${topVal})
`;
};
});

function pathTween(path) {
const length = path.node().getTotalLength(); // Get the length of the path
const r = d3.interpolate(0, length); // Set up interpolation from 0 to the path length
return function(t) {
const point = path.node().getPointAtLength(r(t)); // Get the next point along the path
d3
.select(this) // Select the circle
.attr("transform", `translate(${point.x}, ${point.y})`);
};
}
.main-wrapper {
max-width: 80%;
margin: 20px auto;
}

.element {
display: flex;
flex-flow: column nowrap;
margin-bottom: 20px;
border: 1px solid rgba(0, 0, 0, 0.4);
padding: 20px;
border-radius: 6px;
}

.element .title {
margin-bottom: 4px;
font-weight: 500;
}

.element .description {
margin-bottom: 10px;
color: rgba(0, 0, 0, 0.4);
}

#speedometer {
width: 300px;
height: 300px;
overflow: visible !important;
}

canvas {
width: 100%;
height: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.min.js"></script>
<div class="main-wrapper">
<section class="ui-section">
<div class="element">
<div class="title">
Speedometr
</div>

<div class="content">
<svg id="speedometer" viewbox="0 0 300 300"></svg>
</div>
</div>
</section>
</div>

所以这里的主要问题是旋转文本。它应该处于正常位置。在这种情况下动画应该如何?如何为整个组设置动画并控制每个节点??

最佳答案

首先,您可以通过对文本使用 180 - angleDegrees 而不是 angleDegrees 来抵消转动。

其次,您可能希望文本始终与圆弧的距离大致相同,不要太近以至于重叠,也不要太远因为看起来很奇怪。为此,一种解决方案是使节点 text-anchor: middle,然后在过渡期间定位它。

var chart = d3.select("#speedometer");

const arc = d3
.arc()
.outerRadius(120)
.innerRadius(90)
.startAngle(-Math.PI / 2);

chart
.append("path")
.datum({
endAngle: Math.PI / 2
})
.attr("transform", "translate(160, 180)")
.attr("class", "background")
.style("fill", "#495270")
.attr("d", arc);

const mainGroup = chart.append('g')
.datum({
endAngle: -Math.PI / 2
});

const triangle = mainGroup
.append('path')
.attr("d", "M3.937,0,7.873,14H0Z")
.datum({
endAngle: -Math.PI / 2
})

const text = mainGroup.append('text')
.text('hello there')
.datum({
endAngle: -Math.PI / 2
})
.attr("text-anchor", "middle") // to more easily position the text
.transition()
.duration(3000)
.attrTween("transform", function(d) {
const topVal = (300 / 2 - 16);
const interpolateAngle = d3.interpolate(d.endAngle, newAngle);

// We want to add some offset so the text is always easily visible
// Think about what happens when the following functions are called with
// angles -90, -45, 0, 45, 90
const textWidth = this.getBBox().width;
const offsetX = function(angle) {
return (angle / 90) * textWidth / 2;
};

const offsetY = function(angle) {
if (angle < 0) {
return offsetY(-angle);
}

// The -4 and -3 are a little bit trial and error, and can be
// tweaked further to
return -4 + (1 - angle / 90) * -3;
};

return function(t) {
const angleRadians = interpolateAngle(t);
const angleDegrees = 360 * angleRadians / (2 * Math.PI);

return `
translate(0 15)
rotate(${180 - angleDegrees})
translate(${offsetX(angleDegrees)} ${offsetY(angleDegrees)})
`;
};
});

const newAngle = (70 / 100) * Math.PI - Math.PI / 2;

const foreground = chart
.append("path")
.datum({
endAngle: -Math.PI / 2
})
.style("fill", "rgb(50, 188, 228)")
.attr("transform", "translate(160, 180)")
.attr("d", arc);

foreground
.transition()
.duration(3000)
.attrTween("d", function(d) {
const interpolate = d3.interpolate(d.endAngle, newAngle);
return function(t) {
d.endAngle = interpolate(t);
return arc(d);
};
});

mainGroup
.transition()
.duration(3000)
.attrTween("transform", function(d) {
const topVal = (300 / 2 - 16);
const interpolate = d3.interpolate(d.endAngle, newAngle);
return function(t) {
const angleRadians = interpolate(t);
const angleDegrees = 360 * angleRadians / (2 * Math.PI);
return `
translate(158 176)
rotate(${angleDegrees + 180} 3.5 7)
translate(0 ${topVal})
`;
};
});

function pathTween(path) {
const length = path.node().getTotalLength(); // Get the length of the path
const r = d3.interpolate(0, length); // Set up interpolation from 0 to the path length
return function(t) {
const point = path.node().getPointAtLength(r(t)); // Get the next point along the path
d3
.select(this) // Select the circle
.attr("transform", `translate(${point.x}, ${point.y})`);
};
}
.main-wrapper {
max-width: 80%;
margin: 20px auto;
}

.element {
display: flex;
flex-flow: column nowrap;
margin-bottom: 20px;
border: 1px solid rgba(0, 0, 0, 0.4);
padding: 20px;
border-radius: 6px;
}

.element .title {
margin-bottom: 4px;
font-weight: 500;
}

.element .description {
margin-bottom: 10px;
color: rgba(0, 0, 0, 0.4);
}

#speedometer {
width: 300px;
height: 300px;
overflow: visible !important;
}

canvas {
width: 100%;
height: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.min.js"></script>
<div class="main-wrapper">
<section class="ui-section">
<div class="element">
<div class="title">
Speedometr
</div>

<div class="content">
<svg id="speedometer" viewbox="0 0 300 300"></svg>
</div>
</div>
</section>
</div>

关于javascript - d3 按路径设置动画组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64959415/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com