SOURCE

console 命令行工具 X clear

                    
>
console
const pointGroup = new zrender.Group()
pointGroup.attr("position", [2.5, 2.5])
zr.add(pointGroup)

class PixelDraw {

    cursor = null
    speed = 200

    constructor() {
        this.row = screenRow
        this.column = screenColumn
        this.tileSize = tileSize
        this.canvasWidth = canvasWidth
        this.canvasHeight = canvasHeight
        this.palette = palette
        this.colors = Object.values(palette)
        this.colorNames = Object.keys(palette)

        this.pixelGroup = new zrender.Group()
        zr.add(this.pixelGroup)

        this.currentColor = this.colors[0]

        this.currentPos = {
            x: 0,
            y: 0
        }

        this.nextPos = {
            x: 0,
            y: 0
        }

        this.initCursor()
    }

    sleep(interval = this.speed) {
        return new Promise(resolve => {
            setTimeout(resolve, interval)
        })
    }

    randomColor() {
        return this.colors[Math.floor(Math.random() * this.colors.length)]
    }

    setColor(colorName = "") {
        if (this.colorNames.includes(colorName)) {
            this.currentColor = this.palette[colorName]
        } else {
            this.currentColor = this.randomColor()
        }
    }

    createPixel(x = 0, y = 0, color = this.currentColor) {
        return new zrender.Rect({
            shape: {
                x: x * this.tileSize,
                y: y * this.tileSize,
                width: this.tileSize,
                height: this.tileSize
            },
            style: {
                fill: color,
                stroke: color
            }
        })
    }

    initCursor() {
        const cursor = this.cursor = this.createPixel(this.currentPos.x, this.currentPos.y)
        this.cursor.attr("style", { opacity: 0.8, blend: "multiply" })
        this.cursor.attr("z", 2)
        this.pixelGroup.add(this.cursor)
        let isShow = true
        setInterval(() => {
            if (isShow) {
                cursor.show()
            } else {
                cursor.hide()
            }
            isShow = !isShow
        }, 500)
    }

    async goto(x = 0, y = 0) {
        this.currentPos.x = x
        this.currentPos.y = y
        this.cursor.animate("shape", false)
            .when(this.speed, {x: this.currentPos.x * this.tileSize, y: this.currentPos.y * this.tileSize})
            .start()
        await this.sleep()
    }

    async drawPixel(x = this.currentPos.x, y = this.currentPos.y, color = this.currentColor) {
        if (x !== this.currentPos.x || y !== this.currentPos.y) {
            await this.goto(x, y)
        }
        const pixel = this.createPixel(x, y, color)
        this.pixelGroup.add(pixel)
        await this.sleep()
    }

    async drawPath(path = []) {
        for (let i = 0; i < path.length; i++) {
            await this.drawPixel(path[i].x, path[i].y)
        }
    }

    async lineTo(dir = "right", len = 1) {
        const path = []
        for (let delta = 0; delta < len; delta++) {
            switch (dir) {
                case "right":
                    path.push({
                        x: this.currentPos.x + delta,
                        y: this.currentPos.y
                    })
                    break
                case "left":
                    path.push({
                        x: this.currentPos.x - delta,
                        y: this.currentPos.y
                    })
                    break
                case "up":
                    path.push({
                        x: this.currentPos.x,
                        y: this.currentPos.y - delta
                    })
                    break
                case "down":
                    path.push({
                        x: this.currentPos.x,
                        y: this.currentPos.y + delta
                    })
                    break
                case "up-left":
                    path.push({
                        x: this.currentPos.x - delta,
                        y: this.currentPos.y - delta
                    })
                    break
                case "up-right":
                    path.push({
                        x: this.currentPos.x + delta,
                        y: this.currentPos.y - delta
                    })
                    break
                case "down-left":
                    path.push({
                        x: this.currentPos.x - delta,
                        y: this.currentPos.y + delta
                    })
                    break
                case "down-right":
                    path.push({
                        x: this.currentPos.x + delta,
                        y: this.currentPos.y + delta
                    })
            }
        }
        await this.drawPath(path)
    }
}

const pen = new PixelDraw()

const interpreter = new Sval({
    ecmaVer: 9,
    sandBox: true
})

interpreter.import("pen", pen)

/**
 * 这里注意分号,否则报错
 */
const code = `;(async () => {
    await pen.goto(0, 1)
    await pen.goto(1, 1)
    pen.setColor()
    await pen.drawPixel(7, 7)
    await pen.goto(1, 2)
    pen.setColor()
    await pen.drawPixel()
    await pen.goto(1, 3)
    await pen.goto(2, 3)
    pen.setColor()
    await pen.drawPixel()
    await pen.goto(2, 4)
    await pen.goto(8, 4)
    pen.setColor()
    await pen.drawPixel()
    for (let i = 0; i < 10; i++) {
        await pen.goto(i, 5)
        await pen.drawPixel()
    }
    await pen.lineTo("right", 3)
    pen.setColor()
    await pen.lineTo("down", 5)
    pen.setColor()
    await pen.lineTo("left", 5)
    pen.setColor()
    await pen.lineTo("down-left", 5)
    pen.setColor()
    await pen.lineTo("up", 6)
    pen.setColor()
    await pen.lineTo("down-right", 8)
    pen.setColor()
    await pen.lineTo("up-right", 3)
    pen.setColor()
    await pen.lineTo("up-left", 6)
})();`

interpreter.run(code)
<canvas id="ok" width="384" height="640"></canvas>

<script>
    const canvas = document.getElementById("ok")
    const ctx = canvas.getContext("2d")
    const zr = zrender.init(canvas)

    const gridGroup = new zrender.Group()
    gridGroup.attr("position", [0.5, 0.5])
    zr.add(gridGroup)

    const screenColumn = 24
    const screenRow = 36
    const tileSize = 16
    const canvasWidth = screenColumn * tileSize
    const canvasHeight = screenRow * tileSize
    const gridColor = '#AAA'

    for (let h = 1; h <= screenColumn; h++) {
        const vLine = new zrender.Line({
            shape: {
                x1: h * tileSize,
                y1: 0,
                x2: h * tileSize,
                y2: canvasHeight
            },
            style: {
                stroke: gridColor
            },
            silent: true
        })
        gridGroup.add(vLine)
    }

    for (let v = 1; v <= screenRow; v++) {
        const hLine = new zrender.Line({
            shape: {
                x1: 0,
                y1: v * tileSize,
                x2: canvasWidth,
                y2: v * tileSize
            },
            style: {
                stroke: gridColor
            },
            silent: true
        })
        gridGroup.add(hLine)
    }

    zr.add(new zrender.Rect({
        shape: {
            x: 0,
            y: 0,
            width: canvasWidth,
            height: canvasHeight
        },
        style: {
            fill: "transparent",
            stroke: gridColor
        },
        silent: true
    }))
</script>

<script>
    const palette = {
        gray: "#9CA3AF",
        white: "#FFFFFF",
        black: "#000000",
        silver: "#C0C0C0",
        red: "#EF4444",
        yellow: "#FBBF24",
        green: "#10B981",
        blue: "#3B82F6",
        purple: "#8B5CF6",
        pink: "#F472B6",
        brown: "#A52A2A",
        orange: "#FFA500",
        gold: "#FFD700",
        cyan: "#00FFFF",
        indigo:"#4B0082"
    }

    const paletteGroup = new zrender.Group()
    paletteGroup.attr("position", [0.5, 576.5])
    zr.add(paletteGroup)

    const paletteWidth = 32
    const paletteHeight = 32
    let row = 0
    let column = 0

    for (let color in palette) {
        if (column >= 8) {
            column = 0
            row++
        }
        paletteGroup.add(new zrender.Rect({
            shape: {
                x: column * paletteWidth,
                y: row * paletteHeight,
                width: paletteWidth,
                height: paletteHeight
            },
            style: {
                fill: palette[color],
                stroke: palette[color]
            },
            silent: true
        }))
        column++
    }


</script>
canvas#ok {
    background: #eee;
}

本项目引用的自定义外部资源