原生js + canvas 實現刻度尺效果

歡迎訪問我的 個人博客

手勢事件
touchstart 手指按下 、touchmove 手指移動 、 touchend 手指擡起

效果圖:

在這裏插入圖片描述

完整代碼:

ruler.js

var ruler = {
    /**
     * 初始化刻度尺插件
     * @el 容器 String
     * @height 刻度尺高度 Number
     * @maxScale 最大刻度 Number
     * @startValue 開始的值 Number
     * @region 區間 Array
     * @background 刻度尺背景顏色 String
     * @color 刻度線和字體的顏色 String
     * @markColor  中心刻度標記顏色 String
     * @isConstant 是否不斷地獲取值 Boolean
     * @success(res) 滑動結束後的回調 Function
     * */
    initPlugin: function (params) {
        var initParams = {
            el: params.el,
            height: params.height || 60,
            maxScale: params.maxScale || 200,
            startValue: params.startValue || 0,
            region: params.region || false,
            background: params.background || false,
            color: params.color || false,
            markColor: params.markColor || "#FFCC33",
            isConstant: params.isConstant || false
        };

        if (!initParams.el) {
            console.warn("沒有容器元素的參數");
            return false;
        }

        var rulerWrap = document.getElementById(initParams.el); //獲取容器
        rulerWrap.style.height = initParams.height < 50 ? 50 + "px" : initParams.height + "px";

        //最大刻度的小值是50
        initParams.maxScale = initParams.maxScale < 50 ? 50 : initParams.maxScale;

        if (initParams.startValue > initParams.maxScale) {
            initParams.startValue = initParams.maxScale;
        }

        var minSildeNum = 0;//最小滑動的值
        var maxSildeNum = initParams.maxScale;//最大滑動的值

        if (initParams.region) {
            minSildeNum = Math.floor(initParams.region[0]);
            maxSildeNum = Math.floor(initParams.region[1]);
        }

        var count = initParams.startValue; //初始值

        var winWidth = rulerWrap.offsetWidth; //容器寬度
        var division = winWidth / 50; //每個刻度的距離 分割線
        //刻度值數組
        var scaleValueList = [];
        for (var i = 0; i <= initParams.maxScale; i += 10) {
            scaleValueList.push(i);
        }

        var canvas = rulerWrap.getElementsByTagName("canvas")[0]; //獲取容器下的canvas標籤
        //沒有canvas就創建一個
        if (!canvas) {
            canvas = document.createElement("canvas"); //創建canvas標籤
            canvas.width = winWidth;
            canvas.height = initParams.height;
            rulerWrap.appendChild(canvas);
        }
        var cxt = canvas.getContext("2d");

        if (window.devicePixelRatio) {
            canvas.width = window.devicePixelRatio * winWidth;
            canvas.height = window.devicePixelRatio * initParams.height;
            cxt.scale(window.devicePixelRatio, window.devicePixelRatio);
        }

        //畫刻度尺
        function drawRuler(count) {
            count = count - 25;

            //清空畫布
            cxt.clearRect(0, 0, winWidth, initParams.height);

            //刻度尺背景
            if (initParams.background) {
                cxt.fillStyle = initParams.background;
                cxt.fillRect(0, 0, canvas.width, initParams.height);
            }

            //畫刻度線
            for (var i = 0; i < initParams.maxScale; i++) {
                cxt.beginPath();
                cxt.save();
                cxt.strokeStyle = initParams.color ? initParams.color : "#bbb";
                cxt.lineWidth = 1;
                cxt.lineCap = "round";
                cxt.moveTo(division * i - count * division, 0);
                cxt.lineTo(division * i - count * division, Math.floor(initParams.height * 0.3));

                if (i % 2 === 0) {
                    cxt.strokeStyle = initParams.color ? initParams.color : "#999";
                    cxt.lineTo(division * i - count * division, Math.floor(initParams.height * 0.35));
                }
                if (i % 10 === 0) {
                    cxt.strokeStyle = initParams.color ? initParams.color : "#666";
                    cxt.lineTo(division * i - count * division, Math.floor(initParams.height * 0.52));
                }

                cxt.stroke();
                cxt.restore();
                cxt.closePath();
            }

            //添加體重數字
            cxt.beginPath();
            cxt.font = "14px Arial";
            cxt.fillStyle = initParams.color ? initParams.color : "#333";
            cxt.textAlign = "center";
            cxt.textBaseline = "middle";
            scaleValueList.forEach(function (num, i) {
                cxt.fillText(num.toString(), (division * i * 10) - (count * division), Math.floor(initParams.height * 0.78));
            });
            cxt.closePath();

            //中心刻度線
            cxt.beginPath();
            cxt.save();
            cxt.strokeStyle = initParams.markColor;
            cxt.lineWidth = 2;
            cxt.lineCap = "round";
            cxt.moveTo((winWidth / 2), 0);
            cxt.lineTo((winWidth / 2), Math.floor(initParams.height * 0.52));
            cxt.stroke();
            cxt.restore();
            cxt.closePath();

        }

        if (window.devicePixelRatio) {
            canvas.style.transform = "scale(" + 1 / window.devicePixelRatio + ")";
            canvas.style.transformOrigin = "left top";
        }

        drawRuler(count);

        //滑動相關
        var initX = 0, //初始x 距離
            endX = 0, //結束x 距離
            distanceX = 0, //移動距離
            _distanceX = 0,// 判斷用的移動距離
            lastX = count; //上次移動距離

        if (!canvas) return false;

        //手指按下
        canvas.addEventListener("touchstart", function (e) {
            initX = e.targetTouches[0].pageX;

        }, false);

        //手指滑動
        canvas.addEventListener("touchmove", function (e) {
            endX = e.targetTouches[0].pageX;
            moveEvent();
        }, false);

        //手指擡起
        canvas.addEventListener("touchend", function (e) {
            lastX = count;
            overEvent();
        }, false);

        var isMouseDown = false; //鼠標是否按下

        //鼠標按下
        canvas.addEventListener("mousedown", function (e) {
            isMouseDown = true;
            initX = e.layerX;
        }, false);

        //鼠標移動
        canvas.addEventListener("mousemove", function (e) {
            if (!isMouseDown) {
                return false;
            }
            endX = e.layerX;
            moveEvent();
        }, false);


        //鼠標擡起&離開
        canvas.addEventListener("mouseup", function (e) {
            lastX = count;
            isMouseDown = false;
            overEvent();
        }, false);

        canvas.addEventListener("mouseleave", function (e) {
            if (isMouseDown) {
                lastX = count;
                isMouseDown = false;
                overEvent();
            }
        }, false);


        //手指&鼠標移動事件
        function moveEvent() {
            distanceX = Math.floor((endX - initX) / (winWidth / 50));
            if (distanceX === _distanceX) {
                return false;
            }
            _distanceX = distanceX;
            count = lastX + distanceX;

            if (count >= initParams.maxScale || count <= 0) {
                count = count >= initParams.maxScale ? initParams.maxScale : 0;
            }
            drawRuler(count);

            if (initParams.isConstant) {
                params.success && params.success(count);
            }
        }

        //手指&鼠標結束事件
        function overEvent() {
            if (count > maxSildeNum) {
                lastX = count = count > maxSildeNum ? maxSildeNum : count;
            } else if (count < minSildeNum) {
                lastX = count = count < minSildeNum ? minSildeNum : count;
            } else {

            }
            drawRuler(count);

            //返回最後的值
            params.success && params.success(count);
        }

    }
};

ruler.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>刻度尺</title>
    <meta name="renderer" content="webkit">
    <meta name="viewport"
          content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"/>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        .ruler-wrap {
            width: 100%;
            max-width: 600px;
            /*height: 60px;*/
            line-height: 1px;
            overflow: hidden;
            margin: 0 auto 50px;
        }

        .text-input{
            display: block;
            width: 100px;
            height: 30px;
            border-radius: 5px;
            background: #f6f6f6;
            border: none;
            text-align: center;
            font-size: 14px;
            color: #4142cc;
            font-weight: bold;
            letter-spacing: 1px;
            margin: 0 auto;
        }
        .text-input:focus{
            outline: none;
        }
    </style>
</head>
<body>

<!-- 刻度尺容器(必要的) -->
<div class="ruler-wrap" id="ruler"></div>

<!-- 刻度尺容器(必要的) -->
<div class="ruler-wrap" style="width: 90%;" id="ruler2"></div>


<input id="rulerText3" class="text-input" type="text" readonly value="">

<!-- 刻度尺容器(必要的) -->
<div class="ruler-wrap" style="width: 80%;" id="ruler3"></div>


<!-- 引入刻度尺插件js -->
<script src="js/ruler.js"></script>
<script>

    //調用刻度尺方法
    ruler.initPlugin({
        el: "ruler", //容器id
        startValue: 100,
        background: "#f5f5f5",
        success: function (res) {
            console.log(res);
        }
    });

    //調用刻度尺方法
    ruler.initPlugin({
        el: "ruler2", //容器id
        maxScale: 300, //最大刻度
        startValue: 50, //刻度開始的初始值
        region: [10, 200], //選擇刻度的區間範圍
        background: "#2bd4bc", //刻度尺背景色
        markColor: "#c968ff", //中心刻度標記顏色
        success: function (res) {
            console.log(res);
        }
    });


    var rulerText3 = document.getElementById("rulerText3");
    rulerText3.value = 200;
    //調用刻度尺方法
    ruler.initPlugin({
        el: "ruler3", //容器id
        height: 50, //刻度尺高度
        maxScale: 300, //最大刻度
        startValue: 200, //刻度開始的初始值
        region: [50, 220], //選擇刻度的區間範圍
        background: "#ffa43c", //刻度尺背景色
        color: "#fff", //刻度線和字體的顏色
        markColor: "#3786db", //中心刻度標記顏色
        isConstant: true, //是否不斷地獲取值
        success: function (res) {
            console.log(res);
            rulerText3.value = res;
        }
    });

</script>

</body>
</html>

屬性說明

屬性名 類型 是否必須 默認值 說明
el String 用於包裹canvas的容器
height Number 60 canvas刻度尺的高度,最小值是50
maxScale Number 200 最大刻度值,最小值是50
startValue Number 0 開始時的刻度值
region Array false 選擇刻度的區間範圍
background String false canvas刻度尺的顏色
color String false 刻度線和字體的顏色
markColor String “#FFCC33” 中心刻度標記顏色
isConstant Boolean false 是否不斷地獲取值
success Function 返回此刻的值
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章