const BACKGROUND_COLOR = "#333", DEFAULT_GAZE_POINT_RADIUS = 15, DEFAULT_GAZE_POINT_COLOR = "#3f0d76", DEBUG_POSITION_OFFSET = 10, DEBUG_FONT = "16px ShareTech", DEBUG_COLOR = "#ffffff", MAX_GAZE_POINT_AGE = 1000; var lastUpdate, lastDelta, fpsBuffer, gazePoints, version, debug, frameRate, canvas, context, loop; function onTick() { setDelta(); updateGazePoints(); context.clearRect(0, 0, canvas.width, canvas.height); drawGazePoints(); if (debug === true) { drawDebugInfo(); } setUpdateTime(); } function setUpdateTime() { lastUpdate = Date.now(); } function setDelta() { lastDelta = Date.now() - lastUpdate; } function addGazePoint(point) { gazePoints.set(point.id, point); } function removeGazePoint(point) { gazePoints.delete(point.id); } function updateGazePoints() { let now = Date.now(); for (let item of gazePoints) { let point = item[1]; if (now - point.createdAt > MAX_GAZE_POINT_AGE) { removeGazePoint(point); } } } function drawGazePoints() { let now = Date.now(); context.fillStyle = DEFAULT_GAZE_POINT_COLOR; for (let item of gazePoints) { let relativeAge = 1 - ((now - item[1].createdAt) / MAX_GAZE_POINT_AGE); context.save(); context.globalAlpha = relativeAge; context.beginPath(); context.ellipse(item[1].targetX, item[1].targetY, relativeAge * DEFAULT_GAZE_POINT_RADIUS, relativeAge * DEFAULT_GAZE_POINT_RADIUS, Math.PI / 4, 0, 2 * Math.PI); context.fill(); context.closePath(); context.restore(); } } function drawDebugInfo() { let fps = parseInt(1000 / lastDelta), averageFps; fpsBuffer.push(fps); if (fpsBuffer.length === frameRate) { averageFps = parseInt(fpsBuffer.reduce((a, b) => a + b, 0) / fpsBuffer.length); fpsBuffer.shift(); } context.beginPath(); context.font = DEBUG_FONT; context.fillStyle = DEBUG_COLOR; context.fillText(`${version} | ${averageFps}fps`, DEBUG_POSITION_OFFSET, canvas.height-DEBUG_POSITION_OFFSET); context.closePath(); } class GameRenderer { constructor() { fpsBuffer = []; gazePoints = new Map(); } start(options) { canvas = options.canvas; canvas.width = options.width; canvas.height = options.height; canvas.style.width = `${options.width}px`; canvas.style.height = `${options.height}px`; context = canvas.getContext("2d", { alpha: false }); canvas.style.backgroundColor = BACKGROUND_COLOR; frameRate = options.frameRate; version = options.version; debug = options.debug; setUpdateTime(); loop = setInterval(onTick, (1000 / frameRate)); } addGazePoint(point) { addGazePoint(point); } removeGazePoint(point) { removeGazePoint(point); } } export default new GameRenderer();