zoukankan      html  css  js  c++  java
  • Canvas

    导语:距离上一次写canvas,已经过去两年半,如今业务需要,再次拾起,随手记录。

    【思考】 时钟的绘制主要在于圆的绘制:1. 使用context.arc()方法直接绘制圆或圆弧; 2. 使用圆的方程(x = r * cosA + X, y = r * sinA + Y)进行描点绘制。指针运行速率较慢,故使用setInterval进行刷新重绘。
    【优化】可以使用两个canvas,一个用来绘制表盘,另一个绘制指针,如此,只需刷新重绘指针canvas,表盘canvas保持不变。

    <!DOCTYPE html>
    <html>
    <head>
      <title>Canvas Clock</title>
    </head>
    <body>
    <canvas id="clock">Your borswer does not support canvas element.</canvas>
    <script type="text/javascript">
    /**
     * 圆的方程:x = r * cosA + X, y = r * sinA + Y
     * 浏览器为了达到抗锯齿的效果会做额外的运算,故为提高渲染效率,均使用整数进行绘制。
     */
    (function() {
        let clockCvs = document.getElementById('clock')
        if (!clockCvs || !clockCvs.getContext) return
        clockCvs.width = 310
        clockCvs.height = 310
        let clockCtx = clockCvs.getContext('2d')
        // X坐标偏移
        const X = 155
        // Y坐标偏移
        const Y = 155
        // 钟的半径
        const R = 150
    
        start()
        setInterval(start, 1000)
    
        function start () {
            clockCtx.clearRect(0, 0, clockCvs.width, clockCvs.height)
            renderClockPlate()
            renderClockTime()
            renderClockHand()
        }
    
        // 渲染表盘
        function renderClockPlate () {
            drawCircle(X, Y, '#070702', R, 1)
            drawCircle(X, Y, '#4f4f52', R - 3, 5)
            drawCircle(X, Y, '#070702', R - 6, 3)
            drawCircle(X, Y, '#dddddd', R - 8)
            drawCircle(X, Y, '#121213', R - 10, 3)
            drawCircle(X, Y, '#19191a', R - 12, 0, 'fill', true)
    
            drawCircle(X, Y, '#4e4738', 15, 0, 'fill')
            drawCircle(X, Y, '#eac55a', 10, 0, 'fill')
            drawCircle(X, Y, '#3e3e41', 8, 0, 'fill')
            drawCircle(X, Y, '#000000', 3, 0, 'fill')
        }
    
        // 渲染时间
        function renderClockTime () {
            for (let angle = -90; angle < 270; angle = angle + 6) {
                let x = Math.round((R - 18) * Math.cos(angle / 180 * Math.PI) + X)
                let y = Math.round((R - 18) * Math.sin(angle / 180 * Math.PI) + Y)
                let r = angle % 90 === 0 ? 4 : 2
                drawCircle(x, y, '#eac55a', r, 0, 'fill')
                if (angle % 30 === 0) {
                    x = Math.round((R - 35) * Math.cos(angle / 180 * Math.PI) + X - 4)
                    y = Math.round((R - 35) * Math.sin(angle / 180 * Math.PI) + Y + 6)
                    clockCtx.font = angle % 90 === 0 ? 'bold 15px yahei' : '12px yahei'
                    clockCtx.fillText((angle + 90) / 30 || 12, x , y)
                }
            }
        }
    
        // 渲染表针
        function renderClockHand () {
            let date = new Date()
            let hour = date.getHours()
            let minute = date.getMinutes()
            let second = date.getSeconds()
            // 秒针
            let angle1 = (second * 6 - 90)
            let x = Math.round((R - 45) * Math.cos(angle1 / 180 * Math.PI) + X)
            let y = Math.round((R - 45) * Math.sin(angle1 / 180 * Math.PI) + Y)
            drawLine([[X, Y], [x, y]], 1)
            // 分针
            let angle2 = (minute * 6 - 90)
            x = Math.round((R - 65) * Math.cos(angle2 / 180 * Math.PI) + X)
            y = Math.round((R - 65) * Math.sin(angle2 / 180 * Math.PI) + Y)
            drawLine([[X, Y], [x, y]], 2)
            // 时针, 时针角度 = 小时角度 + 分钟角度
            let angle3 = ((hour % 12) * 30 - 90) + (angle2 / 12)
            x = Math.round((R - 90) * Math.cos(angle3 / 180 * Math.PI) + X)
            y = Math.round((R - 90) * Math.sin(angle3 / 180 * Math.PI) + Y)
            drawLine([[X, Y], [x, y]], 4)
            
            
        }
    
        /**
         * @param {String} color 颜色
         * @param {Number} r 圆半径
         * @param {Number} lineWidth 线条粗细
         * @param {String} type 类型,stroke/fill
         * @param {Boolean} isLinear 是否渐变
         */
        function drawCircle (x, y,color = '#000000', r = 10, lineWidth = 2, type = 'stroke', isLinear = false) {
            let grd = clockCtx.createLinearGradient(0, 0, clockCvs.width, clockCvs.height)
            grd.addColorStop(0, color)
            grd.addColorStop(0.5, '#555555')
            grd.addColorStop(1, color)
            clockCtx[type + 'Style'] = isLinear ? grd : color
            clockCtx.lineWidth = lineWidth
            clockCtx.beginPath()
            clockCtx.arc(x, y, r, 0, Math.PI * 2, true)
            clockCtx.closePath()
            clockCtx[type]()
        }
    
        /**
         * @param {Array} pos 坐标点集合,如 [[0, 0], [120, 120]]
         * @param {String} color 颜色
         * @param {Number} lineWidth 线条粗细
         */
        function drawLine (pos, lineWidth = 2, color = '#eac55a') {
            clockCtx.strokeStyle = color
            clockCtx.lineWidth = lineWidth
            clockCtx.beginPath()
            clockCtx.moveTo(pos[0][0], pos[0][1])
            for (let i = 0, len = pos.length; i < len; i++) {
                clockCtx.lineTo(pos[i][0], pos[i][1])
            }
            clockCtx.stroke()
            clockCtx.closePath()
        }
    })()
    </script>
    </body>
    </html>
    优化前
    <!DOCTYPE html>
    <html>
    <head>
      <title>Canvas Clock</title>
    </head>
    <body>
    <canvas id="clock" style="position: absolute;">Your borswer does not support canvas element.</canvas>
    <canvas id="clockHand" style="position: absolute;">Your borswer does not support canvas element.</canvas>
    <script type="text/javascript">
    /**
     * 圆的方程:x = r * cosA + X, y = r * sinA + Y
     * 浏览器为了达到抗锯齿的效果会做额外的运算,故为提高渲染效率,均使用整数进行绘制。
     */
    (function() {
    	let clockCvs = document.getElementById('clock')
    	let clockHandCvs = document.getElementById('clockHand')
    	if (!clockCvs || !clockCvs.getContext) return
    	clockCvs.width = clockHandCvs.width = 310
    	clockCvs.height = clockHandCvs.height = 310
    	let clockCtx = clockCvs.getContext('2d')
    	let clockHandCtx = clockHandCvs.getContext('2d')
    	// X坐标偏移
    	const X = 155
    	// Y坐标偏移
    	const Y = 155
    	// 钟的半径
    	const R = 150
    
    	renderClockPlate()
    	renderClockTime()
    	renderClockHand()
    	setInterval(function () {
    		clockHandCtx.clearRect(0, 0, clockHandCvs.width, clockHandCvs.height)
    		renderClockHand()
    	}, 1000)
    
    	// 渲染表盘
    	function renderClockPlate () {
    		drawCircle(clockCtx, clockCvs, X, Y, '#070702', R, 1)
    		drawCircle(clockCtx, clockCvs, X, Y, '#4f4f52', R - 3, 5)
    		drawCircle(clockCtx, clockCvs, X, Y, '#070702', R - 6, 3)
    		drawCircle(clockCtx, clockCvs, X, Y, '#dddddd', R - 8)
    		drawCircle(clockCtx, clockCvs, X, Y, '#121213', R - 10, 3)
    		drawCircle(clockCtx, clockCvs, X, Y, '#19191a', R - 12, 0, 'fill', true)
    
    		drawCircle(clockCtx, clockCvs, X, Y, '#4e4738', 15, 0, 'fill')
    		drawCircle(clockCtx, clockCvs, X, Y, '#eac55a', 10, 0, 'fill')
    		drawCircle(clockCtx, clockCvs, X, Y, '#3e3e41', 8, 0, 'fill')
    		drawCircle(clockCtx, clockCvs, X, Y, '#000000', 3, 0, 'fill')
    	}
    
    	// 渲染时间
    	function renderClockTime () {
    		for (let angle = -90; angle < 270; angle = angle + 6) {
    			let x = Math.round((R - 18) * Math.cos(angle / 180 * Math.PI) + X)
    			let y = Math.round((R - 18) * Math.sin(angle / 180 * Math.PI) + Y)
    			let r = angle % 90 === 0 ? 4 : 2
    			drawCircle(clockCtx, clockCvs, x, y, '#eac55a', r, 0, 'fill')
    			if (angle % 30 === 0) {
    				x = Math.round((R - 35) * Math.cos(angle / 180 * Math.PI) + X - 4)
    				y = Math.round((R - 35) * Math.sin(angle / 180 * Math.PI) + Y + 6)
    				clockCtx.font = angle % 90 === 0 ? 'bold 15px yahei' : '12px yahei'
    				clockCtx.fillText((angle + 90) / 30 || 12, x , y)
    			}
    		}
    	}
    
    	// 渲染表针
    	function renderClockHand () {
    		let date = new Date()
    		let hour = date.getHours()
    		let minute = date.getMinutes()
    		let second = date.getSeconds()
    		// 秒针
    		let angle1 = (second * 6 - 90)
    		let x = Math.round((R - 45) * Math.cos(angle1 / 180 * Math.PI) + X)
    		let y = Math.round((R - 45) * Math.sin(angle1 / 180 * Math.PI) + Y)
    		drawLine(clockHandCtx, [[X, Y], [x, y]], 1)
    		// 分针
    		let angle2 = (minute * 6 - 90)
    		x = Math.round((R - 65) * Math.cos(angle2 / 180 * Math.PI) + X)
    		y = Math.round((R - 65) * Math.sin(angle2 / 180 * Math.PI) + Y)
    		drawLine(clockHandCtx, [[X, Y], [x, y]], 2)
    		// 时针, 时针角度 = 小时角度 + 分钟角度
    		let angle3 = ((hour % 12) * 30 - 90) + (angle2 / 12)
    		x = Math.round((R - 90) * Math.cos(angle3 / 180 * Math.PI) + X)
    		y = Math.round((R - 90) * Math.sin(angle3 / 180 * Math.PI) + Y)
    		drawLine(clockHandCtx, [[X, Y], [x, y]], 4)
    	}
    
    	/**
    	 * @param {String} color 颜色
    	 * @param {Number} r 圆半径
    	 * @param {Number} lineWidth 线条粗细
    	 * @param {String} type 类型,stroke/fill
    	 * @param {Boolean} isLinear 是否渐变
    	 */
    	function drawCircle (ctx, cvs, x, y,color = '#000000', r = 10, lineWidth = 2, type = 'stroke', isLinear = false) {
    		let grd = ctx.createLinearGradient(0, 0, cvs.width, cvs.height)
    		grd.addColorStop(0, color)
    		grd.addColorStop(0.5, '#555555')
    		grd.addColorStop(1, color)
    		ctx[type + 'Style'] = isLinear ? grd : color
    		ctx.lineWidth = lineWidth
    		ctx.beginPath()
    		ctx.arc(x, y, r, 0, Math.PI * 2, true)
    		ctx.closePath()
    		ctx[type]()
    	}
    
    	/**
    	 * @param {Array} pos 坐标点集合,如 [[0, 0], [120, 120]]
    	 * @param {String} color 颜色
    	 * @param {Number} lineWidth 线条粗细
    	 */
    	function drawLine (ctx, pos, lineWidth = 2, color = '#eac55a') {
    		ctx.strokeStyle = color
    		ctx.lineWidth = lineWidth
    		ctx.beginPath()
    		ctx.moveTo(pos[0][0], pos[0][1])
    		for (let i = 0, len = pos.length; i < len; i++) {
    			ctx.lineTo(pos[i][0], pos[i][1])
    		}
    		ctx.stroke()
    		ctx.closePath()
    	}
    })()
    </script>
    </body>
    </html>
    

      

  • 相关阅读:
    让文字从左到右 or 从右到左移动的效果
    pipenv创建命令
    redis笔记
    十分钟掌握pyecharts十类顶级图(亲测 饼图 ok)
    Python------pyecharts中常用的属性解释 (出现样式问题可以看看,有空研究)
    2020 python笔记
    testng参数化方法
    testng 多线程执行测试用例的方法
    xml配置文件---配置要执行的用例
    testng 断言的方法
  • 原文地址:https://www.cnblogs.com/codelovers/p/7050446.html
Copyright © 2011-2022 走看看