Skip to content

Commit

Permalink
fix(highlight): 修复固定定位和弹窗场景下鼠标高亮偏移的问题
Browse files Browse the repository at this point in the history
  • Loading branch information
parisma authored and jia000 committed Apr 28, 2022
1 parent a1ae3dd commit 15b202a
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 4 deletions.
3 changes: 2 additions & 1 deletion packages/stage/src/StageDragResize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,11 @@ export default class StageDragResize extends EventEmitter {
public horizontalGuidelines: number[] = [];
public verticalGuidelines: number[] = [];
public elementGuidelines: HTMLElement[] = [];
public mode: Mode = Mode.ABSOLUTE;

private moveableOptions: MoveableOptions = {};
private dragStatus: ActionStatus = ActionStatus.END;
private ghostEl: HTMLElement | undefined;
private mode: Mode = Mode.ABSOLUTE;
private moveableHelper?: MoveableHelper;

constructor(config: StageDragResizeConfig) {
Expand Down Expand Up @@ -354,6 +354,7 @@ export default class StageDragResize extends EventEmitter {
top: ${offset.top}px;
width: ${width}px;
height: ${height}px;
z-index: 9;
`;

this.dragEl.id = `${DRAG_EL_ID_PREFIX}${el.id}`;
Expand Down
15 changes: 13 additions & 2 deletions packages/stage/src/StageHighlight.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,27 @@ import { EventEmitter } from 'events';

import Moveable from 'moveable';

import { HIGHLIGHT_EL_ID_PREFIX } from './const';
import StageCore from './StageCore';
import TargetCalibrate from './TargetCalibrate';
import type { StageHighlightConfig } from './types';
export default class StageHighlight extends EventEmitter {
public core: StageCore;
public container: HTMLElement;
public target?: HTMLElement;
public moveable?: Moveable;
public calibrationTarget: TargetCalibrate;

constructor(config: StageHighlightConfig) {
super();

this.core = config.core;
this.container = config.container;
this.calibrationTarget = new TargetCalibrate({
parent: this.core.mask.content,
mask: this.core.mask,
dr: this.core.dr,
});
}

/**
Expand All @@ -44,10 +52,12 @@ export default class StageHighlight extends EventEmitter {
if (!el || el === this.target) return;
this.target = el;
this.moveable?.destroy();

this.moveable = new Moveable(this.container, {
target: this.target,
scrollable: true,
target: this.calibrationTarget.update(el, HIGHLIGHT_EL_ID_PREFIX),
origin: false,
rootContainer: this.core.container,
zoom: 1,
});
}

Expand All @@ -66,5 +76,6 @@ export default class StageHighlight extends EventEmitter {
*/
public destroy(): void {
this.moveable?.destroy();
this.calibrationTarget.destroy();
}
}
147 changes: 147 additions & 0 deletions packages/stage/src/TargetCalibrate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
/*
* Tencent is pleased to support the open source community by making TMagicEditor available.
*
* Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* eslint-disable no-param-reassign */
import { EventEmitter } from 'events';

import { Mode } from './const';
import StageDragResize from './StageDragResize';
import StageMask from './StageMask';
import type { Offset, Rect, TargetCalibrateConfig } from './types';
import { getMode } from './util';

/**
* 将选中的节点修正定位后,添加一个操作节点到蒙层上
*/
export default class TargetCalibrate extends EventEmitter {
public parent: HTMLElement;
public mask: StageMask;
public dr: StageDragResize;
public operationEl: HTMLElement;

constructor(config: TargetCalibrateConfig) {
super();

this.parent = config.parent;
this.mask = config.mask;
this.dr = config.dr;

this.operationEl = globalThis.document.createElement('div');
this.parent.append(this.operationEl);
}

public update(el: HTMLElement, prefix: String): HTMLElement {
const { width, height } = el.getBoundingClientRect();
const { left, top } = this.getOffset(el);
this.operationEl.style.cssText = `
position: absolute;
left: ${left}px;
top: ${top}px;
width: ${width}px;
height: ${height}px;
`;

this.operationEl.id = `${prefix}${el.id}`;
return this.operationEl;
}

/**
* 设置样式属性
* @param rect 样式属性
*/
public resetRect(rect: Rect): void {
this.operationEl.style.width = `${rect.width}px`;
this.operationEl.style.height = `${rect.height}px`;
Object.keys(rect).forEach((key: string) => {
this.operationEl.style[key] = `${rect[key]}px`;
});
}

public destroy(): void {
this.operationEl?.remove();
}

private getOffset(el: HTMLElement): Offset {
const { transform } = getComputedStyle(el);
const { offsetParent } = el;

let left = el.offsetLeft;
let top = el.offsetTop;

if (transform.indexOf('matrix') > -1) {
let a = 1;
let b = 1;
let c = 1;
let d = 1;
let e = 0;
let f = 0;
transform.replace(
/matrix\((.+), (.+), (.+), (.+), (.+), (.+)\)/,
($0: string, $1: string, $2: string, $3: string, $4: string, $5: string, $6: string): string => {
a = +$1;
b = +$2;
c = +$3;
d = +$4;
e = +$5;
f = +$6;
return transform;
},
);

left = a * left + c * top + e;
top = b * left + d * top + f;
}

if (offsetParent) {
const parentOffset = this.getOffset(offsetParent as HTMLElement);
return {
left: left + parentOffset.left,
top: top + parentOffset.top,
};
}

// 选中固定定位元素后editor-mask高度被置为视窗大小
if (this.dr.mode === Mode.FIXED) {
// 弹窗的情况
if (getMode(el) === Mode.FIXED) {
return {
left,
top,
};
}

return {
left: left - this.mask.scrollLeft,
top: top - this.mask.scrollTop,
};
}

// 无父元素的固定定位需按滚动值计算
if (getMode(el) === Mode.FIXED) {
return {
left: left + this.mask.scrollLeft,
top: top + this.mask.scrollTop,
};
}

return {
left,
top,
};
}
}
2 changes: 2 additions & 0 deletions packages/stage/src/const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ export const GHOST_EL_ID_PREFIX = 'ghost_el_';

export const DRAG_EL_ID_PREFIX = 'drag_el_';

export const HIGHLIGHT_EL_ID_PREFIX = 'highlight_el_';

// 默认放到缩小倍数
export const DEFAULT_ZOOM = 1;

Expand Down
9 changes: 8 additions & 1 deletion packages/stage/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import { Id, MApp, MNode } from '@tmagic/schema';

import { GuidesType } from './const';
import StageCore from './StageCore';
import StageDragResize from './StageDragResize';
import StageMask from './StageMask';

export type CanSelect = (el: HTMLElement, event: MouseEvent, stop: () => boolean) => boolean | Promise<boolean>;

Expand Down Expand Up @@ -54,7 +56,6 @@ export type Rect = {
width: number;
height: number;
} & Offset;

export interface Offset {
left: number;
top: number;
Expand Down Expand Up @@ -119,3 +120,9 @@ export interface StageHighlightConfig {
core: StageCore;
container: HTMLElement;
}

export interface TargetCalibrateConfig {
parent: HTMLElement;
mask: StageMask;
dr: StageDragResize;
}

0 comments on commit 15b202a

Please sign in to comment.