diff --git a/packages/board/examples/test/wheel.html b/packages/board/examples/test/wheel.html new file mode 100644 index 0000000..fc26fa1 --- /dev/null +++ b/packages/board/examples/test/wheel.html @@ -0,0 +1,85 @@ + + + + + + + + +
+ + + + + + \ No newline at end of file diff --git a/packages/board/src/index.ts b/packages/board/src/index.ts index 837ec20..d6cb6e8 100644 --- a/packages/board/src/index.ts +++ b/packages/board/src/index.ts @@ -4,12 +4,28 @@ import { setStyle } from './util/style'; import Context from './util/context'; import { TypeBoardEventArgMap } from './util/event'; + +const _canvas = Symbol('_canvas'); +const _displayCanvas = Symbol('_displayCanvas'); +const _mount = Symbol('_mount'); +const _opts = Symbol('_opts'); +const _hasRendered = Symbol('_hasRendered'); +const _ctx = Symbol('_ctx'); +const _displayCtx = Symbol('_displayCtx'); +const _originCtx = Symbol('_originCtx'); +const _watcher = Symbol('_watcher'); +const _render = Symbol('_render'); +const _calcScreen = Symbol('_calcScreen'); +const _parsePrivateOptions = Symbol('_parsePrivateOptions'); + + type Options = { width: number; height: number; contextWidth: number; contextHeight: number; devicePixelRatio?: number; + canScroll?: boolean; } type PrivateOptions = Options & { @@ -17,53 +33,50 @@ type PrivateOptions = Options & { } class Board { - private _canvas: HTMLCanvasElement; - private _displayCanvas: HTMLCanvasElement; - private _mount: HTMLDivElement; - private _opts: PrivateOptions; - private _hasRendered = false; - private _ctx: Context; - private _displayCtx: CanvasRenderingContext2D; - private _originCtx: CanvasRenderingContext2D; - // private _scaleRatio = 1; - // private _scrollX = 0; - // private _scrollY = 0; - private _watcher: Watcher; + private [_canvas]: HTMLCanvasElement; + private [_displayCanvas]: HTMLCanvasElement; + private [_mount]: HTMLDivElement; + private [_opts]: PrivateOptions; + private [_hasRendered] = false; + private [_ctx]: Context; + private [_displayCtx]: CanvasRenderingContext2D; + private [_originCtx]: CanvasRenderingContext2D; + private [_watcher]: Watcher; constructor(mount: HTMLDivElement, opts: Options) { - this._mount = mount; - this._canvas = document.createElement('canvas'); - this._displayCanvas = document.createElement('canvas'); - this._mount.appendChild(this._displayCanvas); - this._opts = this._parsePrivateOptions(opts); - this._originCtx = this._canvas.getContext('2d') as CanvasRenderingContext2D; - this._displayCtx = this._displayCanvas.getContext('2d') as CanvasRenderingContext2D; - this._ctx = new Context(this._originCtx, this._opts); - this._watcher = new Watcher(this._displayCanvas); - this._render(); + this[_mount] = mount; + this[_canvas] = document.createElement('canvas'); + this[_displayCanvas] = document.createElement('canvas'); + this[_mount].appendChild(this[_displayCanvas]); + this[_opts] = this[_parsePrivateOptions](opts); + this[_originCtx] = this[_canvas].getContext('2d') as CanvasRenderingContext2D; + this[_displayCtx] = this[_displayCanvas].getContext('2d') as CanvasRenderingContext2D; + this[_ctx] = new Context(this[_originCtx], this[_opts]); + this[_watcher] = new Watcher(this[_displayCanvas]); + this[_render](); } getDisplayContext(): CanvasRenderingContext2D { - return this._displayCtx; + return this[_displayCtx]; } getOriginContext(): CanvasRenderingContext2D { - return this._displayCtx; + return this[_displayCtx]; } getContext(): Context { - return this._ctx; + return this[_ctx]; } createContext(canvas: HTMLCanvasElement) { - const opts = this._opts; + const opts = this[_opts]; canvas.width = opts.contextWidth * opts.devicePixelRatio; canvas.height = opts.contextHeight * opts.devicePixelRatio; - return new Context(canvas.getContext('2d') as CanvasRenderingContext2D, this._opts); + return new Context(canvas.getContext('2d') as CanvasRenderingContext2D, this[_opts]); } createCanvas() { - const opts = this._opts; + const opts = this[_opts]; const canvas = document.createElement('canvas'); canvas.width = opts.contextWidth * opts.devicePixelRatio; canvas.height = opts.contextHeight * opts.devicePixelRatio; @@ -72,75 +85,72 @@ class Board { scale(scaleRatio: number): TypeScreenContext { if (scaleRatio > 0) { - this._ctx.setTransform({ scale: scaleRatio }); + this[_ctx].setTransform({ scale: scaleRatio }); } - const { position, size } = this._calculateScreen(); + const { position, size } = this[_calcScreen](); return { position, size}; } scrollX(x: number) { if (x >= 0 || x < 0) { - this._ctx.setTransform({ scrollX: x }); + this[_ctx].setTransform({ scrollX: x }); } - const { position, size } = this._calculateScreen(); + const { position, size } = this[_calcScreen](); return { position, size}; } scrollY(y: number): TypeScreenContext { if (y >= 0 || y < 0) { - this._ctx.setTransform({ scrollY: y }); + this[_ctx].setTransform({ scrollY: y }); } - const { position, size } = this._calculateScreen(); + const { position, size } = this[_calcScreen](); return { position, size}; } getTransform() { - return this._ctx.getTransform(); + return this[_ctx].getTransform(); } draw(): TypeScreenContext { this.clear(); - const { position, deviceSize, size } = this._calculateScreen(); - this._displayCtx.drawImage( - this._canvas, deviceSize.x, deviceSize.y, deviceSize.w, deviceSize.h + const { position, deviceSize, size } = this[_calcScreen](); + this[_displayCtx].drawImage( + this[_canvas], deviceSize.x, deviceSize.y, deviceSize.w, deviceSize.h ); return { position, size}; } clear() { - this._displayCtx.clearRect(0, 0, this._displayCanvas.width, this._displayCanvas.height); + this[_displayCtx].clearRect(0, 0, this[_displayCanvas].width, this[_displayCanvas].height); } on(name: T, callback: (p: TypeBoardEventArgMap[T]) => void) { - this._watcher.on(name, callback); + this[_watcher].on(name, callback); } off(name: T, callback: (p: TypeBoardEventArgMap[T]) => void) { - this._watcher.off(name, callback); + this[_watcher].off(name, callback); } - private _render() { - if (this._hasRendered === true) { + private [_render]() { + if (this[_hasRendered] === true) { return; } - const { width, height, contextWidth, contextHeight, devicePixelRatio } = this._opts; - this._canvas.width = contextWidth * devicePixelRatio; - this._canvas.height = contextHeight * devicePixelRatio; + const { width, height, contextWidth, contextHeight, devicePixelRatio } = this[_opts]; + this[_canvas].width = contextWidth * devicePixelRatio; + this[_canvas].height = contextHeight * devicePixelRatio; - this._displayCanvas.width = width * devicePixelRatio; - this._displayCanvas.height = height * devicePixelRatio; + this[_displayCanvas].width = width * devicePixelRatio; + this[_displayCanvas].height = height * devicePixelRatio; - setStyle(this._displayCanvas, { + setStyle(this[_displayCanvas], { width: `${width}px`, height: `${height}px`, }); - // this._watcher.onMove(this._onMove.bind(this)); - // this._watcher.onMoveStart(this._onMoveStart.bind(this)); - // this._watcher.onMoveEnd(this._onMoveEnd.bind(this)); - this._hasRendered = true; + this[_hasRendered] = true; } - private _parsePrivateOptions(opts: Options): PrivateOptions { + private [_parsePrivateOptions](opts: Options): PrivateOptions { const defaultOpts = { devicePixelRatio: 1, }; @@ -148,59 +158,59 @@ class Board { } - private _calculateScreen(): { + private [_calcScreen](): { size: TypeScreenSize, position: TypeScreenPosition, deviceSize: TypeScreenSize, } { - const scaleRatio = this._ctx.getTransform().scale; + const scaleRatio = this[_ctx].getTransform().scale; const { width, height, contextWidth, contextHeight, devicePixelRatio: pxRatio, - } = this._opts; + } = this[_opts]; // init scroll if (contextWidth * scaleRatio <= width) { // make context center - this._ctx.setTransform({ + this[_ctx].setTransform({ scrollX: (width - contextWidth * scaleRatio) / 2, }) } if (contextHeight * scaleRatio <= height) { // make context center - this._ctx.setTransform({ + this[_ctx].setTransform({ scrollY: (height - contextHeight * scaleRatio) / 2, }) } - if (contextWidth * scaleRatio >= width && this._ctx.getTransform().scrollX > 0) { - this._ctx.setTransform({ + if (contextWidth * scaleRatio >= width && this[_ctx].getTransform().scrollX > 0) { + this[_ctx].setTransform({ scrollX: 0, }) } - if (contextHeight * scaleRatio >= height && this._ctx.getTransform().scrollY > 0) { - this._ctx.setTransform({ + if (contextHeight * scaleRatio >= height && this[_ctx].getTransform().scrollY > 0) { + this[_ctx].setTransform({ scrollY: 0, }) } - const { scrollX: _scrollX, scrollY: _scrollY } = this._ctx.getTransform(); + const { scrollX: _scrollX, scrollY: _scrollY } = this[_ctx].getTransform(); // reset scroll if (_scrollX < 0 && Math.abs(_scrollX) > Math.abs(contextWidth * scaleRatio - width)) { - this._ctx.setTransform({ + this[_ctx].setTransform({ scrollX: 0 - Math.abs(contextWidth * scaleRatio - width) }) } if (_scrollY < 0 && Math.abs(_scrollY) > Math.abs(contextHeight * scaleRatio - height)) { - this._ctx.setTransform({ + this[_ctx].setTransform({ scrollY: 0 - Math.abs(contextHeight * scaleRatio - height) }) } // result size - const { scrollX, scrollY } = this._ctx.getTransform(); + const { scrollX, scrollY } = this[_ctx].getTransform(); const size = { x: scrollX * scaleRatio, y: scrollY * scaleRatio, @@ -224,7 +234,6 @@ class Board { size, position, deviceSize }; } - } export default Board; diff --git a/packages/board/src/util/event.ts b/packages/board/src/util/event.ts index 22f6543..c17a929 100644 --- a/packages/board/src/util/event.ts +++ b/packages/board/src/util/event.ts @@ -5,9 +5,8 @@ export interface TypeBoardEventArgMap { 'move': TypePoint; 'moveStart': TypePoint; 'moveEnd': TypePoint; - // 'scale': number; - // 'scrollX': number; - // 'scrollY': number; + 'wheelX': number; + 'wheelY': number; } export interface TypeBoardEvent { diff --git a/packages/board/src/util/watcher.ts b/packages/board/src/util/watcher.ts index f2b1a91..41cff3d 100644 --- a/packages/board/src/util/watcher.ts +++ b/packages/board/src/util/watcher.ts @@ -28,13 +28,14 @@ export class Watcher { _initEvent(): void { const canvas = this._canvas; - canvas.addEventListener('mousedown', this._listenMoveStart.bind(this)); - canvas.addEventListener('mousemove', this._listenMove.bind(this)); - canvas.addEventListener('mouseup', this._listenMoveEnd.bind(this)); + canvas.addEventListener('mousedown', this._listenMoveStart.bind(this), true); + canvas.addEventListener('mousemove', this._listenMove.bind(this), true); + canvas.addEventListener('mouseup', this._listenMoveEnd.bind(this), true); + canvas.addEventListener('wheel', this._listenWheel.bind(this), true); - canvas.addEventListener('touchstart', this._listenMoveStart.bind(this)); - canvas.addEventListener('touchmove', this._listenMove.bind(this)); - canvas.addEventListener('touchend', this._listenMoveEnd.bind(this)); + canvas.addEventListener('touchstart', this._listenMoveStart.bind(this), true); + canvas.addEventListener('touchmove', this._listenMove.bind(this), true); + canvas.addEventListener('touchend', this._listenMoveEnd.bind(this), true); // const mouseupEvent = new MouseEvent('mouseup'); // document.querySelector('body')?.addEventListener('mousemove', (e) => { @@ -81,6 +82,16 @@ export class Watcher { this._isMoving = false; } + _listenWheel(e: WheelEvent) { + e.preventDefault(); + if (this._event.has('wheelX') && (e.deltaX > 0 || e.deltaX < 0)) { + this._event.trigger('wheelX', e.deltaX); + } + if (this._event.has('wheelY') && (e.deltaY > 0 || e.deltaY < 0)) { + this._event.trigger('wheelY', e.deltaY); + } + } + _getPosition(e: MouseEvent|TouchEvent): TypePoint { const canvas = this._canvas; let x = 0;