Source: sg2d-pointer.js

"use strict";

import SGModel from './libs/sg-model/sg-model.js';
import SG2DConsts from './sg2d-consts.js';
import SG2DUtils from './sg2d-utils.js';
import SG2DMath from "./sg2d-math.js";
import SG2DCamera from './sg2d-camera.js';

/**
 * Класс для управления указателем (мышь, тачпад)
 * @TODO To prevent the browser from creating a new request every time you change cursor url, you need to display cursor using PixiJS
 * @alias SG2D.Pointer
 */
class SG2DPointer extends SGModel {
	
	initialize(properties, thisProps, options) {
		
		// passed to thisProps: { sg2d: this }
		
		//this.camera = this.sg2d.camera;
		
		if (! SG2DPointer._newPosition) SG2DPointer._newPosition = new PIXI.Point();
		
		this.identifiers = [];
		for (var i = 0; i < SG2DPointer._maxIdentifiers; i++) {
			this.identifiers[i] = {
				target: { cluster: void 0, tile: void 0, sprite: void 0, pxy: this.properties.pxy, cxy: this.properties.cxy, pxy_local: {x: void 0, y: void 0} },
				options: { type: void 0, button: void 0 }
			}
		}
		
		this.on("pxy", ()=>{
			this.set("cxy", [Math.floor( 1 + this.properties.pxy.x / SG2DConsts.CELLSIZEPIX ), Math.floor( 1 + this.properties.pxy.y / SG2DConsts.CELLSIZEPIX )]);
		});
	}
	
	/** @private */
	_sg2dconnect(sg2d) {
		
		this.sg2d = sg2d;
		this.camera = this.sg2d.camera;
		
		this.properties.global = this.sg2d.pixi.renderer.plugins.interaction.mouse.global;
		
		this.sg2d.viewport.interactive = true;
		
		this.sg2d.viewport.on("pointerdown", this.pointerdown.bind(this));
		this.sg2d.viewport.on("pointerup", this.pointerup.bind(this));
		this.sg2d.viewport.on("pointermove", this.pointermove.bind(this));
		//this.sg2d.viewport.on("pointerover", this.pointerover.bind(this));
		//this.sg2d.canvas.addEventListener("pointerup", (e)=>{ debugger; });
		
		this.cursors = {}; // { default: "", hover: "", move: "", /*...*/}; // cursor icons
		for (var p in this.properties.cursors) {
			var s = this.properties.cursors[p];
			this.cursors[p] = s;
			this.sg2d.pixi.renderer.plugins.interaction.cursorStyles[p] = s;
		}
		this.properties.cursors;
		
		this.tCursorUpdater = setInterval(()=>{
			this.set("cursor", this.sg2d.pixi.renderer.plugins.interaction.currentCursorMode);
		}, 100);
	}
	
	/*getTileByPXY(pxy, bClick) {
		SG2DPointer._target.cluster = this.sg2d.clusters.getCluster(pxy.x, pxy.y);
		SG2DPointer._target.tile = null;
		SG2DPointer._target.sprite = null;
		SG2DPointer._target.pxy_local.x = void 0;
		SG2DPointer._target.pxy_local.y = void 0;
		for (var tile of SG2DPointer._target.cluster.bodies) {
			if (bClick && ! tile.click) continue;
			for (var sprite of tile.sprites) {
				//var mousePos = e.data.getLocalPosition(sprite);
				var mousePos = this.sg2d.pixi.renderer.plugins.interaction.mouse.getLocalPosition(sprite);
				if (sprite.getLocalBounds().contains(mousePos.x, mousePos.y)) {
					if (! SG2DPointer._target.sprite || SG2DPointer._target.sprite.zIndex > sprite.zIndex) {
						SG2DPointer._target.sprite = sprite;
						SG2DPointer._target.tile = tile;
					}
				}
			}
		}
		return SG2DPointer._target;
	}*/
	
	pointerdown(event) {
		
		if (! this.sg2d.clusters) return;
		if (event.data.identifier >= SG2DPointer._maxIdentifiers) return;
		
		let target = this.identifiers[event.data.identifier].target;
		let options = this.identifiers[event.data.identifier].options;
		
		options.button = event.data.button;
		options.type = event.type;
		
		target.cluster = this.sg2d.clusters.getCluster(this.properties.cxy.x, this.properties.cxy.y);
		target.tile = null;
		target.sprite = null;
		
		if (target.cluster) {
			for (var tile of target.cluster.bodies) {
				SG2DUtils.objectForEach(tile.sprites, sprite=>{
					if (! sprite.pixiSprites) return;
					this.sg2d.pixi.renderer.plugins.interaction.mouse.getLocalPosition(sprite.pixiSprite, target.pxy_local); // or e.data.getLocalPosition(..)
					if (sprite.getLocalBounds().contains(target.pxy_local.x, target.pxy_local.y)) {
						if (! target.sprite.pixiSprite || target.sprite.pixiSprite.zIndex > sprite.pixiSprite.zIndex) {
							target.sprite = sprite;
							target.tile = tile;
						}
					}
				});
			}
		}
		
		if (this.camera.properties.movement_by_pointer) {
			if (this.camera.properties.movement_state === SG2DCamera.STATE_NO_MOVEMENT) {
				if (
					(options.button === 0 && (this.camera.properties.movement_by_pointer & SG2DCamera.MOVEMENT_BY_POINTER_LEFT)) ||
					(options.button === 2 && (this.camera.properties.movement_by_pointer & SG2DCamera.MOVEMENT_BY_POINTER_RIGHT)) ||
					(options.button === 1 && (this.camera.properties.movement_by_pointer & SG2DCamera.MOVEMENT_BY_POINTER_MIDDLE))
				) {
					SG2DPointer._startPoint.x = SG2DPointer._newPosition.x;
					SG2DPointer._startPoint.y = SG2DPointer._newPosition.y;
					this.camera.set("movement_state", SG2DCamera.STATE_MOVEMENT_WAITING_SHIFT);
				}
			}
		}
	}
	
	pointermove(e) {
		if (this.camera.properties.movement_by_pointer) {
			if (this.camera.properties.movement_state === SG2DCamera.STATE_MOVEMENT_WAITING_SHIFT) {
				this.sg2d.viewport.cursor = "move";
				let d = SG2DMath.distance_p(SG2DPointer._startPoint, SG2DPointer._newPosition);
				if (d >= SG2DPointer.CAMERA_MOVEMENT_SHIFT) {
					SG2DPointer._startPoint.x =  this.properties.global.x;
					SG2DPointer._startPoint.y =  this.properties.global.y;
					SG2DPointer._startPointPXY.x = this.camera.properties.offset.x;
					SG2DPointer._startPointPXY.y = this.camera.properties.offset.y;
					this.camera.set("movement_state", SG2DCamera.STATE_MOVING);
				}
			} else if (this.camera.properties.movement_state === SG2DCamera.STATE_MOVING) {
				let k = this.camera.scales_k[this.camera.properties.scale];
				let dx = (this.properties.global.x - SG2DPointer._startPoint.x) / k;
				let dy = (this.properties.global.y - SG2DPointer._startPoint.y) / k;
				let rotate = this.camera.properties.rotate - this.camera.rotate_adjustment;
				SG2DPointer._position.x = SG2DPointer._startPointPXY.x - dx * SG2DMath.cos(rotate, 1) + dy * SG2DMath.sin(rotate, 1);
				SG2DPointer._position.y = SG2DPointer._startPointPXY.y - dy * SG2DMath.cos(rotate, 1) - dx * SG2DMath.sin(rotate, 1);
				this.camera.set("offset", SG2DPointer._position, SGModel.OPTIONS_PRECISION_5);
			}
		}
	}
	
	pointerup(event) {
		
		if (! this.sg2d.clusters) return;
		if (event.data.identifier >= SG2DPointer._maxIdentifiers) return;
		
		let target = this.identifiers[event.data.identifier].target;
		let options = this.identifiers[event.data.identifier].options;
		
		if (target.tile) {
			if (target.tile.constructor.click) target.tile.constructor.click(target, options);
			if (target.tile.click) target.tile.click(target, options);
		}
		
		if (this.camera.properties.movement_by_pointer) {
			if (this.camera.properties.movement_state) {
				this.sg2d.viewport.cursor = "default";
				let k = this.camera.scales_k[this.camera.properties.scale];
				let dx = (this.properties.global.x - SG2DPointer._startPoint.x) / k;
				let dy = (this.properties.global.y - SG2DPointer._startPoint.y) / k;
				this.camera.set("movement_state", SG2DCamera.STATE_NO_MOVEMENT);
			}
		}
		
		this.pointerclick(target, options);
	}
	
	pointerclick(e) {} // override
	
	iterate() {
		this.sg2d.pixi.renderer.plugins.interaction.mouse.getLocalPosition(this.sg2d.viewport, SG2DPointer._newPosition);
		SG2DPointer._newPosition.x = ~~SG2DPointer._newPosition.x;
		SG2DPointer._newPosition.y = ~~SG2DPointer._newPosition.y;
		this.set("pxy", [SG2DPointer._newPosition.x, SG2DPointer._newPosition.y]);
	}
	
	destroy() {
		this.tCursorUpdater && clearInterval(this.tCursorUpdater);
		super.destroy();
	}
}

SG2DPointer.typeProperties = {
	global: SGModel.TYPE_OBJECT_NUMBERS,
	camera: SGModel.TYPE_OBJECT_NUMBERS,
	pxy: SGModel.TYPE_OBJECT_NUMBERS,
	cxy: SGModel.TYPE_OBJECT_NUMBERS
};

SG2DPointer.POINTER_LEFT = 0;
SG2DPointer.POINTER_MIDDLE = 1;
SG2DPointer.POINTER_RIGHT = 2;

SG2DPointer.CAMERA_MOVEMENT_SHIFT = 10; // pixels

/** @private */
SG2DPointer._newPosition= void 0;

/** @private */
SG2DPointer._maxIdentifiers = 10;

SG2DPointer.defaultProperties = {
	global: void 0, // relative to the screen
	pxy: { x: 0, y: 0 }, // in the coordinates of the game world: PX
	cxy: { x: 0, y: 0 }, // in the coordinates of the game world: Cluster
	cursor: "default" // current cursor
};

/** @private */
SG2DPointer._position = {x: 0, y: 0};

/** @private */
SG2DPointer._startPoint = { x: 0, y: 0 };

/** @private */
SG2DPointer._startPointPXY = { x: 0, y: 0 };

export default SG2DPointer;