nicenote/docs/fea/canvas/base.md
2021-08-25 20:10:25 +08:00

9.1 KiB

nav group
title path
前端 /fea
title order
💊 canvas 1

基础入门

矩形

import React, { useRef, useEffect } from 'react';

export default () => {
    const canvasRef = useRef()

    /**
     *  绘制矩形
     *  fillRect(x, y, w, h) 填充矩形
     *  strokeRect(x, y, w, h) 边框矩形
     *  clearRect(x, y, w, h) 清除指定区域
     */
    function fillRect() {
        let canvas = canvasRef.current
        let ctx = canvas.getContext('2d')

        // 实心矩形
        ctx.fillStyle = 'red'
        ctx.fillRect(25, 25, 50, 50)

        // 空心矩形
        ctx.lineWidth = 1
        ctx.fillStyle = 'black'
        ctx.strokeRect(75, 75, 50, 50)

        // 清除区域
        ctx.clearRect(50, 50, 50, 50)
    }

    useEffect(() => {
        fillRect()
    }, [])

    return (
        <div>
            <canvas ref={canvasRef} width="200" height="200" />
        </div>
    )
}

三角形

import React, { useRef, useEffect } from 'react';

export default () => {
    const canvasRef = useRef()

    /**
     *  绘制三角形
     */
    function tri() {
        let canvas = canvasRef.current
        let ctx = canvas.getContext('2d')

        // 实心三角形
        ctx.beginPath()
        ctx.moveTo(90, 25)
        ctx.lineTo(25, 90)
        ctx.lineTo(155, 90)
        ctx.fill()

        ctx.beginPath()
        ctx.moveTo(90, 155)
        ctx.lineTo(25, 90)
        ctx.lineTo(155, 90)
        ctx.closePath()
        ctx.stroke()
    }

    useEffect(() => {
        tri()
    }, [])

    return (
        <div>
            <canvas ref={canvasRef} width="200" height="200" />
        </div>
    )
}

绘制圆弧

import React, { useRef, useEffect } from 'react';

export default () => {
    const canvasRef = useRef()

    // 绘制圆弧
    function drawArc() {
        let canvas = canvasRef.current
        let ctx = canvas.getContext('2d')

        let x = 90,
            y = 90,
            r = 30,
            startAngle = 0,
            endAngle = (Math.PI / 180) * 180

        ctx.beginPath()
        ctx.arc(x, y, r, startAngle, endAngle, false)
        ctx.fill()

        ctx.beginPath()
        ctx.arc(x, y, r, startAngle, endAngle, true)
        ctx.stroke()
    }

    useEffect(() => {
        drawArc()
    }, [])

    return (
        <div>
            <canvas ref={canvasRef} width="200" height="200" />
        </div>
    )
}

绘制贝塞尔曲线

import React, { useRef, useEffect } from 'react';

export default () => {
    const canvasRef = useRef()

    /**
     *  quadraticCurveTo(cp1x, cp1y, x, y) cp1 为控制点
     *  bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) cp1、cp2 为控制点
     *  x、y 为结束点
     */
    function bezier() {
        let canvas = canvasRef.current
        let ctx = canvas.getContext('2d')

        // 二次贝塞尔曲线
        ctx.beginPath()
        ctx.moveTo(30, 90)
        ctx.quadraticCurveTo(15, 15, 90, 30)
        ctx.quadraticCurveTo(165, 15, 150, 90)
        ctx.quadraticCurveTo(148, 130, 70, 120)
        ctx.quadraticCurveTo(65, 140, 40, 140)
        ctx.quadraticCurveTo(65, 135, 55, 120)
        ctx.quadraticCurveTo(30, 115, 30, 90)
        ctx.stroke()

        ctx.font = '18px bold 黑体'
        ctx.fillStyle = 'black'
        ctx.fillText('聊天框', 120, 160)

    }

    useEffect(() => {
        bezier()
    }, [])

    return (
        <div>
            <canvas ref={canvasRef} width="200" height="200" />
        </div>
    )
}

绘制三次贝塞尔曲线

import React, { useRef, useEffect } from 'react';

export default () => {
    const canvasRef = useRef()

    /**
     * 绘制三次贝塞尔曲线
     *
     */
    function beziers() {
        let canvas = canvasRef.current
        let ctx = canvas.getContext('2d')

        // 三次贝塞尔曲线
        ctx.beginPath()
        ctx.moveTo(90, 40)
        ctx.bezierCurveTo(90, 36, 70, 25, 50, 25)
        ctx.bezierCurveTo(20, 25, 20, 62.5, 20, 62.5)
        ctx.bezierCurveTo(20, 80, 40, 120, 90, 140)
        ctx.bezierCurveTo(110, 135, 155, 110, 160, 62.5)
        ctx.bezierCurveTo(160, 22, 140, 25, 130, 25)
        ctx.bezierCurveTo(120, 25, 110, 30, 90, 40)
        ctx.fillStyle = 'red'
        ctx.fill()

        ctx.font = '18px bold 黑体'
        ctx.fillStyle = 'black'
        ctx.fillText('爱心', 120, 160)
    }

    useEffect(() => {
        beziers()
    }, [])

    return (
        <div>
            <canvas ref={canvasRef} width="200" height="200" />
        </div>
    )
}

绘制笑脸

import React, { useRef, useEffect } from 'react';

export default () => {
    const canvasRef = useRef()

    /**
     *  绘制笑脸
     *
     */
    function fillSmile() {
        let canvas = canvasRef.current
        let ctx = canvas.getContext('2d')

        ctx.beginPath()
        ctx.arc(75, 75, 50, 0, Math.PI * 2, true)
        ctx.moveTo(110, 75)
        ctx.arc(75, 75, 35, 0, Math.PI, false)
        ctx.moveTo(65, 65)
        ctx.arc(60, 65, 5, 0, Math.PI * 2, true)
        ctx.moveTo(95, 65)
        ctx.arc(90, 65, 5, 0, Math.PI * 2, true)
        ctx.stroke()

        ctx.font = '18px bold 黑体'
        ctx.fillStyle = 'black'
        ctx.fillText('笑脸', 120, 160)
    }


    useEffect(() => {
        fillSmile()
    }, [])

    return (
        <div>
            <canvas ref={canvasRef} width="200" height="200" />
        </div>
    )
}

吃豆人

import React, { useRef, useEffect } from 'react';

export default () => {
    const canvasRef = useRef()

    /**
     * 吃豆人
     *
     */
    function bean() {
        let canvas = canvasRef.current
        let ctx = canvas.getContext('2d')

        // 外墙
        _roundedRect(ctx, 12, 12, 160, 160, 15)
        _roundedRect(ctx, 18, 18, 148, 148, 9)
        // 内墙
        _roundedRect(ctx, 45, 50, 45, 30, 6)
        _roundedRect(ctx, 115, 50, 45, 30, 6)
        _roundedRect(ctx, 115, 110, 45, 50, 6)
        _roundedRect(ctx, 45, 110, 45, 25, 6)

        // 绘制吃豆人
        ctx.beginPath()
        ctx.arc(35, 35, 10, Math.PI / 7, -Math.PI / 7, false)
        ctx.lineTo(31, 37)
        ctx.fill()

        // 绘制魔鬼
        ctx.beginPath()
        ctx.moveTo(83, 116)
        ctx.lineTo(83, 102)
        ctx.bezierCurveTo(83, 94, 89, 88, 97, 88)
        ctx.bezierCurveTo(105, 88, 111, 94, 111, 102)
        ctx.lineTo(111, 116)
        ctx.lineTo(106.3, 111.3)
        ctx.lineTo(97.3, 111)
        ctx.lineTo(92, 116)
        ctx.lineTo(87, 111)
        ctx.lineTo(83, 116)
        ctx.fill()

        // 绘制小点
        for (let i = 0; i < 7; i++) {
            ctx.fillRect(52 + i * 16, 35, 4, 4)
        }

        // 绘制小点
        for (let i = 0; i < 7; i++) {
            ctx.fillRect(28, 52 + i * 16, 4, 4)
        }

        // 绘制小点
        for (let i = 0; i < 7; i++) {
            ctx.fillRect(100, 52 + i * 16, 4, 4)
        }

        // 绘制小点
        for (let i = 0; i < 8; i++) {
            ctx.fillRect(44 + i * 16, 92, 4, 4)
        }

        // 绘制小点
        for (let i = 0; i < 3; i++) {
            ctx.fillRect(44 + i * 16, 148, 4, 4)
        }

        ctx.fillStyle = 'white'
        ctx.beginPath()
        ctx.moveTo(91, 96)
        ctx.bezierCurveTo(88, 96, 87, 99, 87, 101)
        ctx.bezierCurveTo(87, 103, 88, 106, 91, 106)
        ctx.bezierCurveTo(94, 106, 95, 103, 95, 101)
        ctx.bezierCurveTo(95, 99, 94, 96, 91, 96)
        ctx.moveTo(103, 96)
        ctx.bezierCurveTo(100, 96, 99, 99, 99, 101)
        ctx.bezierCurveTo(99, 103, 100, 106, 103, 106)
        ctx.bezierCurveTo(106, 106, 107, 103, 107, 101)
        ctx.bezierCurveTo(107, 99, 106, 96, 103, 96)
        ctx.fill()

        // 右眼
        ctx.fillStyle = 'blue'
        ctx.beginPath()
        ctx.arc(101, 102, 2, 0, Math.PI * 2, true)
        ctx.fill()
        // 左眼
        ctx.beginPath()
        ctx.arc(89, 102, 2, 0, Math.PI * 2, true)
        ctx.fill()

        ctx.font = '18px bold 黑体'
        ctx.fillStyle = 'black'
        ctx.fillText('吃豆人', 180, 180)

        ctx.clearRect(150, 0, 100, 200)

        /**
         * 绘制圆角矩形的函数
         *
         * @param {*} ctx 画笔
         * @param {*} x x 坐标
         * @param {*} y y 坐标
         * @param {*} w 宽
         * @param {*} h 高
         * @param {*} r 半径
         */
        function _roundedRect(ctx, x, y, w, h, radius) {
            ctx.beginPath();
            ctx.moveTo(x, y + radius);
            ctx.lineTo(x, y + h - radius);
            ctx.quadraticCurveTo(x, y + h, x + radius, y + h);
            ctx.lineTo(x + w - radius, y + h);
            ctx.quadraticCurveTo(x + w, y + h, x + w, y + h - radius);
            ctx.lineTo(x + w, y + radius);
            ctx.quadraticCurveTo(x + w, y, x + w - radius, y);
            ctx.lineTo(x + radius, y);
            ctx.quadraticCurveTo(x, y, x, y + radius);
            ctx.stroke();
        }
    }


    useEffect(() => {
        bean()
    }, [])

    return (
        <div>
            <canvas ref={canvasRef} width="200" height="200" />
        </div>
    )
}