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;
}