一応、PC・タッチの両操作に対応してます。


PC・タッチ操作対応と書きましたが、残念ながらマルチタッチは考慮してません。本当は identifier 見て、描画開始した指と同じ指が離れたときに描画終了するべきだと思います。

描画色の選択は input type="color" 使ってみました。でも対応してないブラウザで見ると、コード値を直接入力させられると思います。

あと、線の補間はしてないので、速く動かすと線がぶちぶち切れます。

HTML
<!DOCTYPE html>
<html lang="ja">
<head>
	<meta charset="UTF-8" />
	<meta name="robots" content="noarchive" />
	<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0" />
	<meta name="landscape" content="width=device-width, initial-scale=1.0, minimum-scale=1.0" />
	<style>
html { background-color:#000; color:#eee; }
#pixel-canvas { margin: 5px 0 10px; border: 1px solid #666; }
	</style>
	<title>Canvasドット絵 サンプル</title>
</head>
<body>
	描画色: <input type="color" id="brush-color" value="#ffffff" /><br />
	<canvas id="pixel-canvas"></canvas>
	<script src="script.js"></script>
</body>
</html>
JavaScript
(() => {
	const PIXEL_SIZE = 8;		    // 1ドットの大きさ
	const CANVAS_WIDTH = PIXEL_SIZE * 32;   // キャンバス横幅
	const CANVAS_HEIGHT = PIXEL_SIZE * 32;  // キャンバス縦幅
	
	const canvas = document.getElementById('pixel-canvas');
	const _ctx = canvas.getContext('2d');
	let _drawing = false;
	
	
	/**
	 * MouseEventまたはTouchからCanvas内での座標を算出して返却
	 * @param {MouseEvent|Touch}
	 * @return {Object} x: x座標, y: y座標
	 */
	const getCoordsByEvent = e => {
		const bounds = e.target.getBoundingClientRect();
		return {
			x: e.clientX - bounds.left,
			y: e.clientY - bounds.top
		};
	};

	/**
	 * RGBを指定してコンテキストに描画色を設定する
	 * @param {Number} R
	 * @param {Number} G
	 * @param {Number} B
	 */
	const setBrushColor = (r, g, b) => {
		_ctx.fillStyle = 'rgba('+ r +','+ g +','+ b +', 1)';
	};

	/**
	 * Canvas内の座標を指定して、描画モードONならドットを描画する
	 * @param {Number} x座標
	 * @param {Number} y座標
	 */
	const draw = (x, y) => {
		if (_drawing) {
			// ドットの左上の座標を算出
			const upperLeftX = Math.floor(x / canvas.width * CANVAS_WIDTH / PIXEL_SIZE) * PIXEL_SIZE;
			const upperLeftY = Math.floor(y / canvas.height * CANVAS_HEIGHT / PIXEL_SIZE) * PIXEL_SIZE;
			
			// ドットの大きさの矩形を描画
			_ctx.fillRect(upperLeftX, upperLeftY, PIXEL_SIZE, PIXEL_SIZE);
		}
	};
	
	
	// Canvasの幅と高さを設定
	canvas.width  = CANVAS_WIDTH;
	canvas.height = CANVAS_HEIGHT;

	// 不透明の黒で塗りつぶす
	setBrushColor(0, 0, 0);
	_ctx.fillRect(0, 0, canvas.width, canvas.height);

	// 初期描画色を白に
	setBrushColor(255, 255, 255);

	// 左クリックで描画モードON + 1発目の描画
	canvas.addEventListener('mousedown', e => {
		if (e.button <= 1) {
			_drawing = true;

			// Canvas内での左上からの座標を算出して描画
			const coords = getCoordsByEvent(e);
			draw(coords.x, coords.y);
		}
	});
	// タップ開始で同上
	canvas.addEventListener('touchstart', e => { 
		// ※マルチタッチ考慮せず
		_drawing = true;
		const coords = getCoordsByEvent(e.changedTouches[0]);
		draw(coords.x, coords.y);
	}); 

	// 左クリックで描画モードOFF
	canvas.addEventListener('mouseup', e => {
		if (e.button <= 1) {
			_drawing = false;
		}
	});
	// タップ終了で同上 (※マルチタッチ考慮せず)
	canvas.addEventListener('touchend', () => {
		_drawing = false;
	});

	// カーソル移動で描画
	canvas.addEventListener('mousemove', e => {
		const coords = getCoordsByEvent(e);
		draw(coords.x, coords.y);
	});
	// 指移動で同上 (※マルチタッチ考慮せず)
	canvas.addEventListener('touchmove', e => {
		e.preventDefault(); // スクロール防止
		const coords = getCoordsByEvent(e.changedTouches[0]); // 1本目の指だけ使う
		draw(coords.x, coords.y);
	});

	// 描画色変更
	document.getElementById('brush-color').addEventListener('change', e => {
		const code = e.target.value;
		const r = parseInt(code.substr(1, 2), 16);
		const g = parseInt(code.substr(3, 2), 16);
		const b = parseInt(code.substr(5, 2), 16);
		setBrushColor(r, g, b);
	});
})();