UNPKG

react-pixi-plot

Version:

A React component rendering a zoomable and draggable PIXI.js scene. Intended to render 2d plots

136 lines 6.35 kB
import { CustomPIXIComponent, AppContext } from 'react-pixi-fiber'; import * as PIXI from 'pixi.js'; import { preventGlobalMouseEvents, restoreGlobalMouseEvents } from '../../globalEvents'; import React from 'react'; import { PixiPlotContext } from '../../PlotContext'; const TYPE = 'DraggableContainer'; class DraggableContainerBehavior { constructor() { this.customDisplayObject = (props) => { const instance = new PIXI.Container(); instance.interactive = true; instance.hitArea = { contains: () => true }; instance.on('rightdown', (e) => { this.draggedInstance = instance; this.props = props; this.dragAnchor = e.data.getLocalPosition(this.draggedInstance.parent); e.stopPropagation(); this.captureMouseEvents(); }); instance.on('touchStart', (e) => { const originalEvent = e.data.originalEvent; this.draggedInstance = instance; if (originalEvent.targetTouches.length === 1) { this.dragAnchor = this.eventRendererPosition(originalEvent.targetTouches.item(0)); } else if (this.dragAnchor) { delete this.dragAnchor; } }); return instance; }; this.customWillDetach = (instance) => { instance.removeAllListeners(); }; /** * Correlates clicks on the renderer that happen * in screen space coordinates to renderer coordinates. * Used to understand where the mouse event occurred inside the renderer. * @method * @param {MouseEvent} mouseEvent The mouse event. * @returns {PIXI.Point} The Point object containing the coordinates of the mouse, * in the renderer's coordinates system. */ this.eventRendererPosition = (mouseEvent) => { const mousePosition = new PIXI.Point(); this.props.pixiInteractionManager .mapPositionToPoint(mousePosition, mouseEvent.clientX, mouseEvent.clientY); return mousePosition; }; /** * @todo stop the preventDefault for contextmenu event listener * from preventing right clicking in the entire Lodestone application. * Isolates mouse events to the visualization by adding event listeners * and preventing mouse defaults and event propagation. * Handles cancelling the right mouse context menu. * @method * @param {object} e The mouse event. * @returns {undefined} */ this.captureMouseEvents = () => { preventGlobalMouseEvents(); document.addEventListener('mouseup', this.mouseUpListener, true); document.addEventListener('mousemove', this.mouseMoveListener, true); document.addEventListener('contextmenu', ev => ev.preventDefault(), true); }; /** * Handles mouse button release. * Restores event listeners that were removed * during {@link PixiVisualization#captureMouseEvents|captureMouseEvents}, * enables holding shift and selecting more points, * and removing points from selections with the right mouse button. * @method * @param {object} e The mouse up event. * @returns {undefined} */ this.mouseUpListener = (e) => { restoreGlobalMouseEvents(); document.removeEventListener('mouseup', this.mouseUpListener, true); document.removeEventListener('mousemove', this.mouseMoveListener, true); document.removeEventListener('contextmenu', ev => ev.preventDefault(), true); e.preventDefault(); delete this.dragAnchor; }; /*handleTouchEnd = (e: React.TouchEvent<HTMLDivElement>) => { if (e.targetTouches.length === 0) { // no more touches delete this.dragAnchor; } }*/ /* = (e: React.TouchEvent<HTMLDivElement>) => { if (e.targetTouches.length === 1) { const touch = e.targetTouches.item(0); const touchPosition = this.eventRendererPosition(touch); if (this.dragAnchor !== undefined) { this.drag(this.dragAnchor, touchPosition); this.dragAnchor = touchPosition; } } }*/ /** * Handles mouse movement events. * If a selection has already been started this handles expanding the selection, * and handles panning to the new position if a pan is occuring. * @method * @param {object} e The mouse move event. * @returns {undefined} */ this.mouseMoveListener = (e) => { if (this.dragAnchor !== undefined) { e.stopPropagation(); e.preventDefault(); const mousePosition = this.eventRendererPosition(e); this.drag(this.dragAnchor, mousePosition); this.dragAnchor = mousePosition; } }; /** * Pans the view inside of the renderer based on the mouse position. * @method * @param {object} mousePosition The position seen inside the event which triggered * {@link PixiVisualization#mouseMoveListener|mouseMoveListener}. */ this.drag = (from, to) => { const { position } = this.draggedInstance; const nextXPos = position.x + (to.x - from.x); const nextYPos = position.y + (to.y - from.y); this.draggedInstance.position.set(nextXPos, nextYPos); this.props.dispatch({ type: 'drag', payload: { position: { x: nextXPos, y: nextYPos } } }); }; } } const DraggablePIXI = CustomPIXIComponent(new DraggableContainerBehavior(), TYPE); const DraggableContainer = (props) => { return (React.createElement(PixiPlotContext.Consumer, null, context => React.createElement(AppContext.Consumer, null, app => React.createElement(DraggablePIXI, { pixiInteractionManager: app.renderer.plugins.interaction, dispatch: context.dispatch }, props.children)))); }; export default DraggableContainer; //# sourceMappingURL=DraggableContainer.js.map