gpt4 book ai didi

javascript - 在 JavaScript 中创建随机 SVG 曲线同时避免急转弯

转载 作者:行者123 更新时间:2023-12-04 07:20:55 25 4
gpt4 key购买 nike

下面的代码片段在文档上绘制了一定次数的随机连接曲线:

function createPath() {
const
dimensions = getWindowDimensions(), svg = document.querySelector( `svg` ),
path = document.createElementNS( `http://www.w3.org/2000/svg`, `path` );

dimensions[0] = dimensions[0]; dimensions[1] = dimensions[1];
svg.appendChild( path );

path.setAttribute(
`d`,
`M ` +
`${getRandomNumber(dimensions[0])} `+`${getRandomNumber(dimensions[1])} `+
`C `+
`${getRandomNumber(dimensions[0])} `+`${getRandomNumber( dimensions[1])}, `+

`${getRandomNumber(dimensions[0])} `+`${getRandomNumber( dimensions[1])}, `+

`${getRandomNumber(dimensions[0])} `+`${getRandomNumber( dimensions[1])} `
)

for( let i = 0; i < 100; i++ ) {
path.setAttribute(
`d`,
path.getAttribute( `d` ) +
`S `+`${getRandomNumber(dimensions[0])} `+`${getRandomNumber(dimensions[1])},`+

`${getRandomNumber(dimensions[0])} `+`${getRandomNumber(dimensions[1])} `
)
}
}

setInterval( setSVGDimensions, 10 ); setInterval( positionPath, 10 );
createPath();
* { box-sizing: border-box; margin: 0; padding: 0; }
html, body { height: 100%; }
body {
display: flex; justify-content: center; align-items: center;
}
svg {
border-radius: 1rem; background-color: rgba( 95%,95%,95%,0.5 );
filter: blur( 1rem );

animation-name: blur; animation-duration: 1s;
animation-timing-function: ease-in-out; animation-fill-mode: forwards;

stroke-linecap: round; stroke-linejoin: round;
stroke-width: 0.25rem; fill: none;
}

@keyframes blur {
100% { filter: blur( 0rem ); }
}

path {
animation-name: grow;
animation-duration: 2500s;
animation-timing-function: cubic-bezier( 0.75,0.25,0.25,1 );

stroke-dasharray: 1000000;
stroke-dashoffset: 1000000;
stroke: rgba( 0%,100%,75%,0.75 );
}

@keyframes grow {
100% { stroke-dashoffset: 0; }
}
<svg></svg>
<script>
function getRandomNumber( max ) { return Math.floor( Math.random() * max ); }

function getWindowDimensions() {
const
dimensions = [],
windowWidth = document.documentElement.clientWidth,
windowHeight = document.documentElement.clientHeight;

dimensions.push( windowWidth, windowHeight );
return dimensions;
}

function setSVGDimensions() {
const
dimensions = getWindowDimensions(), svg = document.querySelector( `svg` );

svg.style.width = dimensions[0] - 10; svg.style.height = dimensions[1] - 10;
}

function positionPath() {
const
dimensions = getWindowDimensions(), path = document.querySelector( `path` );

path.setAttribute(
`transform`,
`
scale( 0.5 ) translate( ${ dimensions[0] / 2 },${ dimensions[1] / 3 } )
`
)
}
</script>

除了某些曲线的锐度之外,这是期望的行为。半径太小, Angular 太锐。我们想要更宽更平滑的曲线。例如,在此屏幕截图中,问题区域已被圈出。

在下图中,请注意红色圆圈具有非常尖锐的曲线,而绿色圆圈是更宽更平滑的曲线:

enter image description here

有没有办法我们可以使用 JavaScript 来防止创建尖锐的曲线(红色圆圈)并且让算法只创建更宽的曲线(绿色圆圈)?

最佳答案

我添加了一些函数来检查最后两点与下一个点之间的 Angular 是否不小于 MIN_ANGLE。现在是 60 度,但可以更宽以获得更大的曲线半径。

我还添加了 MIN_DISTANCE,因为两点之间的距离太短也会提供陡峭的曲线。

let lastTwoPoints = [];
const MIN_ANGLE = 60;
const MIN_DISTANCE = (Math.min(...getWindowDimensions()))/10;

function getPoint(){
let point = [getRandomNumber(getWindowDimensions()[0]),getRandomNumber(getWindowDimensions()[1])];

if(lastTwoPoints.length < 2){
lastTwoPoints.push(point);
} else {
if(getAngle(...lastTwoPoints, point) < MIN_ANGLE || getDistance(lastTwoPoints[1],point) < MIN_DISTANCE){
point = getPoint();
} else {
lastTwoPoints.shift();
lastTwoPoints.push(point);
}
}
return point;
}

function pointString(){
let point = getPoint();
return `${point[0]} ${point[1]} `;
}

function getDistance(pointA, pointB){
return Math.sqrt((pointA[0] - pointB[0])**2 + (pointA[1] - pointB[1])**2);
}

function getAngle(pointA, pointB, pointC){ // angle to pointB
let a = getDistance(pointA, pointB);
let b = getDistance(pointB, pointC);
let c = getDistance(pointC, pointA);
return Math.acos((a*a + b*b - c*c)/(2*a*b))*(180/Math.PI);
}

function createPath() {
const
dimensions = getWindowDimensions(), svg = document.querySelector( `svg` ),
path = document.createElementNS( `http://www.w3.org/2000/svg`, `path` );

dimensions[0] = dimensions[0]; dimensions[1] = dimensions[1];
svg.appendChild( path );

path.setAttribute(
`d`,
`M ` +
`${pointString()}`+
`C `+
`${pointString()}`+

`${pointString()}`+

`${pointString()}`
)


for( let i = 0; i < 100; i++ ) {
path.setAttribute(
`d`,
path.getAttribute( `d` ) +
`S `+`${pointString()}`+

`${pointString()}`
)
}
}

setInterval( setSVGDimensions, 10 ); setInterval( positionPath, 10 );
createPath();

function getRandomNumber( max ) { return Math.floor( Math.random() * max ); }

function getWindowDimensions() {
const
dimensions = [],
windowWidth = document.documentElement.clientWidth,
windowHeight = document.documentElement.clientHeight;

dimensions.push( windowWidth, windowHeight );
return dimensions;
}

function setSVGDimensions() {
const
dimensions = getWindowDimensions(), svg = document.querySelector( `svg` );

svg.style.width = dimensions[0] - 10; svg.style.height = dimensions[1] - 10;
}

function positionPath() {
const
dimensions = getWindowDimensions(), path = document.querySelector( `path` );

path.setAttribute(
`transform`,
`
scale( 0.5 ) translate( ${ dimensions[0] / 2 },${ dimensions[1] / 3 } )
`
)
}
* { box-sizing: border-box; margin: 0; padding: 0; }
html, body { height: 100%; }
body {
display: flex; justify-content: center; align-items: center;
}
svg {
border-radius: 1rem; background-color: rgba( 95%,95%,95%,0.5 );
filter: blur( 1rem );

animation-name: blur; animation-duration: 1s;
animation-timing-function: ease-in-out; animation-fill-mode: forwards;

stroke-linecap: round; stroke-linejoin: round;
stroke-width: 0.25rem; fill: none;
}

@keyframes blur {
100% { filter: blur( 0rem ); }
}

path {
animation-name: grow;
animation-duration: 2500s;
animation-timing-function: cubic-bezier( 0.75,0.25,0.25,1 );

stroke-dasharray: 1000000;
stroke-dashoffset: 1000000;
stroke: rgba( 0%,100%,75%,0.75 );
}

@keyframes grow {
100% { stroke-dashoffset: 0; }
}
<svg></svg>

我已经清理了代码,添加了 MAX_DISTANCE 来检查:

let lastTwoPoints = [];

const W = document.documentElement.clientWidth;
const H = document.documentElement.clientHeight;

const MIN_ANGLE = 60;
const MIN_DISTANCE = (Math.min(W,H))/20;
const MAX_DISTANCE = (Math.min(W,H))/4;

let svg = document.querySelector('svg');
let path = document.querySelector('path');

svg.style.width = W;
svg.style.height = H;

createPath();

function getPoint(){
let x = getRandomNumber(W*0.6) + W*0.2;
let y = getRandomNumber(H*0.6) + H*0.2;

let point = [x,y];

if(lastTwoPoints.length < 2){
lastTwoPoints.push(point);
} else {
if(getAngle(...lastTwoPoints, point) < MIN_ANGLE
|| getDistance(lastTwoPoints[1],point) < MIN_DISTANCE
|| getDistance(lastTwoPoints[1],point) > MAX_DISTANCE){
point = getPoint();
} else {
lastTwoPoints.shift();
lastTwoPoints.push(point);
}
}
return point;
}

function pointString(){
let point = getPoint();
return `${point[0]} ${point[1]} `;
}

function getDistance(pointA, pointB){
return Math.sqrt((pointA[0] - pointB[0])**2 + (pointA[1] - pointB[1])**2);
}

function getAngle(pointA, pointB, pointC){ // angle to pointB
let a = getDistance(pointA, pointB);
let b = getDistance(pointB, pointC);
let c = getDistance(pointC, pointA);
return Math.acos((a*a + b*b - c*c)/(2*a*b))*(180/Math.PI);
}

function createPath() {

let path_string = `M ${pointString()} C ${pointString()} ${pointString()} ${pointString()}`;

for( let i = 0; i < 100; i++ ) {
path_string += `S ${pointString()} ${pointString()} `
}

path.setAttribute('d', path_string);
}


function getRandomNumber(max) { return Math.floor( Math.random() * max ); }
<svg fill="none" stroke="black">
<path d=""/>
</svg>

关于javascript - 在 JavaScript 中创建随机 SVG 曲线同时避免急转弯,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68512066/

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