随机生成千山万水动画

发布时间:2026/7/10 9:38:37

随机生成千山万水动画 !DOCTYPE html html langzh-CN head meta charsetutf-8 title千山万水/title style body { margin: 0; padding: 0; } #container { margin: 0; padding: 0; position:absolute; top:0; left:0; width:100%; height:100vh; overflow:hidden; background-color: #fff; box-shadow: 0 0 20px rgba(0, 0, 0, 0.5); background-color:#ff3333; } canvas { margin: 0; padding: 0; position:absolute; top:0; left:-100px; } svg{ margin: 0; padding: 0; position:absolute; top:0; left:0; } /style /head body !-- 千山万水 -- div idcontainer/div /body script // 使用SVG绘制山脉 // 画布高度和页面高度相同 let canvasHeightwindow.innerHeight; console.log(canvasHeight${canvasHeight}); //---------------------------- function generateMountainsCurvePoints (pointCount9,mtWidthBase30,mtWidthVariation120,mtHeightBase100,mtHeightVariation200) { // 生成随机的山脉曲线点 // 山脉曲线点数组 let mountainCurvePoints[]; // 起点 let currentX0; let currentYcanvasHeight; // 随机生成山脉曲线点 for (let i 0; i pointCount; i) { mountainCurvePoints.push([currentX,currentY]); //生成随机偏移量 //x偏移量限定区间100-200 let xOffsetMath.random()*mtWidthVariationmtWidthBase; currentXxOffset; //y值随机变幻区间 currentYMath.random()*mtHeightVariationmtHeightBase; currentYcanvasHeight-currentY; } // 终点 mountainCurvePoints.push([currentX100,canvasHeight]); // 返回结果数组 return mountainCurvePoints; } //---------------------------- // 绘制山脉 function drawMountains (canvasId,mountainCurvePoints,mtLineColorrgb(255,0,0,1),mtFillColorrgb(255,0,0,1),mtLineWidth1) { console.log(canvasId); // 获取Canvas元素 const canvas document.getElementById(canvasId); const ctx canvas.getContext(2d); // 设置Canvas布大小mountainCurvePoints最后一个点的x坐标决定 // 画布宽度由mountainCurvePoints最后一个点的x坐标决定 canvas.width mountainCurvePoints[mountainCurvePoints.length-1][0]; console.log(canvas.width${canvas.width}); canvas.height canvasHeight; // 设置背景颜色 ctx.fillStylergba(255,0,0,0); ctx.fillRect(0,0,canvas.width,canvas.height); // 绘制山脉曲线使用随机颜色 ctx.strokeStyle${mtLineColor}; ctx.lineWidthmtLineWidth; ctx.lineCapround; ctx.lineJoinround; ctx.beginPath(); ctx.moveTo(mountainCurvePoints[0][0], mountainCurvePoints[0][1]); for (let i 0; i mountainCurvePoints.length-1; i) { // ctx.lineTo(mountainCurvePoints[i][0], mountainCurvePoints[i][1]); //绘制圆滑曲线 const p0xmountainCurvePoints[Math.max(i-1,0)][0]; const p0ymountainCurvePoints[Math.max(i-1,0)][1]; const p1xmountainCurvePoints[i][0]; const p1ymountainCurvePoints[i][1]; const p2xmountainCurvePoints[i1][0]; const p2ymountainCurvePoints[i1][1]; const p3xmountainCurvePoints[Math.min(i2,mountainCurvePoints.length-1)][0]; const p3ymountainCurvePoints[Math.min(i2,mountainCurvePoints.length-1)][1]; //计算控制点 const tension0.15; const cp1xp1x(p2x-p0x)*tension; const cp1yp1y(p2y-p0y)*tension; const cp2xp1x(p3x-p1x)*tension; const cp2yp1y(p3y-p1y)*tension; ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, p2x, p2y); } //闭合曲线 ctx.closePath(); ctx.stroke(); //填充颜色 ctx.fillStyle${mtFillColor}; ctx.fill(); } //---------------------------- function drawMountainsSVG (canvasId,mountainCurvePoints,mtLineColorrgb(255,0,0,1),mtFillColorrgb(255,0,0,1),mtLineWidth1) { // 绘制山脉 //创建SVG元素svg const svg document.createElementNS(http://www.w3.org/2000/svg,svg); // 设置SVG元素的属性 svg.setAttribute(width,mountainCurvePoints[mountainCurvePoints.length-1][0]); svg.setAttribute(height,canvasHeight); svg.setAttribute(id,canvasId); // 设置SVG元素的属性 svg.setAttribute(viewBox,0 0 ${mountainCurvePoints[mountainCurvePoints.length-1][0]} ${canvasHeight}); // 创建path元素 const path document.createElementNS(http://www.w3.org/2000/svg,path); // 构造path文本字符串 let pathTextM ${mountainCurvePoints[0][0]} ${mountainCurvePoints[0][1]} ; // 按照mountainCurvePoints的坐标点绘制山脉曲线 for (let i 0; i mountainCurvePoints.length; i) { //构造path文本字符串 pathTextL ${mountainCurvePoints[i][0]} ${mountainCurvePoints[i][1]} ; } // 闭合曲线 pathTextZ; // 设置path元素的属性 path.setAttribute(d,pathText); // 绘制山脉曲线使用随机颜色 path.setAttribute(stroke,${mtLineColor}); path.setAttribute(stroke-width,${mtLineWidth}); path.setAttribute(stroke-linecap,round); path.setAttribute(stroke-linejoin,round); //添加linearGradient线性渐变填充 const linearGradient document.createElementNS(http://www.w3.org/2000/svg,linearGradient); linearGradient.setAttribute(id,linearGradientFill${canvasId}); linearGradient.setAttribute(x1,0%); linearGradient.setAttribute(y1,0%); linearGradient.setAttribute(x2,0%); linearGradient.setAttribute(y2,100%); const stop1 document.createElementNS(http://www.w3.org/2000/svg,stop); stop1.setAttribute(stop-color,${mtFillColor}); stop1.setAttribute(offset,0%); linearGradient.appendChild(stop1); const stop2 document.createElementNS(http://www.w3.org/2000/svg,stop); stop2.setAttribute(stop-color,orange); stop2.setAttribute(offset,100%); linearGradient.appendChild(stop2); // 添加linearGradient元素到svg元素 svg.appendChild(linearGradient); path.setAttribute(fill,url(#linearGradientFill${canvasId})); // 填充颜色 // path.setAttribute(fill,${mtFillColor}); // 添加path元素到svg元素 svg.appendChild(path); // 添加svg元素到container元素 document.getElementById(container).appendChild(svg); } //---------------------------- // 动画canvas水平平移动画循环 function moveMt(canvasId,speed10,stopGate1000000) { // 获取Canvas元素 let mt document.getElementById(canvasId); // 通过修改left属性实现水平平移动,left的属性无法直接获取,需要通过getComputedStyle()方法获取当前left值,, // 所能直接修改left属性,实现水平平移动 let mtLeftparseInt(getComputedStyle(mt).left); // console.log(canvas left:mtLeft); mt.style.leftmtLeft-speedpx; //动画循环 let animationIdrequestAnimationFrame((){ moveMt(canvasId,speed); }); // 触发结束循环的条件是left绝对值大于等于当前画布的宽度 // console.log(stopGate${stopGate}); if(mtLeft-stopGate){ console.log(${canvasId} 结束循环); cancelAnimationFrame(animationId); } } //---------------------------- // 绘制山脉 let pointCount10000; let mtWidthVariation50; let mtHeightVariation145; mtps0generateMountainsCurvePoints(pointCountpointCount,mtWidthBase30,mtWidthVariationmtWidthVariation,mtHeightBase870,mtHeightVariationmtHeightVariation); mtps1generateMountainsCurvePoints(pointCountpointCount,mtWidthBase30,mtWidthVariationmtWidthVariation,mtHeightBase800,mtHeightVariationmtHeightVariation); mtps2generateMountainsCurvePoints(pointCountpointCount,mtWidthBase30,mtWidthVariationmtWidthVariation,mtHeightBase720,mtHeightVariationmtHeightVariation); mtps3generateMountainsCurvePoints(pointCountpointCount,mtWidthBase30,mtWidthVariationmtWidthVariation,mtHeightBase630,mtHeightVariationmtHeightVariation); mtps4generateMountainsCurvePoints(pointCountpointCount,mtWidthBase30,mtWidthVariationmtWidthVariation,mtHeightBase530,mtHeightVariationmtHeightVariation); mtps5generateMountainsCurvePoints(pointCountpointCount,mtWidthBase30,mtWidthVariationmtWidthVariation,mtHeightBase420,mtHeightVariationmtHeightVariation); mtps6generateMountainsCurvePoints(pointCountpointCount,mtWidthBase30,mtWidthVariationmtWidthVariation,mtHeightBase320,mtHeightVariationmtHeightVariation); mtps7generateMountainsCurvePoints(pointCountpointCount,mtWidthBase30,mtWidthVariationmtWidthVariation,mtHeightBase200,mtHeightVariationmtHeightVariation); //---------------------------- //SVG模式绘制山脉 let mtFillColorList[#ff4444,#ff5555,#ff6666,#ff7777,#ff8888,#ff9999,#ffaaaa,#ffbbbb,#ffcccc,#ffdddd,#ffeeee,#ffffff]; drawMountainsSVG(canvas0,mtps0,mtLineColormtFillColorList[0],mtFillColormtFillColorList[0],mtLineWidth0); drawMountainsSVG(canvas1,mtps1,mtLineColormtFillColorList[1],mtFillColormtFillColorList[1],mtLineWidth0); drawMountainsSVG(canvas2,mtps2,mtLineColormtFillColorList[2],mtFillColormtFillColorList[2],mtLineWidth0); drawMountainsSVG(canvas3,mtps3,mtLineColormtFillColorList[3],mtFillColormtFillColorList[3],mtLineWidth0); drawMountainsSVG(canvas4,mtps4,mtLineColormtFillColorList[4],mtFillColormtFillColorList[4],mtLineWidth0); drawMountainsSVG(canvas5,mtps5,mtLineColormtFillColorList[5],mtFillColormtFillColorList[5],mtLineWidth0); drawMountainsSVG(canvas6,mtps6,mtLineColormtFillColorList[6],mtFillColormtFillColorList[6],mtLineWidth0); drawMountainsSVG(canvas7,mtps7,mtLineColormtFillColorList[7],mtFillColormtFillColorList[7],mtLineWidth0); /* //canvas模式绘制山脉 let mtFillColorList[#ff3333,#ff4444,#ff5555,#ff6666,#ff7777,#ff8888,#ff9999,#ffaaaa,#ffbbbb,#ffcccc]; drawMountains(canvas0,mtps0,mtLineColormtFillColorList[0],mtFillColormtFillColorList[0],mtLineWidth0); drawMountains(canvas1,mtps1,mtLineColormtFillColorList[1],mtFillColormtFillColorList[1],mtLineWidth0); drawMountains(canvas2,mtps2,mtLineColormtFillColorList[2],mtFillColormtFillColorList[2],mtLineWidth0); drawMountains(canvas3,mtps3,mtLineColormtFillColorList[3],mtFillColormtFillColorList[3],mtLineWidth0); drawMountains(canvas4,mtps4,mtLineColormtFillColorList[4],mtFillColormtFillColorList[4],mtLineWidth0); drawMountains(canvas5,mtps5,mtLineColormtFillColorList[5],mtFillColormtFillColorList[5],mtLineWidth0); drawMountains(canvas6,mtps6,mtLineColormtFillColorList[6],mtFillColormtFillColorList[6],mtLineWidth0); drawMountains(canvas7,mtps7,mtLineColormtFillColorList[7],mtFillColormtFillColorList[7],mtLineWidth0); */ //---------------------------- // 调用动画函数 moveMt(canvas0,speed1); moveMt(canvas1,speed2); moveMt(canvas2,speed3); moveMt(canvas3,speed4); moveMt(canvas4,speed5); moveMt(canvas5,speed6); moveMt(canvas6,speed7); moveMt(canvas7,speed8); /script /html精简圆滑曲线版!DOCTYPE html html langzh-CN head meta charsetutf-8 title千山万水/title style body { margin: 0; padding: 0; } #container { margin: 0; padding: 0; position:absolute; top:0; left:0; width:100%; height:100vh; overflow:hidden; background-color: #fff; box-shadow: 0 0 20px rgba(0, 0, 0, 0.5); background-color:#ff3333; } canvas { margin: 0; padding: 0; position:absolute; top:0; left:-100px; } svg{ margin: 0; padding: 0; position:absolute; top:0; left:0; } /style /head body !-- 千山万水 -- div idcontainer/div /body script // 使用SVG绘制山脉 // 画布高度和页面高度相同 let canvasHeightwindow.innerHeight; console.log(canvasHeight${canvasHeight}); //---------------------------- function generateMountainsCurvePoints (pointCount9,mtWidthBase30,mtWidthVariation120,mtHeightBase100,mtHeightVariation200) { // 生成随机的山脉曲线点 // 山脉曲线点数组 let mountainCurvePoints[]; // 起点 let currentX0; let currentYcanvasHeight; // 随机生成山脉曲线点 for (let i 0; i pointCount; i) { mountainCurvePoints.push([currentX,currentY]); //生成随机偏移量 //x偏移量限定区间100-200 let xOffsetMath.random()*mtWidthVariationmtWidthBase; currentXxOffset; //y值随机变幻区间 currentYMath.random()*mtHeightVariationmtHeightBase; currentYcanvasHeight-currentY; } // 终点 mountainCurvePoints.push([currentX100,canvasHeight]); // 返回结果数组 return mountainCurvePoints; } //---------------------------- //---------------------------- function drawMountainsSVG (canvasId,mountainCurvePoints,mtLineColorrgb(255,0,0,1),mtFillColorrgb(255,0,0,1),mtLineWidth1) { // 绘制山脉 //创建SVG元素svg const svg document.createElementNS(http://www.w3.org/2000/svg,svg); // 设置SVG元素的属性 svg.setAttribute(width,mountainCurvePoints[mountainCurvePoints.length-1][0]); svg.setAttribute(height,canvasHeight); svg.setAttribute(id,canvasId); // 设置SVG元素的属性 svg.setAttribute(viewBox,0 0 ${mountainCurvePoints[mountainCurvePoints.length-1][0]} ${canvasHeight}); // 创建path元素 const path document.createElementNS(http://www.w3.org/2000/svg,path); // 构造path文本字符串 let pathTextM ${mountainCurvePoints[0][0]} ${mountainCurvePoints[0][1]} ; // 按照mountainCurvePoints的坐标点绘制山脉曲线 for (let i 0; i mountainCurvePoints.length-1; i) { //构造path文本字符串 // pathTextL ${mountainCurvePoints[i][0]} ${mountainCurvePoints[i][1]} ; // 绘制圆滑曲线使用三次贝塞尔曲线 const p0 mountainCurvePoints[i]; const p1 mountainCurvePoints[i 1]; const cp1 { x: (p0[0] p1[0]) / 2, y: p0[1] }; // 控制点1通常在两个点之间垂直于线段的中点 const cp2 { x: (p0[0] p1[0]) / 2, y: p1[1] }; // 控制点2通常在两个点之间垂直于线段的中点但稍微偏移以避免直线连接 if (i 0) { pathText M ${p0[0]} ${p0[1]}; // Move to the first point } else { pathText C ${cp1.x} ${cp1.y}, ${cp2.x} ${cp2.y}, ${p1[0]} ${p1[1]} ; // Cubic Bezier curve to the next point } } // 闭合曲线 pathTextZ; // 设置path元素的属性 path.setAttribute(d,pathText); // 绘制山脉曲线使用随机颜色 path.setAttribute(stroke,${mtLineColor}); path.setAttribute(stroke-width,${mtLineWidth}); path.setAttribute(stroke-linecap,round); path.setAttribute(stroke-linejoin,round); //添加linearGradient线性渐变填充 const linearGradient document.createElementNS(http://www.w3.org/2000/svg,linearGradient); linearGradient.setAttribute(id,linearGradientFill${canvasId}); linearGradient.setAttribute(x1,0%); linearGradient.setAttribute(y1,0%); linearGradient.setAttribute(x2,0%); linearGradient.setAttribute(y2,100%); const stop1 document.createElementNS(http://www.w3.org/2000/svg,stop); stop1.setAttribute(stop-color,${mtFillColor}); stop1.setAttribute(offset,0%); linearGradient.appendChild(stop1); const stop2 document.createElementNS(http://www.w3.org/2000/svg,stop); stop2.setAttribute(stop-color,orange); stop2.setAttribute(offset,100%); linearGradient.appendChild(stop2); // 添加linearGradient元素到svg元素 svg.appendChild(linearGradient); // 填充颜色 // path.setAttribute(fill,${mtFillColor}); path.setAttribute(fill,url(#linearGradientFill${canvasId})); // 添加path元素到svg元素 svg.appendChild(path); // 添加svg元素到container元素 document.getElementById(container).appendChild(svg); } //---------------------------- // 动画canvas水平平移动画循环 function moveMt(canvasId,speed10,stopGate1000000) { // 获取Canvas元素 let mt document.getElementById(canvasId); // 通过修改left属性实现水平平移动,left的属性无法直接获取,需要通过getComputedStyle()方法获取当前left值,, // 所能直接修改left属性,实现水平平移动 let mtLeftparseInt(getComputedStyle(mt).left); // console.log(canvas left:mtLeft); mt.style.leftmtLeft-speedpx; //动画循环 let animationIdrequestAnimationFrame((){ moveMt(canvasId,speed); }); // 触发结束循环的条件是left绝对值大于等于当前画布的宽度 // console.log(stopGate${stopGate}); if(mtLeft-stopGate){ console.log(${canvasId} 结束循环); cancelAnimationFrame(animationId); } } //---------------------------- // 绘制山脉 let pointCount10000; let mtWidthVariation50; let mtHeightVariation145; mtps0generateMountainsCurvePoints(pointCountpointCount,mtWidthBase30,mtWidthVariationmtWidthVariation,mtHeightBase870,mtHeightVariationmtHeightVariation); mtps1generateMountainsCurvePoints(pointCountpointCount,mtWidthBase30,mtWidthVariationmtWidthVariation,mtHeightBase800,mtHeightVariationmtHeightVariation); mtps2generateMountainsCurvePoints(pointCountpointCount,mtWidthBase30,mtWidthVariationmtWidthVariation,mtHeightBase720,mtHeightVariationmtHeightVariation); mtps3generateMountainsCurvePoints(pointCountpointCount,mtWidthBase30,mtWidthVariationmtWidthVariation,mtHeightBase630,mtHeightVariationmtHeightVariation); mtps4generateMountainsCurvePoints(pointCountpointCount,mtWidthBase30,mtWidthVariationmtWidthVariation,mtHeightBase530,mtHeightVariationmtHeightVariation); mtps5generateMountainsCurvePoints(pointCountpointCount,mtWidthBase30,mtWidthVariationmtWidthVariation,mtHeightBase420,mtHeightVariationmtHeightVariation); mtps6generateMountainsCurvePoints(pointCountpointCount,mtWidthBase30,mtWidthVariationmtWidthVariation,mtHeightBase320,mtHeightVariationmtHeightVariation); mtps7generateMountainsCurvePoints(pointCountpointCount,mtWidthBase30,mtWidthVariationmtWidthVariation,mtHeightBase200,mtHeightVariationmtHeightVariation); //---------------------------- //SVG模式绘制山脉 let mtFillColorList[#ff4444,#ff5555,#ff6666,#ff7777,#ff8888,#ff9999,#ffaaaa,#ffbbbb,#ffcccc,#ffdddd,#ffeeee,#ffffff]; drawMountainsSVG(canvas0,mtps0,mtLineColormtFillColorList[0],mtFillColormtFillColorList[0],mtLineWidth0); drawMountainsSVG(canvas1,mtps1,mtLineColormtFillColorList[1],mtFillColormtFillColorList[1],mtLineWidth0); drawMountainsSVG(canvas2,mtps2,mtLineColormtFillColorList[2],mtFillColormtFillColorList[2],mtLineWidth0); drawMountainsSVG(canvas3,mtps3,mtLineColormtFillColorList[3],mtFillColormtFillColorList[3],mtLineWidth0); drawMountainsSVG(canvas4,mtps4,mtLineColormtFillColorList[4],mtFillColormtFillColorList[4],mtLineWidth0); drawMountainsSVG(canvas5,mtps5,mtLineColormtFillColorList[5],mtFillColormtFillColorList[5],mtLineWidth0); drawMountainsSVG(canvas6,mtps6,mtLineColormtFillColorList[6],mtFillColormtFillColorList[6],mtLineWidth0); drawMountainsSVG(canvas7,mtps7,mtLineColormtFillColorList[7],mtFillColormtFillColorList[7],mtLineWidth0); //---------------------------- // 调用动画函数 moveMt(canvas0,speed1); moveMt(canvas1,speed2); moveMt(canvas2,speed3); moveMt(canvas3,speed4); moveMt(canvas4,speed5); moveMt(canvas5,speed6); moveMt(canvas6,speed7); moveMt(canvas7,speed8); /script /html

相关新闻