diff --git a/README.md b/README.md index ea5ddbb3..9e7b37af 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,18 @@ With your support, I can make pixi-viewport even better! Please consider making +## v5+ +Moves pixi-viewport to pixi.js v7 (thanks [@cuire](https://github.com/cuire)!). + +NOTE: there is a breaking change since pixi-viewport moved to pixi's new event system. `options.interaction` is removed and you need pass `options.events` to the viewport for it to work properly. The events object can be found at pixi's `renderer.events` or `app.renderer.events`. + +```js +const viewport = new Viewport({ events: renderer.events }); + +// or +// const viewport = new Viewport({ events: app.renderer.events }); +``` + ## v4.30.0+ This project was migrated to Typescript (thanks [@ShukantPal](https://github.com/ShukantPal)!). All functionality should be the same. The live Example has been updated. @@ -40,7 +52,7 @@ const viewport = new Viewport({ worldWidth: 1000, worldHeight: 1000, - interaction: app.renderer.plugins.interaction // the interaction module is important for wheel to work properly when renderer.view is placed or scaled + events: app.renderer.events // the interaction module is important for wheel to work properly when renderer.view is placed or scaled }) // add the viewport to the stage @@ -118,9 +130,6 @@ viewport.plugins.add('name', plugin, index) PRs are more than welcome! -## v4.30.0+ -This project was migrated to Typescript (thanks [@sukantpal](https://github.com/SukantPal)!). All functionality should be the same. The live Example has been updated. - ## Other Libraries If you liked pixi-viewport, please try my other open source libraries: * [pixi-scrollbox](https://github.com/davidfig/pixi-scrollbox) - pixi.js scrollbox: a masked box that can scroll vertically or horizontally with scrollbars (uses pixi-viewport) @@ -129,4 +138,4 @@ If you liked pixi-viewport, please try my other open source libraries: ## license MIT License -(c) 2021 [YOPEY YOPEY LLC](https://yopeyopey.com/) by David Figatner (david@yopeyopey.com) +(c) 2023 [YOPEY YOPEY LLC](https://yopeyopey.com/) by David Figatner (david@yopeyopey.com) diff --git a/docs/src/code.js b/docs/src/code.js index 86474958..456fa6b4 100644 --- a/docs/src/code.js +++ b/docs/src/code.js @@ -25,7 +25,7 @@ let _fps, _application, _viewport, _object, _stars = [], domEase function viewport() { _viewport = _application.stage.addChild(new Viewport( { - interaction: _application.renderer.plugins.interaction, + events: _application.renderer.events, passiveWheel: false, stopPropagation: true })) diff --git a/index.d.ts b/index.d.ts index eed726b6..6550a156 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,13 +1,14 @@ import { Container } from '@pixi/display'; import type { DisplayObject } from '@pixi/display'; +import type { EventSystem } from '@pixi/events'; +import type { FederatedEvent } from '@pixi/events'; +import type { FederatedPointerEvent } from '@pixi/events'; import type { IDestroyOptions } from '@pixi/display'; -import type { IHitArea } from '@pixi/interaction'; -import type { InteractionEvent } from '@pixi/interaction'; -import type { InteractionManager } from '@pixi/interaction'; -import { IPointData } from '@pixi/math'; -import { Point } from '@pixi/math'; -import { Rectangle } from '@pixi/math'; -import { Ticker } from '@pixi/ticker'; +import type { IHitArea } from '@pixi/events'; +import { IPointData } from '@pixi/core'; +import { Point } from '@pixi/core'; +import { Rectangle } from '@pixi/core'; +import { Ticker } from '@pixi/core'; export declare class Animate extends Plugin_2 { readonly options: IAnimateOptions & { @@ -95,10 +96,7 @@ export declare class Decelerate extends Plugin_2 { down(): boolean; isActive(): boolean; move(): boolean; - protected moved(data: { - type: 'clamp-x' | 'clamp-y'; - original: Point; - }): void; + protected handleMoved(e: MovedEvent): void; up(): boolean; activate(options: { x?: number; @@ -127,12 +125,12 @@ export declare class Drag extends Plugin_2 { destroy(): void; protected mouseButtons(buttons: string): void; protected parseUnderflow(): void; - protected checkButtons(event: InteractionEvent): boolean; - protected checkKeyPress(event: InteractionEvent): boolean; - down(event: InteractionEvent): boolean; + protected checkButtons(event: FederatedPointerEvent): boolean; + protected checkKeyPress(event: FederatedPointerEvent): boolean; + down(event: FederatedPointerEvent): boolean; get active(): boolean; - move(event: InteractionEvent): boolean; - up(event: InteractionEvent): boolean; + move(event: FederatedPointerEvent): boolean; + up(event: FederatedPointerEvent): boolean; wheel(event: WheelEvent): boolean; resume(): void; clamp(): void; @@ -264,11 +262,11 @@ export declare class InputManager { constructor(viewport: Viewport); private addListeners; destroy(): void; - down(event: InteractionEvent): void; + down(event: FederatedPointerEvent): void; clear(): void; checkThreshold(change: number): boolean; - move(event: InteractionEvent): void; - up(event: InteractionEvent): void; + move(event: FederatedPointerEvent): void; + up(event: FederatedPointerEvent): void; getPointerPosition(event: WheelEvent): Point; handleWheel(event: WheelEvent): void; pause(): void; @@ -324,11 +322,9 @@ export declare interface IViewportOptions { stopPropagation?: boolean; forceHitArea?: Rectangle | null; noTicker?: boolean; - interaction?: InteractionManager | null; + events: EventSystem; disableOnContextMenu?: boolean; - divWheel?: HTMLElement; ticker?: Ticker; - useDivWheelForInputManager?: boolean; } export declare interface IViewportTouch { @@ -369,13 +365,19 @@ export declare class MouseEdges extends Plugin_2 { constructor(parent: Viewport, options?: IMouseEdgesOptions); resize(): void; down(): boolean; - move(event: InteractionEvent): boolean; + move(event: FederatedPointerEvent): boolean; private decelerateHorizontal; private decelerateVertical; up(): boolean; update(): void; } +declare type MovedEvent = { + viewport: Viewport; + type: 'wheel' | 'pinch' | 'animate' | 'ensureVisible' | 'snap' | 'mouse-edges' | 'follow' | 'drag' | 'decelerate' | 'clamp-x' | 'clamp-y' | 'bounce-x' | 'bounce-y'; + original?: Point_2; +}; + export declare class Pinch extends Plugin_2 { readonly options: Required; active: boolean; @@ -386,7 +388,7 @@ export declare class Pinch extends Plugin_2 { down(): boolean; isAxisX(): boolean; isAxisY(): boolean; - move(e: InteractionEvent): boolean; + move(e: FederatedPointerEvent): boolean; up(): boolean; } @@ -395,9 +397,9 @@ declare class Plugin_2 { paused: boolean; constructor(parent: Viewport); destroy(): void; - down(_e: InteractionEvent): boolean; - move(_e: InteractionEvent): boolean; - up(_e: InteractionEvent): boolean; + down(_e: FederatedEvent): boolean; + move(_e: FederatedEvent): boolean; + up(_e: FederatedEvent): boolean; wheel(_e: WheelEvent): boolean | undefined; update(_delta: number): void; resize(): void; @@ -434,9 +436,9 @@ export declare class PluginManager { pause(name: string): void; resume(name: string): void; sort(): void; - down(event: InteractionEvent): boolean; - move(event: InteractionEvent): boolean; - up(event: InteractionEvent): boolean; + down(event: FederatedEvent): boolean; + move(event: FederatedEvent): boolean; + up(event: FederatedEvent): boolean; wheel(e: WheelEvent): boolean; } @@ -493,9 +495,7 @@ export declare class Viewport extends Container { readonly plugins: PluginManager; zooming?: boolean; lastViewport?: IViewportTransformState | null; - readonly options: ICompleteViewportOptions & { - divWheel: HTMLElement; - }; + readonly options: ICompleteViewportOptions; private _dirty?; private _forceHitArea?; private _hitAreaDefault?; @@ -504,7 +504,7 @@ export declare class Viewport extends Container { private _worldWidth?; private _worldHeight?; private _disableOnContextMenu; - constructor(options?: IViewportOptions); + constructor(options: IViewportOptions); destroy(options?: IDestroyOptions): void; update(elapsed: number): void; resize(screenWidth?: number, screenHeight?: number, worldWidth?: number, worldHeight?: number): void; diff --git a/package.json b/package.json index 298b4c88..7dd959f8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pixi-viewport", - "version": "4.38.0", + "version": "5.0.0", "description": "A highly configurable viewport/2D camera designed to work with pixi.js. Features include dragging, pinch-to-zoom, mouse wheel zooming, decelerated dragging, follow target, snap to point, snap to zoom, clamping, bouncing on edges, and move on mouse edges.", "main": "dist/cjs/viewport.js", "module": "dist/esm/viewport.es.js", @@ -23,7 +23,7 @@ "docs": "vite build && rimraf ./js && tsc -p ./tsconfig-docs.json --outDir js && rimraf ./docs/dist/jsdoc/ && jsdoc -c .jsdoc.json && node ./scripts/copy", "docs:serve": "vite preview --outDir dist/", "upgrade": "yarn upgrade-interactive --latest", - "prepublishOnly": "yarn build && yarn builds && yarn build:types && yarn docs" + "prepublishOnly": "yarn build && yarn docs" }, "repository": { "type": "git", diff --git a/src/InputManager.ts b/src/InputManager.ts index 81532fe4..993a1949 100644 --- a/src/InputManager.ts +++ b/src/InputManager.ts @@ -51,7 +51,7 @@ export class InputManager this.viewport.on('pointercancel', this.up, this); this.viewport.on('pointerout', this.up, this); this.wheelFunction = (e) => this.handleWheel(e); - this.viewport.options.divWheel.addEventListener( + this.viewport.options.events.domElement.addEventListener( 'wheel', this.wheelFunction as any, { passive: this.viewport.options.passiveWheel }); @@ -64,7 +64,7 @@ export class InputManager */ public destroy(): void { - this.viewport.options.divWheel.removeEventListener('wheel', this.wheelFunction as any); + this.viewport.options.events.domElement.removeEventListener('wheel', this.wheelFunction as any); } /** @@ -207,22 +207,7 @@ export class InputManager { const point = new Point(); - if (this.viewport.options.interaction) - { - this.viewport.options.interaction.mapPositionToPoint(point, event.clientX, event.clientY); - } - else if (this.viewport.options.useDivWheelForInputManager && this.viewport.options.divWheel) - { - const rect = this.viewport.options.divWheel.getBoundingClientRect(); - - point.x = event.clientX - rect.left; - point.y = event.clientY - rect.top; - } - else - { - point.x = event.clientX; - point.y = event.clientY; - } + this.viewport.options.events.mapPositionToPoint(point, event.clientX, event.clientY); return point; } @@ -235,13 +220,6 @@ export class InputManager return; } - // do not handle events coming from other elements - if (this.viewport.options.interaction - && (this.viewport.options.interaction as any).interactionDOMElement !== event.target) - { - return; - } - // only handle wheel events where the mouse is over the viewport const point = this.viewport.toLocal(this.getPointerPosition(event)); diff --git a/src/Viewport.ts b/src/Viewport.ts index 33cd92c6..40a382e5 100644 --- a/src/Viewport.ts +++ b/src/Viewport.ts @@ -69,36 +69,21 @@ export interface IViewportOptions noTicker?: boolean; /** - * EventSystem, available from instantiated `WebGLRenderer/CanvasRenderer.plugins.interaction` - * - * It's used to calculate pointer postion relative to canvas location on screen + * EventSystem is required now */ - interaction?: EventSystem | null; + events: EventSystem; /** - * Remove oncontextmenu=() => {} from the divWheel element + * Remove oncontextmenu=() => {} from options.events.domElement */ disableOnContextMenu?: boolean; - /** - * div to attach the wheel event - * - * @default document.body - */ - divWheel?: HTMLElement; - /** * Use this PIXI.ticker for updates * * @default PIXI.Ticker.shared */ ticker?: Ticker; - - /** - * Uses divWheel definition for InputManager to calculate positioning relative to containing div - * this is used only if options.interaction is not defined - */ - useDivWheelForInputManager?: boolean; } export interface ICompleteViewportOptions extends IViewportOptions @@ -120,7 +105,7 @@ export interface IViewportTransformState scaleY: number; } -const DEFAULT_VIEWPORT_OPTIONS: ICompleteViewportOptions = { +const DEFAULT_VIEWPORT_OPTIONS: Partial = { screenWidth: window.innerWidth, screenHeight: window.innerHeight, worldWidth: null, @@ -130,7 +115,6 @@ const DEFAULT_VIEWPORT_OPTIONS: ICompleteViewportOptions = { stopPropagation: false, forceHitArea: null, noTicker: false, - interaction: null, disableOnContextMenu: false, ticker: Ticker.shared, }; @@ -192,7 +176,7 @@ export class Viewport extends Container public lastViewport?: IViewportTransformState | null; /** The options passed when creating this viewport, merged with the default values */ - public readonly options: ICompleteViewportOptions & { divWheel: HTMLElement }; + public readonly options: ICompleteViewportOptions; private _dirty?: boolean; private _forceHitArea?: IHitArea | null; @@ -218,21 +202,17 @@ export class Viewport extends Container * @param {HitArea} [options.forceHitArea] change the default hitArea from world size to a new value * @param {boolean} [options.noTicker] set this if you want to manually call update() function on each frame * @param {PIXI.Ticker} [options.ticker=PIXI.Ticker.shared] use this PIXI.ticker for updates - * @param {PIXI.EventSystem} [options.interaction=null] EventSystem, available from instantiated - * WebGLRenderer/CanvasRenderer.plugins.interaction - used to calculate pointer position relative to canvas + * @param {PIXI.EventSystem} [options.events] EventSystem available from app.events or added manually and passed here * location on screen - * @param {HTMLElement} [options.divWheel=document.body] div to attach the wheel event - * @param {boolean} [options.disableOnContextMenu] remove oncontextmenu=() => {} from the divWheel element + * @param {boolean} [options.disableOnContextMenu] remove oncontextmenu=() => {} from the pixi's events.domElement */ - constructor(options: IViewportOptions = {}) + constructor(options: IViewportOptions) { super(); - this.options = Object.assign( - {}, - { divWheel: document.body }, - DEFAULT_VIEWPORT_OPTIONS, - options - ); + this.options = { + ...DEFAULT_VIEWPORT_OPTIONS, + ...options, + } as ICompleteViewportOptions; this.screenWidth = this.options.screenWidth; this.screenHeight = this.options.screenHeight; @@ -242,11 +222,9 @@ export class Viewport extends Container this.forceHitArea = this.options.forceHitArea; this.threshold = this.options.threshold; - this.options.divWheel = this.options.divWheel || document.body; - if (this.options.disableOnContextMenu) { - this.options.divWheel.addEventListener('contextmenu', this._disableOnContextMenu); + this.options.events.domElement.addEventListener('contextmenu', this._disableOnContextMenu); } if (!this.options.noTicker) { @@ -267,7 +245,7 @@ export class Viewport extends Container } if (this.options.disableOnContextMenu) { - this.options.divWheel.removeEventListener('contextmenu', this._disableOnContextMenu); + this.options.events.domElement.removeEventListener('contextmenu', this._disableOnContextMenu); } this.input.destroy(); @@ -1177,8 +1155,7 @@ export class Viewport extends Container /** * Zoom using mouse wheel * - * NOTE: the default event listener for 'wheel' event is document.body. Use `Viewport.options.divWheel` to - * change this default + * NOTE: the default event listener for 'wheel' event is the options.events.domElement. * * @param {IWheelOptions} [options] * @param {number} [options.percent=0.1] - percent to scroll with each spin