diff --git a/packages/board/examples/test/wheel.html b/packages/board/examples/test/wheel.html index 2b179ab..d096bf8 100644 --- a/packages/board/examples/test/wheel.html +++ b/packages/board/examples/test/wheel.html @@ -30,6 +30,7 @@ contextWidth: 1000, contextHeight: 900, devicePixelRatio: 4, + canScroll: true, } const board = new Board(mount, opts); board.on('wheelX', (deltaX) => { @@ -73,7 +74,7 @@ // board.scrollY(-600); // board.scale(1); - const result = board.scale(0.5); + const result = board.scale(1); console.log('result =', result); board.draw(); diff --git a/packages/board/src/index.ts b/packages/board/src/index.ts index f0d2764..961a6fc 100644 --- a/packages/board/src/index.ts +++ b/packages/board/src/index.ts @@ -3,6 +3,7 @@ import { Watcher } from './util/watcher'; import { setStyle } from './util/style'; import Context from './util/context'; import { TypeBoardEventArgMap } from './util/event'; +import { Scroller } from './util/scroller'; const _canvas = Symbol('_canvas'); @@ -17,7 +18,7 @@ const _watcher = Symbol('_watcher'); const _render = Symbol('_render'); const _calcScreen = Symbol('_calcScreen'); const _parsePrivateOptions = Symbol('_parsePrivateOptions'); - +const _scroller = Symbol('_scroller'); type Options = { width: number; @@ -25,6 +26,7 @@ type Options = { contextWidth: number; contextHeight: number; devicePixelRatio?: number; + canScroll?: boolean; } type PrivateOptions = Options & { @@ -41,6 +43,7 @@ class Board { private [_displayCtx]: CanvasRenderingContext2D; private [_originCtx]: CanvasRenderingContext2D; private [_watcher]: Watcher; + private [_scroller]: Scroller; constructor(mount: HTMLDivElement, opts: Options) { this[_mount] = mount; @@ -52,6 +55,12 @@ class Board { this[_displayCtx] = this[_displayCanvas].getContext('2d') as CanvasRenderingContext2D; this[_ctx] = new Context(this[_originCtx], this[_opts]); this[_watcher] = new Watcher(this[_displayCanvas]); + this[_scroller] = new Scroller( + this[_displayCtx], { + width: opts.width, + height: opts.height, + devicePixelRatio: opts.devicePixelRatio || 1, + }) this[_render](); } @@ -116,7 +125,10 @@ class Board { this[_displayCtx].drawImage( this[_canvas], deviceSize.x, deviceSize.y, deviceSize.w, deviceSize.h ); - return { position, size}; + if (this[_opts].canScroll === true) { + this[_scroller].draw(position); + } + return { position, size }; } clear() { diff --git a/packages/board/src/util/scroller.ts b/packages/board/src/util/scroller.ts new file mode 100644 index 0000000..c086e8c --- /dev/null +++ b/packages/board/src/util/scroller.ts @@ -0,0 +1,143 @@ +import { + TypeScreenPosition +} from '@idraw/types'; + +type TypeOptions = { + width: number, + height: number, + devicePixelRatio: number +}; + + +export class Scroller { + + private _displayCtx: CanvasRenderingContext2D; + private _opts: TypeOptions; + + constructor( + ctx: CanvasRenderingContext2D, + opts: TypeOptions + ) { + this._displayCtx = ctx; + this._opts = opts; + } + + draw(position: TypeScreenPosition) { + const { width, height } = this._opts; + const wrapper = this._calc(position); + // TODO + if (this._displayCtx) { + console.log(wrapper); + } + + const ctx = this._displayCtx; + ctx.globalAlpha = 0.4; + ctx.fillStyle = wrapper.color; + if (wrapper.xSize > 0) { + // x-line + ctx.fillRect(0, this._doSize(height - wrapper.lineSize), this._doSize(width), this._doSize(wrapper.lineSize)); + + // x-slider + drawBox(ctx, { + x: this._doSize(wrapper.translateX), + y: this._doSize(height - wrapper.lineSize), + w: this._doSize(wrapper.xSize), + h: this._doSize(wrapper.lineSize), + r: this._doSize(wrapper.lineSize / 2), + color: wrapper.color, + }); + } + + if (wrapper.ySize > 0) { + // y-line + ctx.fillRect(this._doSize(width - wrapper.lineSize), 0, this._doSize(wrapper.lineSize), this._doSize(height)); + ctx.globalAlpha = 1; + + // y-slider + drawBox(ctx, { + x: this._doSize(width - wrapper.lineSize), + y: this._doSize(wrapper.translateY), + w: this._doSize(wrapper.lineSize), + h: this._doSize(wrapper.ySize), + r: this._doSize(wrapper.lineSize / 2), + color: wrapper.color, + }); + } + + + ctx.globalAlpha = 1; + + } + + private _calc(position: TypeScreenPosition) { + const { width, height } = this._opts; + const sliderMinSize = 50; + const lineSize = 16; + let xSize = 0; + let ySize = 0; + if (position.left <= 0 || position.right <= 0) { + xSize = Math.max( + sliderMinSize, width - ( + Math.abs(position.left < 0 ? position.left : 0) + Math.abs(position.right < 0 ? position.right : 0) + ) + ); + if (xSize >= width) xSize = 0; + } + if (position.top <= 0 || position.bottom <= 0) { + ySize = Math.max( + sliderMinSize, height - ( + Math.abs(position.top < 0 ? position.top : 0) + Math.abs(position.bottom < 0 ? position.bottom : 0) + ) + ); + if (ySize >= height) ySize = 0; + } + + let translateX = 0; + if (xSize > 0) { + translateX = width * Math.abs(position.left) / (Math.abs(position.left) + Math.abs(position.right)); + translateX = Math.min(Math.max(0, translateX - xSize / 2), width - xSize); + } + + let translateY = 0; + if (ySize > 0) { + translateY = height * Math.abs(position.top) / (Math.abs(position.top) + Math.abs(position.bottom)); + translateY = Math.min(Math.max(0, translateY - ySize / 2), height - ySize); + } + const scrollWrapper = { + lineSize, + xSize, + ySize, + translateY, + translateX, + color: '#e0e0e0' + }; + return scrollWrapper; + } + + private _doSize(num: number) { + return num * this._opts.devicePixelRatio; + } +} + + +function drawBox( + ctx: CanvasRenderingContext2D, + opts: { x: number, y: number, w: number, h: number, r: number, color: string } +): void { + + const { x, y, w, h, color } = opts; + let r = opts.r; + r = Math.min(r, w / 2, h / 2); + if (w < r * 2 || h < r * 2) { + r = 0; + }; + ctx.beginPath(); + ctx.moveTo(x + r, y); + ctx.arcTo(x + w, y, x + w, y + h, r); + ctx.arcTo(x + w, y + h, x, y + h, r); + ctx.arcTo(x, y + h, x, y, r); + ctx.arcTo(x, y, x + w, y, r); + ctx.closePath(); + ctx.fillStyle = color; + ctx.fill(); +} \ No newline at end of file diff --git a/packages/core/src/lib/draw/index.ts b/packages/core/src/lib/draw/index.ts index 1f25075..3e7415c 100644 --- a/packages/core/src/lib/draw/index.ts +++ b/packages/core/src/lib/draw/index.ts @@ -14,7 +14,7 @@ import { drawSVG } from './svg'; import { drawText } from './text'; import { drawElementWrapper, - drawDisplayContextScrollWrapper, + // drawDisplayContextScrollWrapper, } from './wrapper'; const { isColorStr } = util.color; @@ -58,6 +58,6 @@ export function drawContext( } } drawElementWrapper(ctx, helperConfig); - drawDisplayContextScrollWrapper(ctx, helperConfig) + // drawDisplayContextScrollWrapper(ctx, helperConfig) } diff --git a/packages/core/src/lib/draw/wrapper.ts b/packages/core/src/lib/draw/wrapper.ts index 02dfed2..dadd5d5 100644 --- a/packages/core/src/lib/draw/wrapper.ts +++ b/packages/core/src/lib/draw/wrapper.ts @@ -57,9 +57,14 @@ export function drawElementWrapper(ctx: TypeContext, config: TypeHelperConfig) { } -export function drawDisplayContextScrollWrapper(ctx: TypeContext, config: TypeHelperConfig) { - console.log('config?.displayContextScrollWrapper = ', config?.displayContextScrollWrapper); - if (!config?.displayContextScrollWrapper) { - return; - } -} \ No newline at end of file +// export function drawDisplayContextScrollWrapper(displayCtx: TypeContext, config: TypeHelperConfig) { +// // console.log('config?.displayContextScrollWrapper = ', config?.displayContextScrollWrapper); +// // if (!config?.displayContextScrollWrapper) { +// // return; +// // } + +// // draw scroll x-line + +// // draw scroll y-line + +// } \ No newline at end of file