UNPKG

pixi-pixelate

Version:

draw proper pixelated graphic primitives for pixi.js (i.e., point, line, circle, ellipse, arc, and filled versions)

763 lines (692 loc) 82.5 kB
'use strict'; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var PIXI = require('pixi.js'); var Angle = require('yy-angle'); /** * pixi-pixelate: a container to create proper pixelated graphics */ var Pixelate = function (_PIXI$Container) { _inherits(Pixelate, _PIXI$Container); function Pixelate() { _classCallCheck(this, Pixelate); var _this = _possibleConstructorReturn(this, (Pixelate.__proto__ || Object.getPrototypeOf(Pixelate)).call(this)); _this.cursor = { x: 0, y: 0 }; _this.tint = 0xffffff; _this._lineStyle = { width: 1, tint: 0xffffff, alpha: 1, direction: 'up' }; _this.cache = []; return _this; } /** * clear all graphics * @returns {Pixelate} */ _createClass(Pixelate, [{ key: 'clear', value: function clear() { while (this.children.length) { this.cache.push(this.children.pop()); } return this; } /** * texture to use for sprites (defaults to PIXI.Texture.WHITE) * @type {PIXI.Texture} */ }, { key: 'getPoint', /** * creates or gets an old sprite * @param {number} tint * @param {number} alpha * @private */ value: function getPoint(tint, alpha) { var point = void 0; if (this.cache.length) { point = this.addChild(this.cache.pop()); } else { point = this.addChild(new PIXI.Sprite(Pixelate.texture)); } point.tint = typeof tint === 'undefined' ? this._lineStyle.tint : tint; point.alpha = typeof alpha === 'undefined' ? this._lineStyle.alpha : alpha; return point; } /** * draw a list of points * @param {(number[]|PIXI.Point[]|PIXI.PointLike[])} points * @param {number} tint * @param {number} alpha */ }, { key: 'points', value: function points(_points, tint, alpha) { if (isNaN(_points[0])) { var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = _points[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var point = _step.value; this.point(point.x, point.y, tint, alpha); } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } } else { for (var i = 0; i < _points.length; i += 2) { this.point(_points[i], _points[i + 1], tint, alpha); } } } /** * add a point using lineStyle or provided tint and alpha * @param {number} x * @param {number} y * @param {number} [tint] * @param {number} [alpha] * @returns {Pixelate} */ }, { key: 'point', value: function point(x, y, tint, alpha) { var point = this.getPoint(tint, alpha); point.position.set(x, y); point.width = point.height = 1; return this; } /** * if lineStyle.width > 1 then use this direction to place the next line; center=alternate up and down * @typedef {string} LineDirection (up, center, down) */ /** * set linestyle for pixelated layer * NOTE: width only works for line() for now * @param {number} width * @param {number} [tint=0xffffff] * @param {number} [alpha=1] * @param {LineDirection} [direction=up] (up, center, down) * @returns {Pixelate} */ }, { key: 'lineStyle', value: function lineStyle(width, tint, alpha, direction) { this._lineStyle.width = width; this._lineStyle.tint = typeof tint !== 'undefined' ? tint : 0xffffff; this._lineStyle.alpha = typeof alpha !== 'undefined' ? alpha : 1; this._lineStyle.direction = direction || 'up'; return this; } /** * move cursor to this location * @param {number} x * @param {number} y * @returns {Pixelate} */ }, { key: 'moveTo', value: function moveTo(x, y) { this.cursor.x = x; this.cursor.y = y; return this; } /** * draw a pixelated line between two points and move cursor to the second point * @param {number} x0 * @param {number} y0 * @param {number} x1 * @param {number} y1 * @param {number} [tint] * @param {number} [alpha] * @param {number} [lineWidth] * @param {LineDirection} [lineDirection] * @returns {Pixelate} */ }, { key: 'line', value: function line(x0, y0, x1, y1, tint, alpha, lineWidth, lineDirection) { lineWidth = typeof lineWidth === 'undefined' ? this._lineStyle.width : lineWidth; lineDirection = lineDirection || this._lineStyle.direction; if (lineWidth === 1) { this.drawPoints(this.linePoints(x0, y0, x1, y1), tint, alpha); } else { var angle = Angle.angleTwoPoints(x0, y0, x1, y1) + Math.PI / 2 * (lineDirection === 'up' ? -1 : 1); var cos = Math.cos(angle); var sin = Math.sin(angle); var points = []; if (lineDirection === 'center') { var half = lineWidth / 2; points.push(x0 + Math.round(cos * half), y0 + Math.round(sin * half)); points.push(x1 + Math.round(cos * half), y1 + Math.round(sin * half)); points.push(x1 - Math.round(cos * half), y1 - Math.round(sin * half)); points.push(x0 - Math.round(cos * half), y0 - Math.round(sin * half)); } else { points.push(x0, y0); points.push(x0 + Math.round(cos * lineWidth), y0 + Math.round(sin * lineWidth)); points.push(x1 + Math.round(cos * lineWidth), y1 + Math.round(sin * lineWidth)); points.push(x1, y1); } this.polygonFill(points, tint, alpha, 1); } return this; } /** * draw a pixelated line between two points and move cursor to the second point * based on https://github.com/madbence/node-bresenham/blob/master/index.js * @private * @param {number} x0 * @param {number} y0 * @param {number} x1 * @param {number} y1 * @param {number[]} [points] * @returns {number[]} */ }, { key: 'linePoints', value: function linePoints(x0, y0, x1, y1, points) { points = points || []; points.push([x0, y0]); var dx = x1 - x0; var dy = y1 - y0; var adx = Math.abs(dx); var ady = Math.abs(dy); var eps = 0; var sx = dx > 0 ? 1 : -1; var sy = dy > 0 ? 1 : -1; if (adx > ady) { for (var x = x0, y = y0; sx < 0 ? x >= x1 : x <= x1; x += sx) { points.push([x, y]); eps += ady; if (eps << 1 >= adx) { y += sy; eps -= adx; } } } else { for (var x = x0, y = y0; sy < 0 ? y >= y1 : y <= y1; y += sy) { points.push([x, y]); eps += adx; if (eps << 1 >= ady) { x += sx; eps -= ady; } } } return points; } /** * create a unique array * from https://stackoverflow.com/a/9229821/1955997 * @private * @param {Array} a */ }, { key: 'hashUnique', value: function hashUnique(a) { var seen = {}; return a.filter(function (item) { var key = item[0] + '.' + item[1]; return seen.hasOwnProperty(key) ? false : seen[key] = true; }); } /** * draw a set of points, removing duplicates first * @private * @param {object[]} */ }, { key: 'drawPoints', value: function drawPoints(points, tint, alpha) { points = this.hashUnique(points); var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { for (var _iterator2 = points[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { var point = _step2.value; this.point(point[0], point[1], tint, alpha); } } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2.return) { _iterator2.return(); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } } /** * draw a pixelated line from the cursor position to this position * @param {number} x * @param {number} y * @returns {Pixelate} */ }, { key: 'lineTo', value: function lineTo(x, y) { this.drawPoints(this.linePoints(this.cursor.x, this.cursor.y, x, y)); this.cursor.x = x; this.cursor.y = y; return this; } /** * draw a pixelated circle * from https://en.wikipedia.org/wiki/Midpoint_circle_algorithm * @param {number} x0 * @param {number} y0 * @param {number} radius * @param {number} [tint] * @param {number} [alpha] * @returns {Pixelate} */ }, { key: 'circle', value: function circle(x0, y0, radius, tint, alpha) { var points = []; var x = radius; var y = 0; var decisionOver2 = 1 - x; // Decision criterion divided by 2 evaluated at x=r, y=0 while (x >= y) { points.push([x + x0, y + y0]); points.push([y + x0, x + y0]); points.push([-x + x0, y + y0]); points.push([-y + x0, x + y0]); points.push([-x + x0, -y + y0]); points.push([-y + x0, -x + y0]); points.push([x + x0, -y + y0]); points.push([y + x0, -x + y0]); y++; if (decisionOver2 <= 0) { decisionOver2 += 2 * y + 1; // Change in decision criterion for y -> y+1 } else { x--; decisionOver2 += 2 * (y - x) + 1; // Change for y -> y+1, x -> x-1 } } this.drawPoints(points, tint, alpha); return this; } /** * draw and fill circle * @param {number} x center * @param {number} y center * @param {number} radius * @param {number} tint * @param {number} alpha */ }, { key: 'circleFill', value: function circleFill(x0, y0, radius, tint, alpha) { var points = []; var x = radius; var y = 0; var decisionOver2 = 1 - x; // Decision criterion divided by 2 evaluated at x=r, y=0 while (x >= y) { this.rectPoints(-x + x0, y + y0, x * 2 + 1, 1, points); this.rectPoints(-y + x0, x + y0, y * 2 + 1, 1, points); this.rectPoints(-x + x0, -y + y0, x * 2 + 1, 1, points); this.rectPoints(-y + x0, -x + y0, y * 2 + 1, 1, points); y++; if (decisionOver2 <= 0) { decisionOver2 += 2 * y + 1; // Change in decision criterion for y -> y+1 } else { x--; decisionOver2 += 2 * (y - x) + 1; // Change for y -> y+1, x -> x-1 } } this.drawPoints(points, tint, alpha); return this; } /** * return an array of points for a rect * @private * @param {number} x0 * @param {number} y0 * @param {number} width * @param {number} height * @param {number[]} [points] * @returns {object[]} */ }, { key: 'rectPoints', value: function rectPoints(x0, y0, width, height, points) { points = points || []; for (var y = y0; y < y0 + height; y++) { for (var x = x0; x < x0 + width; x++) { points.push([x, y]); } } return points; } /** * draw the outline of a rect * @param {number} x * @param {number} y * @param {number} width * @param {number} height * @param {number} tint * @param {number} alpha * @return {Pixelate} */ }, { key: 'rect', value: function rect(x, y, width, height, tint, alpha) { if (width === 1) { var point = this.getPoint(tint, alpha); point.position.set(x, y); point.width = 1; point.height = height; } else if (height === 1) { var _point = this.getPoint(tint, alpha); _point.position.set(x, y); _point.width = 1; _point.height = 1; } else { var top = this.getPoint(tint, alpha); top.position.set(x, y); top.width = width + 1; top.height = 1; var bottom = this.getPoint(tint, alpha); bottom.position.set(x, y + height); bottom.width = width + 1; bottom.height = 1; var left = this.getPoint(tint, alpha); left.position.set(x, y + 1); left.width = 1; left.height = height - 1; var right = this.getPoint(tint, alpha); right.position.set(x + width, y + 1); right.width = 1; right.height = height - 1; } return this; } /** * draw and fill rectangle * @param {number} x * @param {number} y * @param {number} width * @param {number} height * @param {number} [tint] * @param {number} [alpha] * @returns {Pixelate} */ }, { key: 'rectFill', value: function rectFill(x, y, width, height, tint, alpha) { var point = this.getPoint(tint, alpha); point.position.set(x, y); point.width = width + 1; point.height = height + 1; return this; } /** * draw a pixelated ellipse * from http://cfetch.blogspot.tw/2014/01/wap-to-draw-ellipse-using-midpoint.html * @param {number} xc center * @param {number} yc center * @param {number} rx - radius x-axis * @param {number} ry - radius y-axis * @param {number} tint * @param {number} alpha * @returns {Pixelate} */ }, { key: 'ellipse', value: function ellipse(xc, yc, rx, ry, tint, alpha) { var points = []; var x = 0, y = ry; var p = ry * ry - rx * rx * ry + rx * rx / 4; while (2 * x * ry * ry < 2 * y * rx * rx) { points.push([xc + x, yc - y]); points.push([xc - x, yc + y]); points.push([xc + x, yc + y]); points.push([xc - x, yc - y]); if (p < 0) { x = x + 1; p = p + 2 * ry * ry * x + ry * ry; } else { x = x + 1; y = y - 1; p = p + (2 * ry * ry * x + ry * ry) - 2 * rx * rx * y; } } p = (x + 0.5) * (x + 0.5) * ry * ry + (y - 1) * (y - 1) * rx * rx - rx * rx * ry * ry; while (y >= 0) { points.push([xc + x, yc - y]); points.push([xc - x, yc + y]); points.push([xc + x, yc + y]); points.push([xc - x, yc - y]); if (p > 0) { y = y - 1; p = p - 2 * rx * rx * y + rx * rx; } else { y = y - 1; x = x + 1; p = p + 2 * ry * ry * x - 2 * rx * rx * y - rx * rx; } } this.drawPoints(points, tint, alpha); return this; } /** * draw and fill ellipse * @param {number} xc - x-center * @param {number} yc - y-center * @param {number} rx - radius x-axis * @param {number} ry - radius y-axis * @param {number} tint * @returns {Pixelate} */ }, { key: 'ellipseFill', value: function ellipseFill(xc, yc, rx, ry, tint, alpha) { var points = []; var x = 0, y = ry; var p = ry * ry - rx * rx * ry + rx * rx / 4; while (2 * x * ry * ry < 2 * y * rx * rx) { this.rectPoints(xc - x, yc - y, x * 2 + 1, 1, points); this.rectPoints(xc - x, yc + y, x * 2 + 1, 1, points); if (p < 0) { x = x + 1; p = p + 2 * ry * ry * x + ry * ry; } else { x = x + 1; y = y - 1; p = p + (2 * ry * ry * x + ry * ry) - 2 * rx * rx * y; } } p = (x + 0.5) * (x + 0.5) * ry * ry + (y - 1) * (y - 1) * rx * rx - rx * rx * ry * ry; while (y >= 0) { this.rectPoints(xc - x, yc - y, x * 2 + 1, 1, points); this.rectPoints(xc - x, yc + y, x * 2 + 1, 1, points); if (p > 0) { y = y - 1; p = p - 2 * rx * rx * y + rx * rx; } else { y = y - 1; x = x + 1; p = p + 2 * ry * ry * x - 2 * rx * rx * y - rx * rx; } } this.drawPoints(points, tint, alpha); return this; } /** * draw a pixelated polygon * @param {number[]} vertices * @param {number} tint * @param {number} alpha * @returns {Pixelate} */ }, { key: 'polygon', value: function polygon(vertices, tint, alpha) { var points = []; for (var i = 2; i < vertices.length; i += 2) { this.linePoints(vertices[i - 2], vertices[i - 1], vertices[i], vertices[i + 1], points); } if (vertices[vertices.length - 2] !== vertices[0] || vertices[vertices.length - 1] !== vertices[1]) { this.linePoints(vertices[vertices.length - 2], vertices[vertices.length - 1], vertices[0], vertices[1], points); } this.drawPoints(points, tint, alpha); } /** * draw and fill pixelated polygon * @param {number[]} vertices * @param {number} tint * @param {number} alpha * @returns {Pixelate} */ }, { key: 'polygonFill', value: function polygonFill(vertices, tint, alpha) { function mod(n, m) { return (n % m + m) % m; } var points = []; var edges = [], active = []; var minY = Infinity, maxY = 0; for (var i = 0; i < vertices.length; i += 2) { var p1 = { x: vertices[i], y: vertices[i + 1] }; var p2 = { x: vertices[mod(i + 2, vertices.length)], y: vertices[mod(i + 3, vertices.length)] }; if (p1.y - p2.y !== 0) { var edge = {}; edge.p1 = p1; edge.p2 = p2; if (p1.y < p2.y) { edge.minY = p1.y; edge.minX = p1.x; } else { edge.minY = p2.y; edge.minX = p2.x; } minY = edge.minY < minY ? edge.minY : minY; edge.maxY = Math.max(p1.y, p2.y); maxY = edge.maxY > maxY ? edge.maxY : maxY; if (p1.x - p2.x === 0) { edge.slope = Infinity; edge.b = p1.x; } else { edge.slope = (p1.y - p2.y) / (p1.x - p2.x); edge.b = p1.y - edge.slope * p1.x; } edges.push(edge); } } edges.sort(function (a, b) { return a.minY - b.minY; }); for (var y = minY; y <= maxY; y++) { for (var _i = 0; _i < edges.length; _i++) { var _edge = edges[_i]; if (_edge.minY === y) { active.push(_edge); edges.splice(_i, 1); _i--; } } for (var _i2 = 0; _i2 < active.length; _i2++) { var _edge2 = active[_i2]; if (_edge2.maxY < y) { active.splice(_i2, 1); _i2--; } else { if (_edge2.slope !== Infinity) { _edge2.x = Math.round((y - _edge2.b) / _edge2.slope); } else { _edge2.x = _edge2.b; } } } if (active.length) { active.sort(function (a, b) { return a.x - b.x === 0 ? b.maxY - a.maxY : a.x - b.x; }); var bit = true, current = 1; for (var x = active[0].x; x <= active[active.length - 1].x; x++) { if (bit) { points.push([x, y]); } if (active[current].x === x) { if (active[current].maxY !== y) { bit = !bit; } current++; } } } else { return this; } } this.drawPoints(points, tint, alpha); return this; } /** * draw arc * @param {number} x0 - x-start * @param {number} y0 - y-start * @param {number} radius - radius * @param {number} start angle (radians) * @param {number} end angle (radians) * @param {number} tint * @param {number} alpha * @returns {Pixelate} */ }, { key: 'arc', value: function arc(x0, y0, radius, start, end, tint, alpha) { var interval = Math.PI / radius / 4; var points = []; for (var i = start; i <= end; i += interval) { points.push([Math.floor(x0 + Math.cos(i) * radius), Math.floor(y0 + Math.sin(i) * radius)]); } this.drawPoints(points, tint, alpha); return this; } /** * empties cache of old sprites */ }, { key: 'flush', value: function flush() { this.cache = []; } }], [{ key: 'texture', get: function get() { return Pixelate._texture; }, set: function set(value) { Pixelate._texture = value; } }]); return Pixelate; }(PIXI.Container); Pixelate._texture = PIXI.Texture.WHITE; module.exports = Pixelate; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9waXhlbGF0ZS5qcyJdLCJuYW1lcyI6WyJQSVhJIiwicmVxdWlyZSIsIkFuZ2xlIiwiUGl4ZWxhdGUiLCJjdXJzb3IiLCJ4IiwieSIsInRpbnQiLCJfbGluZVN0eWxlIiwid2lkdGgiLCJhbHBoYSIsImRpcmVjdGlvbiIsImNhY2hlIiwiY2hpbGRyZW4iLCJsZW5ndGgiLCJwdXNoIiwicG9wIiwicG9pbnQiLCJhZGRDaGlsZCIsIlNwcml0ZSIsInRleHR1cmUiLCJwb2ludHMiLCJpc05hTiIsImkiLCJnZXRQb2ludCIsInBvc2l0aW9uIiwic2V0IiwiaGVpZ2h0IiwieDAiLCJ5MCIsIngxIiwieTEiLCJsaW5lV2lkdGgiLCJsaW5lRGlyZWN0aW9uIiwiZHJhd1BvaW50cyIsImxpbmVQb2ludHMiLCJhbmdsZSIsImFuZ2xlVHdvUG9pbnRzIiwiTWF0aCIsIlBJIiwiY29zIiwic2luIiwiaGFsZiIsInJvdW5kIiwicG9seWdvbkZpbGwiLCJkeCIsImR5IiwiYWR4IiwiYWJzIiwiYWR5IiwiZXBzIiwic3giLCJzeSIsImEiLCJzZWVuIiwiZmlsdGVyIiwiaXRlbSIsImtleSIsImhhc093blByb3BlcnR5IiwiaGFzaFVuaXF1ZSIsInJhZGl1cyIsImRlY2lzaW9uT3ZlcjIiLCJyZWN0UG9pbnRzIiwidG9wIiwiYm90dG9tIiwibGVmdCIsInJpZ2h0IiwieGMiLCJ5YyIsInJ4IiwicnkiLCJwIiwidmVydGljZXMiLCJtb2QiLCJuIiwibSIsImVkZ2VzIiwiYWN0aXZlIiwibWluWSIsIkluZmluaXR5IiwibWF4WSIsInAxIiwicDIiLCJlZGdlIiwibWluWCIsIm1heCIsInNsb3BlIiwiYiIsInNvcnQiLCJzcGxpY2UiLCJiaXQiLCJjdXJyZW50Iiwic3RhcnQiLCJlbmQiLCJpbnRlcnZhbCIsImZsb29yIiwiX3RleHR1cmUiLCJ2YWx1ZSIsIkNvbnRhaW5lciIsIlRleHR1cmUiLCJXSElURSIsIm1vZHVsZSIsImV4cG9ydHMiXSwibWFwcGluZ3MiOiI7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