pixi-dashed-line2
Version:
A pixi.js implementation to support dashed lines in PIXI.Graphics.
358 lines • 13.8 kB
JavaScript
"use strict";
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
exports.__esModule = true;
exports.DashLine = void 0;
var PIXI = require("pixi.js");
var dashLineOptionsDefault = {
dash: [10, 5],
width: 1,
color: 0xffffff,
alpha: 1,
scale: 1,
useTexture: false,
alignment: 0.5
};
var DashLine = /** @class */ (function () {
/**
* Create a DashLine
* @param graphics
* @param [options]
* @param [options.useTexture=false] - use the texture based render (useful for very large or very small dashed lines)
* @param [options.dashes=[10,5] - an array holding the dash and gap (eg, [10, 5, 20, 5, ...])
* @param [options.width=1] - width of the dashed line
* @param [options.alpha=1] - alpha of the dashed line
* @param [options.color=0xffffff] - color of the dashed line
* @param [options.cap] - add a PIXI.LINE_CAP style to dashed lines (only works for useTexture: false)
* @param [options.join] - add a PIXI.LINE_JOIN style to the dashed lines (only works for useTexture: false)
* @param [options.alignment] - The alignment of any lines drawn (0.5 = middle, 1 = outer, 0 = inner)
*/
function DashLine(graphics, options) {
if (options === void 0) { options = {}; }
/** cursor location */
this.cursor = new PIXI.Point();
/** desired scale of line */
this.scale = 1;
this.graphics = graphics;
options = __assign(__assign({}, dashLineOptionsDefault), options);
this.dash = options.dash;
this.dashSize = this.dash.reduce(function (a, b) { return a + b; });
this.useTexture = options.useTexture;
this.options = options;
this.setLineStyle();
}
/** resets line style to enable dashed line (useful if lineStyle was changed on graphics element) */
DashLine.prototype.setLineStyle = function () {
var options = this.options;
if (this.useTexture) {
var texture = DashLine.getTexture(options, this.dashSize);
this.graphics.lineTextureStyle({
width: options.width * options.scale,
color: options.color,
alpha: options.alpha,
texture: texture,
alignment: options.alignment
});
this.activeTexture = texture;
}
else {
this.graphics.lineStyle({
width: options.width * options.scale,
color: options.color,
alpha: options.alpha,
cap: options.cap,
join: options.join,
alignment: options.alignment
});
}
this.scale = options.scale;
};
DashLine.distance = function (x1, y1, x2, y2) {
return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
};
DashLine.prototype.moveTo = function (x, y) {
this.lineLength = 0;
this.cursor.set(x, y);
this.start = new PIXI.Point(x, y);
this.graphics.moveTo(this.cursor.x, this.cursor.y);
return this;
};
DashLine.prototype.lineTo = function (x, y, closePath) {
if (typeof this.lineLength === undefined) {
this.moveTo(0, 0);
}
var length = DashLine.distance(this.cursor.x, this.cursor.y, x, y);
var angle = Math.atan2(y - this.cursor.y, x - this.cursor.x);
var closed = closePath && x === this.start.x && y === this.start.y;
if (this.useTexture) {
this.graphics.moveTo(this.cursor.x, this.cursor.y);
this.adjustLineStyle(angle);
if (closed && this.dash.length % 2 === 0) {
var gap = Math.min(this.dash[this.dash.length - 1], length);
this.graphics.lineTo(x - Math.cos(angle) * gap, y - Math.sin(angle) * gap);
this.graphics.closePath();
}
else {
this.graphics.lineTo(x, y);
}
}
else {
var cos = Math.cos(angle);
var sin = Math.sin(angle);
var x0 = this.cursor.x;
var y0 = this.cursor.y;
// find the first part of the dash for this line
var place = this.lineLength % (this.dashSize * this.scale);
var dashIndex = 0, dashStart = 0;
var dashX = 0;
for (var i = 0; i < this.dash.length; i++) {
var dashSize = this.dash[i] * this.scale;
if (place < dashX + dashSize) {
dashIndex = i;
dashStart = place - dashX;
break;
}
else {
dashX += dashSize;
}
}
var remaining = length;
// let count = 0
while (remaining > 0) { // && count++ < 1000) {
var dashSize = this.dash[dashIndex] * this.scale - dashStart;
var dist = remaining > dashSize ? dashSize : remaining;
if (closed) {
var remainingDistance = DashLine.distance(x0 + cos * dist, y0 + sin * dist, this.start.x, this.start.y);
if (remainingDistance <= dist) {
if (dashIndex % 2 === 0) {
var lastDash = DashLine.distance(x0, y0, this.start.x, this.start.y) - this.dash[this.dash.length - 1] * this.scale;
x0 += cos * lastDash;
y0 += sin * lastDash;
this.graphics.lineTo(x0, y0);
}
break;
}
}
x0 += cos * dist;
y0 += sin * dist;
if (dashIndex % 2) {
this.graphics.moveTo(x0, y0);
}
else {
this.graphics.lineTo(x0, y0);
}
remaining -= dist;
dashIndex++;
dashIndex = dashIndex === this.dash.length ? 0 : dashIndex;
dashStart = 0;
}
// if (count >= 1000) console.log('failure', this.scale)
}
this.lineLength += length;
this.cursor.set(x, y);
return this;
};
DashLine.prototype.closePath = function () {
this.lineTo(this.start.x, this.start.y, true);
};
DashLine.prototype.drawCircle = function (x, y, radius, points, matrix) {
if (points === void 0) { points = 80; }
var interval = Math.PI * 2 / points;
var angle = 0, first;
if (matrix) {
first = new PIXI.Point(x + Math.cos(angle) * radius, y + Math.sin(angle) * radius);
matrix.apply(first, first);
this.moveTo(first[0], first[1]);
}
else {
first = new PIXI.Point(x + Math.cos(angle) * radius, y + Math.sin(angle) * radius);
this.moveTo(first.x, first.y);
}
angle += interval;
for (var i = 1; i < points + 1; i++) {
var next = i === points ? first : [x + Math.cos(angle) * radius, y + Math.sin(angle) * radius];
this.lineTo(next[0], next[1]);
angle += interval;
}
return this;
};
DashLine.prototype.arc = function (cx, cy, radius, startAngle, endAngle, points) {
if (points === void 0) { points = 80; }
var interval = (endAngle - startAngle) / points;
var angle = startAngle;
for (var i = 0; i < points + 1; i++) {
var next = [cx + Math.cos(angle) * radius, cy + Math.sin(angle) * radius];
if (i === 0) {
this.moveTo(next[0], next[1]);
}
else {
this.lineTo(next[0], next[1]);
}
angle += interval;
}
return this;
};
DashLine.prototype.drawEllipse = function (x, y, radiusX, radiusY, points, matrix) {
if (points === void 0) { points = 80; }
var interval = Math.PI * 2 / points;
var first;
var point = new PIXI.Point();
var f = 0;
for (var i = 0; i < Math.PI * 2; i += interval) {
var x0 = x - radiusX * Math.sin(i);
var y0 = y - radiusY * Math.cos(i);
if (matrix) {
point.set(x0, y0);
matrix.apply(point, point);
x0 = point.x;
y0 = point.y;
}
if (i === 0) {
this.moveTo(x0, y0);
first = { x: x0, y: y0 };
}
else {
this.lineTo(x0, y0);
}
}
this.lineTo(first.x, first.y, true);
return this;
};
DashLine.prototype.drawPolygon = function (points, matrix) {
var p = new PIXI.Point();
if (typeof points[0] === 'number') {
if (matrix) {
p.set(points[0], points[1]);
matrix.apply(p, p);
this.moveTo(p.x, p.y);
for (var i = 2; i < points.length; i += 2) {
p.set(points[i], points[i + 1]);
matrix.apply(p, p);
this.lineTo(p.x, p.y, i === points.length - 2);
}
}
else {
this.moveTo(points[0], points[1]);
for (var i = 2; i < points.length; i += 2) {
this.lineTo(points[i], points[i + 1], i === points.length - 2);
}
}
}
else {
if (matrix) {
var point = points[0];
p.copyFrom(point);
matrix.apply(p, p);
this.moveTo(p.x, p.y);
for (var i = 1; i < points.length; i++) {
var point_1 = points[i];
p.copyFrom(point_1);
matrix.apply(p, p);
this.lineTo(p.x, p.y, i === points.length - 1);
}
}
else {
var point = points[0];
this.moveTo(point.x, point.y);
for (var i = 1; i < points.length; i++) {
var point_2 = points[i];
this.lineTo(point_2.x, point_2.y, i === points.length - 1);
}
}
}
return this;
};
DashLine.prototype.drawRect = function (x, y, width, height, matrix) {
if (matrix) {
var p = new PIXI.Point();
// moveTo(x, y)
p.set(x, y);
matrix.apply(p, p);
this.moveTo(p.x, p.y);
// lineTo(x + width, y)
p.set(x + width, y);
matrix.apply(p, p);
this.lineTo(p.x, p.y);
// lineTo(x + width, y + height)
p.set(x + width, y + height);
matrix.apply(p, p);
this.lineTo(p.x, p.y);
// lineto(x, y + height)
p.set(x, y + height);
matrix.apply(p, p);
this.lineTo(p.x, p.y);
// lineTo(x, y, true)
p.set(x, y);
matrix.apply(p, p);
this.lineTo(p.x, p.y, true);
}
else {
this.moveTo(x, y)
.lineTo(x + width, y)
.lineTo(x + width, y + height)
.lineTo(x, y + height)
.lineTo(x, y, true);
}
return this;
};
// adjust the matrix for the dashed texture
DashLine.prototype.adjustLineStyle = function (angle) {
var lineStyle = this.graphics.line;
lineStyle.matrix = new PIXI.Matrix();
if (angle) {
lineStyle.matrix.rotate(angle);
}
if (this.scale !== 1)
lineStyle.matrix.scale(this.scale, this.scale);
var textureStart = -this.lineLength;
lineStyle.matrix.translate(this.cursor.x + textureStart * Math.cos(angle), this.cursor.y + textureStart * Math.sin(angle));
this.graphics.lineStyle(lineStyle);
};
// creates or uses cached texture
DashLine.getTexture = function (options, dashSize) {
var key = options.dash.toString();
if (DashLine.dashTextureCache[key]) {
return DashLine.dashTextureCache[key];
}
var canvas = document.createElement("canvas");
canvas.width = dashSize;
canvas.height = Math.ceil(options.width);
var context = canvas.getContext("2d");
if (!context) {
console.warn('Did not get context from canvas');
return;
}
context.strokeStyle = "white";
context.globalAlpha = options.alpha;
context.lineWidth = options.width;
var x = 0;
var y = options.width / 2;
context.moveTo(x, y);
for (var i = 0; i < options.dash.length; i += 2) {
x += options.dash[i];
context.lineTo(x, y);
if (options.dash.length !== i + 1) {
x += options.dash[i + 1];
context.moveTo(x, y);
}
}
context.stroke();
var texture = DashLine.dashTextureCache[key] = PIXI.Texture.from(canvas);
texture.baseTexture.scaleMode = PIXI.SCALE_MODES.NEAREST;
return texture;
};
// cache of PIXI.Textures for dashed lines
DashLine.dashTextureCache = {};
return DashLine;
}());
exports.DashLine = DashLine;
//# sourceMappingURL=index.js.map