Browse Source

Add fitViewport

canvas-spot
Artur Arseniev 3 years ago
parent
commit
cb44c208ee
  1. 19
      src/canvas/index.ts
  2. 25
      src/canvas/model/Frame.ts
  3. 76
      src/canvas/view/CanvasView.ts
  4. 12
      src/common/index.ts
  5. 6
      src/editor/model/Editor.ts

19
src/canvas/index.ts

@ -54,7 +54,7 @@ import { getElement, getViewEl } from '../utils/mixins';
import defaults, { CanvasConfig } from './config/config';
import Canvas from './model/Canvas';
import Frame from './model/Frame';
import CanvasView from './view/CanvasView';
import CanvasView, { FitViewportOptions } from './view/CanvasView';
import FrameView from './view/FrameView';
export type CanvasEvent = 'canvas:dragenter' | 'canvas:dragover' | 'canvas:drop' | 'canvas:dragend' | 'canvas:dragdata';
@ -606,8 +606,17 @@ export default class CanvasModule extends Module<CanvasConfig> {
* @example
* canvas.setCoords(100, 100);
*/
setCoords(x: string, y: string) {
this.canvas.set({ x: parseFloat(x), y: parseFloat(y) });
setCoords(x?: string | number, y?: string | number) {
const coords = {
x: this.canvas.get('x'),
y: this.canvas.get('y'),
};
if (x || x === 0) coords.x = parseFloat(`${x}`);
if (y || y === 0) coords.y = parseFloat(`${y}`);
this.canvas.set(coords);
return this;
}
@ -633,6 +642,10 @@ export default class CanvasModule extends Module<CanvasConfig> {
return zoom ? 1 / zoom : 1;
}
fitViewport(opts?: FitViewportOptions) {
this.canvasView?.fitViewport(opts);
}
toggleFramesEvents(on: boolean) {
const { style } = this.getFramesEl();
style.pointerEvents = on ? '' : 'none';

25
src/canvas/model/Frame.ts

@ -1,4 +1,4 @@
import { result, forEach, isEmpty, isString } from 'underscore';
import { result, forEach, isEmpty, isString, isNumber } from 'underscore';
import { ModuleModel } from '../../abstract';
import CanvasModule from '..';
import ComponentWrapper from '../../dom_components/model/ComponentWrapper';
@ -10,6 +10,21 @@ import Page from '../../pages/model/Page';
const keyAutoW = '__aw';
const keyAutoH = '__ah';
const getDimension = (frame: Frame, type: 'width' | 'height') => {
const dim = frame.get(type);
const viewDim = frame.view?.el['width' ? 'offsetWidth' : 'offsetHeight'];
if (isNumber(dim)) {
return dim;
} else if (isString(dim) && dim.endsWith('px')) {
return parseFloat(dim);
} else if (viewDim) {
return viewDim;
} else {
return 0;
}
};
/**
* @property {Object|String} component Wrapper component definition. You can also pass an HTML string as components of the default wrapper component.
* @property {String} [width=''] Width of the frame. By default, the canvas width will be taken.
@ -87,6 +102,14 @@ export default class Frame extends ModuleModel<CanvasModule> {
!attr.height && this.set(keyAutoH, 1);
}
get width() {
return getDimension(this, 'width');
}
get height() {
return getDimension(this, 'height');
}
get head(): { tag: string; attributes: any }[] {
return this.get('head');
}

76
src/canvas/view/CanvasView.ts

@ -1,13 +1,14 @@
import { bindAll } from 'underscore';
import { bindAll, isNumber } from 'underscore';
import { ModuleView } from '../../abstract';
import { on, off, getElement, getKeyChar, isTextNode, getElRect, getUiClass } from '../../utils/mixins';
import { BoxRect, ElementRect } from '../../common';
import Component from '../../dom_components/model/Component';
import ComponentView from '../../dom_components/view/ComponentView';
import { createEl, getDocumentScroll } from '../../utils/dom';
import FramesView from './FramesView';
import { getElRect, getElement, getKeyChar, getUiClass, isTextNode, off, on } from '../../utils/mixins';
import Canvas from '../model/Canvas';
import Frame from '../model/Frame';
import FrameView from './FrameView';
import ComponentView from '../../dom_components/view/ComponentView';
import Component from '../../dom_components/model/Component';
import { ElementRect } from '../../common';
import FramesView from './FramesView';
export interface MarginPaddingOffsets {
marginTop?: number;
@ -25,6 +26,13 @@ export type ElementPosOpts = {
avoidFrameZoom?: boolean;
noScroll?: boolean;
};
export interface FitViewportOptions {
frame?: Frame;
gap?: number | { x: number; y: number };
ignoreHeight?: boolean;
}
export default class CanvasView extends ModuleView<Canvas> {
events() {
return {
@ -173,17 +181,65 @@ export default class CanvasView extends ModuleView<Canvas> {
}
updateFramesArea() {
const { framesArea, model } = this;
const { framesArea, model, module } = this;
if (framesArea) {
const zoom = this.getZoom();
const { x, y } = model.attributes;
const mpl = zoom ? 1 / zoom : 1;
const zoomDc = module.getZoomDecimal();
const mpl = module.getZoomMultiplier();
framesArea.style.transform = `scale(${zoom}) translate(${x * mpl}px, ${y * mpl}px)`;
framesArea.style.transform = `scale(${zoomDc}) translate(${x * mpl}px, ${y * mpl}px)`;
}
}
fitViewport(opts: FitViewportOptions = {}) {
const { em, module } = this;
const canvasRect = this.getCanvasOffset();
const frame = opts.frame || em.getCurrentFrameModel() || this.model.frames.at(0);
const { x, y } = frame.attributes;
const boxRect: BoxRect = {
x: x ?? 0,
y: y ?? 0,
width: frame.width,
height: frame.height,
};
const noHeight = opts.ignoreHeight;
const gap = opts.gap ?? 0;
const gapIsNum = isNumber(gap);
const gapX = gapIsNum ? gap : gap.x;
const gapY = gapIsNum ? gap : gap.y;
const boxWidth = boxRect.width + gapX * 2;
const boxHeight = boxRect.height + gapY * 2;
const canvasWidth = canvasRect.width;
const canvasHeight = canvasRect.height;
const widthRatio = canvasWidth / boxWidth;
const heightRatio = canvasHeight / boxHeight;
const zoomRatio = noHeight ? widthRatio : Math.min(widthRatio, heightRatio);
const zoom = zoomRatio * 100;
module.setZoom(zoom);
// check for the boxWidth is necessary as we're centering the frame via CSS
const coordX = boxRect.x + (boxWidth > canvasWidth ? canvasWidth / 2 - boxWidth / 2 : -gapX);
const coordY = boxRect.y + canvasHeight / 2 - boxHeight / 2;
const coords = {
x: (coordX + gapX) * zoomRatio,
y: (coordY + gapY) * zoomRatio,
};
if (noHeight) {
const zoomMltp = module.getZoomMultiplier();
const canvasWorldHeight = canvasHeight * zoomMltp;
const canvasHeightDiff = canvasWorldHeight - canvasHeight;
const yDelta = canvasHeightDiff / 2;
coords.y = (boxRect.y + gapY) * zoomRatio - yDelta / zoomMltp;
}
module.setCoords(coords.x, coords.y);
}
getZoom() {
return this.em.getZoomDecimal();
}

12
src/common/index.ts

@ -27,6 +27,18 @@ export type Position = {
y: number;
};
export interface Coordinates {
x: number;
y: number;
}
export interface Dimensions {
height: number;
width: number;
}
export interface BoxRect extends Coordinates, Dimensions {}
export type ElementRect = {
top: number;
left: number;

6
src/editor/model/Editor.ts

@ -904,12 +904,12 @@ export default class EditorModel extends Model {
return this.set('currentFrame', frameView);
}
getCurrentFrame(): FrameView {
getCurrentFrame(): FrameView | undefined {
return this.get('currentFrame');
}
getCurrentFrameModel(): Frame {
return (this.getCurrentFrame() || {}).model;
getCurrentFrameModel() {
return (this.getCurrentFrame() || {})?.model;
}
getIcon(icon: string) {

Loading…
Cancel
Save