算法【动态规划】——前端实践:类金字塔

需求描述:用csstransparent属性渲染三角形和梯形,根据传入的参数,动态渲染类金字塔结构的图形。如下:

类金字塔图形

<style>
/* 三角形 */
#Triangle{
	width: 0px;
	border-left: 15px solid transparent;
	border-right: 15px solid transparent;
	border-bottom: 30px solid grey;
}
/* 梯形 */
#Trapezoid{
	width: 10px;
	border-left: 10px solid transparent;
	border-right: 10px solid transparent;
	border-bottom: 30px solid grey;
}
</style>
<!-- 一个简单的三角形 -->
<div id="Triangle"></div>
<!-- 一个简单的梯形 -->
<div id="Trapezoid"></div>

效果如下:
三角形、梯形
分析过程:(设第n个图形的上底为Xn,下底为Yn,高恒为h,两个图形之间的距离恒为d,倾斜角度为α)
则css的属性值与图形各个长度的对应关系为:

width: (Xn)px;
height: (d)px;
border-left: (t)px solid transparent;
border-right: (t)px solid transparent;
border-bottom: (h)px solid grey;

/* 相关计算公式如下:
 t = (Yn - Xn)/ 2 
 tanα = t / h 
*/

需由上关系推出Xn,Yn与用户已输入的参数之间的关系:
用户输入的参数

  1. 当n = 1,X1 = x, Y1 = y,t = (Y1-X1) / 2
  2. 当n = 2,X2 = Y1 + (2td) / h,Y2 = X2 + 2t,t2 = t1
  3. 当n = 3,X3 = Y2 + (2td) / h,Y3 = X3 + 2t,t3 = t1
  4. Xn = Y(n-1) + (2td) / h, Yn = Xn + 2t, tn = t1
  5. 由此得出状态公式:
    若n = 1,Xn = x,Yn = y,tn = (y-x) * 0.5
    若n > 1,Xn = Y(n-1) + ((y-x) * d) / h,Yn = Xn + (y-x),tn = (y-x) * 0.5

完整详细代码如下:

<html lang="en">
    <head>
        <title>算法【动态规划】——前端实践:类金字塔</title>
    </head>
    <style>
        /* 分割线 */
        .divider{
            width: 100%;
            height: 10px;
        }
        /* 平行四边形 */
        #Paralle{
            width: 30px;
            height: 20px;
            background-color: grey;
            transform: skew(-25deg);
        }
        /* 三角形 */
        #Triangle{
            width: 0px;
            border-left: 15px solid transparent;
            border-right: 15px solid transparent;
            border-bottom: 30px solid grey;
        }
        /* 梯形 */
        #Trapezoid{
            width: 10px;
            border-left: 10px solid transparent;
            border-right: 10px solid transparent;
            border-bottom: 30px solid grey;
        }
        /* 比例: 4 height:10px  width:【30, 50, 70, 90, 110, 130, 150】 border-bottom:30px  border-left:7.5px*/
        /* 比例:3.5 height:12px width:【40, 64, 88, 112, 136, 150, 174】border-bottom:30px  border-left:8.6px*/
        /* 类金字塔 */
        #Pyramid{
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
        }
    </style>
    <body>
        <!-- 平行四边形 -->
        <div id="Paralle"></div>
        <!-- 分隔间距 -->
        <div class="divider"></div>

        <!-- 三角形 -->
        <div id="Triangle"></div>
        <!-- 分隔间距 -->
        <div class="divider"></div>

        <!-- 梯形 -->
        <div id="Trapezoid"></div>
        <!-- 分隔间距 -->
        <div class="divider"></div>
        
        <!-- 类金字塔  -->
        <div id="Pyramid"></div>
    </body>
    <script>
        window.onload = this.drawPyramid({
            x: 0,  //第一个图形的上底(较短的边),为0时表示第一个图形为三角形
            y: 20, //第一个图形的下底(较长的边)
            h: 10, //图形的高
            d: 5, //相邻图形之间的距离
            start: 1,  // 从第几个图形开始渲染
            account: 7, // 生成图形盒子总的个数
            inverted: false,  // 是否倒金字塔
        });

        /**
         * 开始生成 box DOM节点
         * @param { account }  生成图形盒子总的个数
         * 第一个图形:上底(x) 下底(y), 高(h), 两个相邻邻图形之间的距离(d), 半下底-半上底(t)
         * inverted: true-'倒金字塔' false-'正金字塔'
        */
        function drawPyramid({account=1, inverted=false, x=0, y=20, h=10, d=5, start=1}){
            let dom = document.getElementById("Pyramid");
            if(!dom || account<1 || x<0 || y<0 || y<=x || h<0 || start < 1) return ; // 异常处理
            let arr = [];  // 存放各个图形的属性值
            let lastX = x, lastY = y, t = (y-x) * 0.5;
            for(let i = start-1;  i < account+start; ++i){  // 正逆序金字塔属性处理
                let Xn = lastX,  Yn = lastY ; 
                if( i != 0) {
                    Xn = lastY + ((y-x)*d)/h; // 根据上一个图形的状态得到当前状态的值
                    Yn = Xn + (y-x);    // 根据上一个图形的状态得到当前状态的值
                }
                lastX = Xn;lastY = Yn;   // 保留当前图形的状态
                const obj = { t, h, d, width: Xn, height: Yn};
                inverted ?   arr.unshift(obj) : arr.push(obj) 
               } 
            // 渲染图形
            arr.forEach(item => {
                let divBox = document.createElement('div');
                let styleObj = {
                    'width': item.width + 'px',
                    'height': item.d + 'px',
                    'border-left': item.t + 'px' + ' solid transparent',
                    'border-right':item.t + 'px' + ' solid transparent',
                    'border-top': inverted ? item.h + 'px' + ' solid grey' : 0,
                    'border-bottom': inverted ? 0 : item.h + 'px' + ' solid grey',
                }
                let str = Object.keys(styleObj).reduce((prev, cur) => prev  + cur + ':' + styleObj[cur] +';' ,'');
                divBox.style.cssText = str
                dom.appendChild(divBox)
            })
        }
    </script>
</html>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值