302 lines
9.0 KiB
JavaScript
302 lines
9.0 KiB
JavaScript
|
|
/**
|
||
|
|
* A CanvasLayer responsible for drawing a square grid
|
||
|
|
*/
|
||
|
|
class GridLayer extends CanvasLayer {
|
||
|
|
|
||
|
|
/**
|
||
|
|
* The grid mesh.
|
||
|
|
* @type {GridMesh}
|
||
|
|
*/
|
||
|
|
mesh;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* The Grid Highlight container
|
||
|
|
* @type {PIXI.Container}
|
||
|
|
*/
|
||
|
|
highlight;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Map named highlight layers
|
||
|
|
* @type {Record<string, GridHighlight>}
|
||
|
|
*/
|
||
|
|
highlightLayers = {};
|
||
|
|
|
||
|
|
/* -------------------------------------------- */
|
||
|
|
|
||
|
|
/** @inheritdoc */
|
||
|
|
static get layerOptions() {
|
||
|
|
return foundry.utils.mergeObject(super.layerOptions, {name: "grid"});
|
||
|
|
}
|
||
|
|
|
||
|
|
/* -------------------------------------------- */
|
||
|
|
|
||
|
|
/** @override */
|
||
|
|
async _draw(options) {
|
||
|
|
// Draw the highlight layer
|
||
|
|
this.highlightLayers = {};
|
||
|
|
this.highlight = this.addChild(new PIXI.Container());
|
||
|
|
this.highlight.sortableChildren = true;
|
||
|
|
|
||
|
|
// Draw the grid
|
||
|
|
this.mesh = this.addChild(await this._drawMesh());
|
||
|
|
// Initialize the mesh appeareance
|
||
|
|
this.initializeMesh(canvas.grid);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* -------------------------------------------- */
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Creates the grid mesh.
|
||
|
|
* @returns {Promise<GridMesh>}
|
||
|
|
* @protected
|
||
|
|
*/
|
||
|
|
async _drawMesh() {
|
||
|
|
return new GridMesh().initialize({
|
||
|
|
type: canvas.grid.type,
|
||
|
|
width: canvas.dimensions.width,
|
||
|
|
height: canvas.dimensions.height,
|
||
|
|
size: canvas.dimensions.size
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/* -------------------------------------------- */
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Initialize the grid mesh appearance and configure the grid shader.
|
||
|
|
* @param {object} options
|
||
|
|
* @param {string} [options.style] The grid style
|
||
|
|
* @param {number} [options.thickness] The grid thickness
|
||
|
|
* @param {string} [options.color] The grid color
|
||
|
|
* @param {number} [options.alpha] The grid alpha
|
||
|
|
*/
|
||
|
|
initializeMesh({style, thickness, color, alpha}) {
|
||
|
|
const {shaderClass, shaderOptions} = CONFIG.Canvas.gridStyles[style] ?? {};
|
||
|
|
this.mesh.initialize({thickness, color, alpha});
|
||
|
|
this.mesh.setShaderClass(shaderClass ?? GridShader);
|
||
|
|
this.mesh.shader.configure(shaderOptions ?? {});
|
||
|
|
}
|
||
|
|
|
||
|
|
/* -------------------------------------------- */
|
||
|
|
/* Grid Highlighting Methods
|
||
|
|
/* -------------------------------------------- */
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Define a new Highlight graphic
|
||
|
|
* @param {string} name The name for the referenced highlight layer
|
||
|
|
*/
|
||
|
|
addHighlightLayer(name) {
|
||
|
|
const layer = this.highlightLayers[name];
|
||
|
|
if ( !layer || layer._destroyed ) {
|
||
|
|
this.highlightLayers[name] = this.highlight.addChild(new GridHighlight(name));
|
||
|
|
}
|
||
|
|
return this.highlightLayers[name];
|
||
|
|
}
|
||
|
|
|
||
|
|
/* -------------------------------------------- */
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Clear a specific Highlight graphic
|
||
|
|
* @param {string} name The name for the referenced highlight layer
|
||
|
|
*/
|
||
|
|
clearHighlightLayer(name) {
|
||
|
|
const layer = this.highlightLayers[name];
|
||
|
|
if ( layer ) layer.clear();
|
||
|
|
}
|
||
|
|
|
||
|
|
/* -------------------------------------------- */
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Destroy a specific Highlight graphic
|
||
|
|
* @param {string} name The name for the referenced highlight layer
|
||
|
|
*/
|
||
|
|
destroyHighlightLayer(name) {
|
||
|
|
const layer = this.highlightLayers[name];
|
||
|
|
if ( layer ) {
|
||
|
|
this.highlight.removeChild(layer);
|
||
|
|
layer.destroy();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/* -------------------------------------------- */
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Obtain the highlight layer graphic by name
|
||
|
|
* @param {string} name The name for the referenced highlight layer
|
||
|
|
*/
|
||
|
|
getHighlightLayer(name) {
|
||
|
|
return this.highlightLayers[name];
|
||
|
|
}
|
||
|
|
|
||
|
|
/* -------------------------------------------- */
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Add highlighting for a specific grid position to a named highlight graphic
|
||
|
|
* @param {string} name The name for the referenced highlight layer
|
||
|
|
* @param {object} [options] Options for the grid position that should be highlighted
|
||
|
|
* @param {number} [options.x] The x-coordinate of the highlighted position
|
||
|
|
* @param {number} [options.y] The y-coordinate of the highlighted position
|
||
|
|
* @param {PIXI.ColorSource} [options.color=0x33BBFF] The fill color of the highlight
|
||
|
|
* @param {PIXI.ColorSource|null} [options.border=null] The border color of the highlight
|
||
|
|
* @param {number} [options.alpha=0.25] The opacity of the highlight
|
||
|
|
* @param {PIXI.Polygon} [options.shape=null] A predefined shape to highlight
|
||
|
|
*/
|
||
|
|
highlightPosition(name, {x, y, color=0x33BBFF, border=null, alpha=0.25, shape=null}) {
|
||
|
|
const layer = this.highlightLayers[name];
|
||
|
|
if ( !layer ) return;
|
||
|
|
const grid = canvas.grid;
|
||
|
|
if ( grid.type !== CONST.GRID_TYPES.GRIDLESS ) {
|
||
|
|
const cx = x + (grid.sizeX / 2);
|
||
|
|
const cy = y + (grid.sizeY / 2);
|
||
|
|
const points = grid.getShape();
|
||
|
|
for ( const point of points ) {
|
||
|
|
point.x += cx;
|
||
|
|
point.y += cy;
|
||
|
|
}
|
||
|
|
shape = new PIXI.Polygon(points);
|
||
|
|
} else if ( !shape ) return;
|
||
|
|
if ( !layer.highlight(x, y) ) return;
|
||
|
|
layer.beginFill(color, alpha);
|
||
|
|
if ( border !== null ) layer.lineStyle(2, border, Math.min(alpha * 1.5, 1.0));
|
||
|
|
layer.drawShape(shape).endFill();
|
||
|
|
}
|
||
|
|
|
||
|
|
/* -------------------------------------------- */
|
||
|
|
/* Deprecations and Compatibility */
|
||
|
|
/* -------------------------------------------- */
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @deprecated since v12
|
||
|
|
* @ignore
|
||
|
|
*/
|
||
|
|
get type() {
|
||
|
|
const msg = "GridLayer#type is deprecated. Use canvas.grid.type instead.";
|
||
|
|
foundry.utils.logCompatibilityWarning(msg, {since: 12, until: 14, once: true});
|
||
|
|
return canvas.grid.type;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* -------------------------------------------- */
|
||
|
|
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @deprecated since v12
|
||
|
|
* @ignore
|
||
|
|
*/
|
||
|
|
get size() {
|
||
|
|
const msg = "GridLayer#size is deprecated. Use canvas.grid.size instead.";
|
||
|
|
foundry.utils.logCompatibilityWarning(msg, {since: 12, until: 14, once: true});
|
||
|
|
return canvas.grid.size;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* -------------------------------------------- */
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @deprecated since v12
|
||
|
|
* @ignore
|
||
|
|
*/
|
||
|
|
get grid() {
|
||
|
|
const msg = "GridLayer#grid is deprecated. Use canvas.grid instead.";
|
||
|
|
foundry.utils.logCompatibilityWarning(msg, {since: 12, until: 14, once: true});
|
||
|
|
return canvas.grid;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* -------------------------------------------- */
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @deprecated since v12
|
||
|
|
* @ignore
|
||
|
|
*/
|
||
|
|
isNeighbor(r0, c0, r1, c1) {
|
||
|
|
const msg = "GridLayer#isNeighbor is deprecated. Use canvas.grid.testAdjacency instead.";
|
||
|
|
foundry.utils.logCompatibilityWarning(msg, {since: 12, until: 14, once: true});
|
||
|
|
return canvas.grid.testAdjacency({i: r0, j: c0}, {i: r1, j: c1});
|
||
|
|
}
|
||
|
|
|
||
|
|
/* -------------------------------------------- */
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @deprecated since v12
|
||
|
|
* @ignore
|
||
|
|
*/
|
||
|
|
get w() {
|
||
|
|
const msg = "GridLayer#w is deprecated in favor of canvas.grid.sizeX.";
|
||
|
|
foundry.utils.logCompatibilityWarning(msg, {since: 12, until: 14, once: true});
|
||
|
|
return canvas.grid.sizeX;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* -------------------------------------------- */
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @deprecated since v12
|
||
|
|
* @ignore
|
||
|
|
*/
|
||
|
|
get h() {
|
||
|
|
const msg = "GridLayer#h is deprecated in favor of canvas.grid.sizeY.";
|
||
|
|
foundry.utils.logCompatibilityWarning(msg, {since: 12, until: 14, once: true});
|
||
|
|
return canvas.grid.sizeY;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* -------------------------------------------- */
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @deprecated since v12
|
||
|
|
* @ignore
|
||
|
|
*/
|
||
|
|
get isHex() {
|
||
|
|
const msg = "GridLayer#isHex is deprecated. Use canvas.grid.isHexagonal instead.";
|
||
|
|
foundry.utils.logCompatibilityWarning(msg, {since: 12, until: 14, once: true});
|
||
|
|
return canvas.grid.isHexagonal;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* -------------------------------------------- */
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @deprecated since v12
|
||
|
|
* @ignore
|
||
|
|
*/
|
||
|
|
getTopLeft(x, y) {
|
||
|
|
const msg = "GridLayer#getTopLeft is deprecated. Use canvas.grid.getTopLeftPoint instead.";
|
||
|
|
foundry.utils.logCompatibilityWarning(msg, {since: 12, until: 14, once: true});
|
||
|
|
return canvas.grid.getTopLeft(x, y);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* -------------------------------------------- */
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @deprecated since v12
|
||
|
|
* @ignore
|
||
|
|
*/
|
||
|
|
getCenter(x, y) {
|
||
|
|
const msg = "GridLayer#getCenter is deprecated. Use canvas.grid.getCenterPoint instead.";
|
||
|
|
foundry.utils.logCompatibilityWarning(msg, {since: 12, until: 14, once: true});
|
||
|
|
return canvas.grid.getCenter(x, y);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* -------------------------------------------- */
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @deprecated since v12
|
||
|
|
* @ignore
|
||
|
|
*/
|
||
|
|
getSnappedPosition(x, y, interval=1, options={}) {
|
||
|
|
const msg = "GridLayer#getSnappedPosition is deprecated. Use canvas.grid.getSnappedPoint instead.";
|
||
|
|
foundry.utils.logCompatibilityWarning(msg, {since: 12, until: 14, once: true});
|
||
|
|
if ( interval === 0 ) return {x: Math.round(x), y: Math.round(y)};
|
||
|
|
return canvas.grid.getSnappedPosition(x, y, interval, options);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* -------------------------------------------- */
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @deprecated since v12
|
||
|
|
* @ignore
|
||
|
|
*/
|
||
|
|
measureDistance(origin, target, options={}) {
|
||
|
|
const msg = "GridLayer#measureDistance is deprecated. "
|
||
|
|
+ "Use canvas.grid.measurePath instead for non-Euclidean measurements.";
|
||
|
|
foundry.utils.logCompatibilityWarning(msg, {since: 12, until: 14, once: true});
|
||
|
|
const ray = new Ray(origin, target);
|
||
|
|
const segments = [{ray}];
|
||
|
|
return canvas.grid.measureDistances(segments, options)[0];
|
||
|
|
}
|
||
|
|
}
|