§ Минимальный шаблон index.html

1<!DOCTYPE html>
2<html>
3<head>
4    <title>Минимальный шаблон</title>
5    <meta charset="utf8">
6    <meta name="viewport" content="width=device-width, initial-scale=1">
7    <script src="app.js"></script>
8</head>
9<body onload="new app()">
10    <canvas id="viewport" width="640" height="400" style="width: 1280px; height: 800px; image-rendering: pixelated;"></canvas>
11</body>
12</html>

§ Код класса app.js

1class app {
2
3    constructor() {
4
5        this.el     = document.getElementById('viewport');
6        this.ctx    = this.el.getContext('2d');
7        this.width  = this.el.width;
8        this.height = this.el.height;
9        this.img    = this.ctx.getImageData(0, 0, this.width, this.height);
10        this.dos256 = [
11            0x000000, 0x0000aa, 0x00aa00, 0x00aaaa, 0xaa0000, 0xaa00aa, 0xaa5500, 0xaaaaaa, // 0
12            0x555555, 0x5555ff, 0x55ff55, 0x55ffff, 0xff5555, 0xff55ff, 0xffff55, 0xffffff, // 8
13            0x000000, 0x141414, 0x202020, 0x2c2c2c, 0x383838, 0x454545, 0x515151, 0x616161, // 10
14            0x717171, 0x828282, 0x929292, 0xa2a2a2, 0xb6b6b6, 0xcbcbcb, 0xe3e3e3, 0xffffff, // 18
15            0x0000ff, 0x4100ff, 0x7d00ff, 0xbe00ff, 0xff00ff, 0xff00be, 0xff007d, 0xff0041, // 20
16            0xff0000, 0xff4100, 0xff7d00, 0xffbe00, 0xffff00, 0xbeff00, 0x7dff00, 0x41ff00, // 28
17            0x00ff00, 0x00ff41, 0x00ff7d, 0x00ffbe, 0x00ffff, 0x00beff, 0x007dff, 0x0041ff, // 30
18            0x7d7dff, 0x9e7dff, 0xbe7dff, 0xdf7dff, 0xff7dff, 0xff7ddf, 0xff7dbe, 0xff7d9e, // 38
19            0xff7d7d, 0xff9e7d, 0xffbe7d, 0xffdf7d, 0xffff7d, 0xdfff7d, 0xbeff7d, 0x9eff7d, // 40
20            0x7dff7d, 0x7dff9e, 0x7dffbe, 0x7dffdf, 0x7dffff, 0x7ddfff, 0x7dbeff, 0x7d9eff, // 48
21            0xb6b6ff, 0xc7b6ff, 0xdbb6ff, 0xebb6ff, 0xffb6ff, 0xffb6eb, 0xffb6db, 0xffb6c7, // 50
22            0xffb6b6, 0xffc7b6, 0xffdbb6, 0xffebb6, 0xffffb6, 0xebffb6, 0xdbffb6, 0xc7ffb6, // 58
23            0xb6ffb6, 0xb6ffc7, 0xb6ffdb, 0xb6ffeb, 0xb6ffff, 0xb6ebff, 0xb6dbff, 0xb6c7ff, // 60
24            0x000071, 0x1c0071, 0x380071, 0x550071, 0x710071, 0x710055, 0x710038, 0x71001c, // 68
25            0x710000, 0x711c00, 0x713800, 0x715500, 0x717100, 0x557100, 0x387100, 0x1c7100, // 70
26            0x007100, 0x00711c, 0x007138, 0x007155, 0x007171, 0x005571, 0x003871, 0x001c71, // 78
27            0x383871, 0x453871, 0x553871, 0x613871, 0x713871, 0x713861, 0x713855, 0x713845, // 80
28            0x713838, 0x714538, 0x715538, 0x716138, 0x717138, 0x617138, 0x557138, 0x457138, // 88
29            0x387138, 0x387145, 0x387155, 0x387161, 0x387171, 0x386171, 0x385571, 0x384571, // 90
30            0x515171, 0x595171, 0x615171, 0x695171, 0x715171, 0x715169, 0x715161, 0x715159, // 98
31            0x715151, 0x715951, 0x716151, 0x716951, 0x717151, 0x697151, 0x617151, 0x597151, // A0
32            0x517151, 0x517159, 0x517161, 0x517169, 0x517171, 0x516971, 0x516171, 0x515971, // A8
33            0x000041, 0x100041, 0x200041, 0x300041, 0x410041, 0x410030, 0x410020, 0x410010, // B0
34            0x410000, 0x411000, 0x412000, 0x413000, 0x414100, 0x304100, 0x204100, 0x104100, // B8
35            0x004100, 0x004110, 0x004120, 0x004130, 0x004141, 0x003041, 0x002041, 0x001041, // C0
36            0x202041, 0x282041, 0x302041, 0x382041, 0x412041, 0x412038, 0x412030, 0x412028, // C8
37            0x412020, 0x412820, 0x413020, 0x413820, 0x414120, 0x384120, 0x304120, 0x284120, // D0
38            0x204120, 0x204128, 0x204130, 0x204138, 0x204141, 0x203841, 0x203041, 0x202841, // D8
39            0x2c2c41, 0x302c41, 0x342c41, 0x3c2c41, 0x412c41, 0x412c3c, 0x412c34, 0x412c30, // E0
40            0x412c2c, 0x41302c, 0x41342c, 0x413c2c, 0x41412c, 0x3c412c, 0x34412c, 0x30412c, // E8
41            0x2c412c, 0x2c4130, 0x2c4134, 0x2c413c, 0x2c4141, 0x2c3c41, 0x2c3441, 0x2c3041, // F0
42            0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000  // F8
43        ];
44    }
45
46    // Вычисление размера экрана
47    windowsize() {
48
49        let win  = window, doc = document, docelem = doc.documentElement,
50            body = doc.getElementsByTagName('body')[0],
51            wx = win.innerWidth  || docelem.clientWidth || body.clientWidth,
52            wy = win.innerHeight || docelem.clientHeight|| body.clientHeight;
53
54        return {w: wx, h: wy};
55    }
56
57    // Цвет из 256-палитры
58    dos(cl) { return this.dos256[ cl & 255 ]; }
59
60    // Рисование пикселя на экране
61    pset(x, y, k) {
62
63        if (x < this.el.width && y < this.el.height && x >= 0 && y >= 0) {
64
65            let p = 4*(x + y * this.el.width);
66            this.img.data[p    ] =  (k >> 16) & 0xff;
67            this.img.data[p + 1] =  (k >>  8) & 0xff;
68            this.img.data[p + 2] =  (k      ) & 0xff;
69            this.img.data[p + 3] = ((k >> 24) & 0xff) ^ 0xff;
70        }
71    }
72
73    // Линия по Брезенхэму
74	line(x1, y1, x2, y2, color) {
75
76		// Инициализация смещений
77		let signx  = x1 < x2 ? 1 : -1;
78		let signy  = y1 < y2 ? 1 : -1;
79		let deltax = x2 > x1 ? x2 - x1 : x1 - x2;
80		let deltay = y2 > y1 ? y2 - y1 : y1 - y2;
81		let error  = deltax - deltay;
82		let error2;
83
84		// Если линия - это точка
85		this.pset(x2, y2, color);
86
87		// Перебирать до конца
88		while ((x1 != x2) || (y1 != y2)) {
89
90			this.pset(x1, y1, color);
91			error2 = 2 * error;
92			if (error2 > -deltay) { error -= deltay; x1 += signx; }
93			if (error2 <  deltax) { error += deltax; y1 += signy; }
94		}
95	}
96
97    // Очистка экрана
98    cls(cl) {
99
100        for (let y = 0; y < this.height; y++)
101        for (let x = 0; x < this.width; x++)
102            this.pset(x, y, cl);
103    }
104
105    // Обновление экрана
106    flush() { this.ctx.putImageData(this.img, 0, 0); }
107}