123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228 |
- import * as React from "react";
- import { Vector2 } from 'babylonjs/Maths/math.vector';
- import { KeyframeSvgPoint, IKeyframeSvgPoint } from './keyframeSvgPoint';
- interface ISvgDraggableAreaProps {
- keyframeSvgPoints: IKeyframeSvgPoint[];
- updatePosition: (updatedKeyframe: IKeyframeSvgPoint, index: number) => void;
- scale: number;
- viewBoxScale: number;
- selectKeyframe: (id: string) => void;
- selectedControlPoint: (type: string, id: string) => void;
- }
- export class SvgDraggableArea extends React.Component<ISvgDraggableAreaProps>{
- private _active: boolean;
- private _isCurrentPointControl: string;
- private _currentPointIndex: number;
- private _draggableArea: React.RefObject<SVGSVGElement>;
- private _panStart: Vector2;
- private _panStop: Vector2;
- private _width: number;
- constructor(props: ISvgDraggableAreaProps) {
- super(props);
- this._currentPointIndex = -1;
- this._isCurrentPointControl = "";
- this._draggableArea = React.createRef();
- this._panStart = new Vector2(0, 0);
- this._panStop = new Vector2(0, 0);
- }
- componentDidMount() {
- this._draggableArea.current?.addEventListener("keydown", this.keyDown.bind(this));
- this._draggableArea.current?.addEventListener("keyup", this.keyUp.bind(this));
- setTimeout(() => {
- this._width = this._draggableArea.current?.clientWidth !== undefined ? this._draggableArea.current?.clientWidth : 0;
- console.log(this._width);
- }, 500);
- }
- dragStart(e: React.TouchEvent<SVGSVGElement>): void;
- dragStart(e: React.MouseEvent<SVGSVGElement, MouseEvent>): void;
- dragStart(e: any): void {
- e.preventDefault();
- if (e.target.classList.contains("draggable")) {
- this._active = true;
- this._currentPointIndex = parseInt(e.target.getAttribute('data-id'));
- if (e.target.classList.contains("control-point")) {
- this._isCurrentPointControl = e.target.getAttribute("type");
- }
- }
- if (e.target.classList.contains("pannable")) {
- if (e.buttons === 1 && e.ctrlKey) {
- this._panStart.set(e.clientX, e.clientY);
- }
- }
- }
- drag(e: React.TouchEvent<SVGSVGElement>): void;
- drag(e: React.MouseEvent<SVGSVGElement, MouseEvent>): void;
- drag(e: any): void {
- if (this._active) {
- e.preventDefault();
- var coord = this.getMousePosition(e);
- if (coord !== undefined) {
- var newPoints = [...this.props.keyframeSvgPoints];
- // Check for NaN values here.
- if (this._isCurrentPointControl === "left") {
- newPoints[this._currentPointIndex].leftControlPoint = coord;
- } else if (this._isCurrentPointControl === "right") {
- newPoints[this._currentPointIndex].rightControlPoint = coord;
- } else {
- newPoints[this._currentPointIndex].keyframePoint = coord;
- }
- this.props.updatePosition(newPoints[this._currentPointIndex], this._currentPointIndex);
- }
- }
- }
- dragEnd(e: React.TouchEvent<SVGSVGElement>): void;
- dragEnd(e: React.MouseEvent<SVGSVGElement, MouseEvent>): void;
- dragEnd(e: any): void {
- e.preventDefault();
- this._active = false;
- this._currentPointIndex = -1;
- this._isCurrentPointControl = "";
- if (e.target.classList.contains("pannable")) {
- if (this._panStart.x !== 0 && this._panStart.y !== 0) {
- this._panStop.set(e.clientX, e.clientY);
- this.panDirection();
- }
- }
- }
- getMousePosition(e: React.TouchEvent<SVGSVGElement>): Vector2 | undefined;
- getMousePosition(e: React.MouseEvent<SVGSVGElement, MouseEvent>): Vector2 | undefined;
- getMousePosition(e: any): Vector2 | undefined {
- if (e.touches) { e = e.touches[0]; }
- if (this._draggableArea.current) {
- var svg = this._draggableArea.current as SVGSVGElement;
- var CTM = svg.getScreenCTM();
- if (CTM) {
- return new Vector2((e.clientX - CTM.e) / CTM.a, (e.clientY - CTM.f) / CTM.d);
- } else {
- return undefined;
- }
- } else {
- return undefined;
- }
- }
- panDirection() {
- // Movement Right to Left
- if (this._panStart.x > this._panStop.x) {
- console.log("right to left");
- this.panTo("right", Math.abs(this._panStart.x - this._panStop.x));
- }
- // Movement Right to Left
- if (this._panStart.x < this._panStop.x) {
- this.panTo("left", Math.abs(this._panStart.x - this._panStop.x));
- console.log("left to right");
- }
- // Movement Bottom to Up
- if (this._panStart.y > this._panStop.y) {
- console.log("down up");
- }
- // Movement Up to Bottom
- if (this._panStart.y < this._panStop.y) {
- console.log("up down");
- }
- this._panStart.set(0, 0);
- this._panStop.set(0, 0);
- }
- panTo(direction: string, value: number) {
- switch (direction) {
- case "left":
- (this._draggableArea.current?.parentElement as HTMLDivElement).scrollLeft -= (value * 1);
- break;
- case "right":
- (this._draggableArea.current?.parentElement as HTMLDivElement).scrollLeft += (value * 1);
- break;
- case "top":
- break;
- case "down":
- break;
- }
- }
- keyDown(e: KeyboardEvent) {
- e.preventDefault();
- if (e.keyCode === 17) {
- this._draggableArea.current?.style.setProperty("cursor", "grab");
- }
- }
- keyUp(e: KeyboardEvent) {
- e.preventDefault();
- if (e.keyCode === 17) {
- this._draggableArea.current?.style.setProperty("cursor", "initial");
- }
- }
- focus(e: React.MouseEvent<SVGSVGElement>) {
- e.preventDefault();
- this._draggableArea.current?.focus();
- }
- render() {
- return (
- <>
- <svg className="linear pannable" ref={this._draggableArea} tabIndex={0}
- onMouseMove={(e) => this.drag(e)}
- onTouchMove={(e) => this.drag(e)}
- onTouchStart={(e) => this.dragStart(e)}
- onTouchEnd={(e) => this.dragEnd(e)}
- onMouseDown={(e) => this.dragStart(e)}
- onMouseUp={(e) => this.dragEnd(e)}
- onMouseLeave={(e) => this.dragEnd(e)}
- // Add way to add new keyframe
- onClick={(e) => this.focus(e)}
- viewBox={`0 0 ${Math.round(this.props.scale * 200)} ${Math.round(this.props.scale * 100)}`}>
- {this.props.children}
- {this.props.keyframeSvgPoints.map((keyframe, i) =>
- <KeyframeSvgPoint
- key={i}
- id={i.toString()}
- keyframePoint={keyframe.keyframePoint}
- leftControlPoint={keyframe.leftControlPoint}
- rightControlPoint={keyframe.rightControlPoint}
- isLeftActive={keyframe.isLeftActive}
- isRightActive={keyframe.isRightActive}
- selected={keyframe.selected}
- selectedControlPoint={(type: string, id: string) => this.props.selectedControlPoint(type, id)}
- selectKeyframe={(id: string) => this.props.selectKeyframe(id)} />
- )}
- </svg>
- </>)
- }
- }
|