Browse Source

refactor: streamline guide rendering logic and separate matched guides retrieval

carlos/505-improve-grapesjs-absolute-mode
Carlos 11 months ago
parent
commit
f3a06c1581
  1. 204
      packages/core/src/commands/view/ComponentDrag.ts

204
packages/core/src/commands/view/ComponentDrag.ts

@ -385,43 +385,16 @@ export default {
position,
});
}
// TODO: remove this and move to the drag:start event
const originComponent = target;
const originComponentView = getComponentView(originComponent?.getEl());
const originGuides = this.renderGuideInfo(guidesTarget);
const dragStartProps: DragEventProps = {
originComponent,
originComponentView,
originGuides,
};
this.editor!.trigger(`${evName}:drag:start`, dragStartProps);
},
onDrag() {
const { guidesTarget, opts } = this;
let matchedGuides: MatchedGuide[] = [];
const guidesTargetActive = guidesTarget?.filter((item) => item.active) ?? [];
this.updateGuides(guidesTarget);
opts?.debug && guidesTarget?.forEach((item) => this.renderGuide(item));
opts?.guidesInfo && (matchedGuides = this.renderGuideInfo(guidesTargetActive));
opts?.guidesInfo && this.renderGuideInfo(guidesTargetActive);
opts?.onDrag?.(this._getDragData());
const matchedComponentEl = matchedGuides[0]?.matched.origin;
let matchedComponent = getComponentModel(matchedComponentEl);
let matchedComponentView = getComponentView(matchedComponentEl);
const dragMoveProps: DragEventProps = {
matchedComponent,
matchedComponentView,
matchedGuides,
};
// TODO: use the `${evName}:move` event
this.editor!.trigger(`${evName}:drag:move`, dragMoveProps);
},
onEnd(ev, _dragger, opt) {
@ -431,8 +404,6 @@ export default {
this.hideGuidesInfo();
this.em.trigger(`${evName}:end`, this.getEventOpts());
this.em.trigger(`${evName}:drag:end`, undefined);
},
hideGuidesInfo() {
@ -442,94 +413,101 @@ export default {
});
},
/**
* Render guides with spacing information
*/
// TODO: consider splitting this method into getMatchedGuides and renderGuideInfo
renderGuideInfo(guides = []) {
const { guidesStatic } = this;
const matchedGuides = this.getMatchedGuides(guides);
this.hideGuidesInfo();
const guidesData = guides.map((item) => {
const { origin, x } = item;
const rectOrigin = this.getElementPos(origin);
const axis = isUndefined(x) ? 'y' : 'x';
const isY = axis === 'y';
const origEdge1 = rectOrigin[isY ? 'left' : 'top'];
const origEdge1Raw = rectOrigin.rect[isY ? 'left' : 'top'];
const origEdge2 = isY ? origEdge1 + rectOrigin.width : origEdge1 + rectOrigin.height;
const origEdge2Raw = isY ? origEdge1Raw + rectOrigin.rect.width : origEdge1Raw + rectOrigin.rect.height;
const elGuideInfo = this[`elGuideInfo${axis.toUpperCase()}` as ElGuideInfoKey];
const elGuideInfoCnt = this[`elGuideInfoContent${axis.toUpperCase()}` as ElGuideInfoContentKey];
const guideInfoStyle = elGuideInfo?.style;
let guideMatched: MatchedGuide | null = null;
// Find the nearest element
const matched = guidesStatic
?.filter((stat) => stat.type === item.type)
.map((stat) => {
const { left, width, top, height } = stat.originRect;
const statEdge1 = isY ? left : top;
matchedGuides.forEach((matchedGuide) => {
// TODO: improve this
if (!this.opts?.skipGuidesRender) {
this.renderSingleGuideInfo(matchedGuide);
}
this.em.trigger(`${evName}:active`, {
...this.getEventOpts(),
...matchedGuide,
});
});
},
renderSingleGuideInfo(matchedGuide: MatchedGuide) {
const { posFirst, posSecond, size, sizeRaw, guide, elGuideInfo, elGuideInfoCnt } = matchedGuide;
const axis = isUndefined(guide.x) ? 'y' : 'x';
const isY = axis === 'y';
const guideInfoStyle = elGuideInfo?.style;
if (guideInfoStyle) {
guideInfoStyle.display = '';
guideInfoStyle[isY ? 'top' : 'left'] = `${posFirst}px`;
guideInfoStyle[isY ? 'left' : 'top'] = `${posSecond}px`;
guideInfoStyle[isY ? 'width' : 'height'] = `${size}px`;
}
if (elGuideInfoCnt) {
elGuideInfoCnt.innerHTML = `${Math.round(sizeRaw)}px`;
}
},
getMatchedGuides(guides = []): MatchedGuide[] {
const { guidesStatic } = this;
return guides
.map((item) => {
const { origin, x } = item;
const rectOrigin = this.getElementPos(origin);
const axis = isUndefined(x) ? 'y' : 'x';
const isY = axis === 'y';
const origEdge1 = rectOrigin[isY ? 'left' : 'top'];
const origEdge2 = isY ? origEdge1 + rectOrigin.width : origEdge1 + rectOrigin.height;
const elGuideInfo = this[`elGuideInfo${axis.toUpperCase()}` as ElGuideInfoKey];
const elGuideInfoCnt = this[`elGuideInfoContent${axis.toUpperCase()}` as ElGuideInfoContentKey];
// Find the nearest element
const matched = guidesStatic
?.filter((stat) => stat.type === item.type)
.map((stat) => {
const { left, width, top, height } = stat.originRect;
const statEdge1 = isY ? left : top;
const statEdge2 = isY ? left + width : top + height;
return {
gap: statEdge2 < origEdge1 ? origEdge1 - statEdge2 : statEdge1 - origEdge2,
guide: stat,
};
})
.filter((item) => item.gap > 0)
.sort((a, b) => a.gap - b.gap)
.map((item) => item.guide)[0];
if (matched) {
const { left, width, top, height, rect } = matched.originRect;
const isEdge1 = isY ? left < rectOrigin.left : top < rectOrigin.top;
const statEdge2 = isY ? left + width : top + height;
const posFirst = isY ? item.y : item.x;
const posSecond = isEdge1 ? statEdge2 : origEdge2;
const size = isEdge1 ? origEdge1 - statEdge2 : statEdge2 - origEdge2;
const sizeRaw = isEdge1
? rectOrigin.rect[isY ? 'left' : 'top'] - rect[isY ? 'left' : 'top']
: rect[isY ? 'left' : 'top'] - rectOrigin.rect[isY ? 'left' : 'top'];
const sizePercent = (sizeRaw / (isY ? matched.originRect.height : matched.originRect.width)) * 100;
return {
gap: statEdge2 < origEdge1 ? origEdge1 - statEdge2 : statEdge1 - origEdge2,
guide: stat,
guide: item,
guidesStatic,
matched,
posFirst,
posSecond,
size,
sizeRaw,
sizePercent,
elGuideInfo,
elGuideInfoCnt,
};
})
.filter((item) => item.gap > 0)
.sort((a, b) => a.gap - b.gap)
.map((item) => item.guide)[0];
if (matched) {
const { left, width, top, height, rect } = matched.originRect;
const isEdge1 = isY ? left < rectOrigin.left : top < rectOrigin.top;
const statEdge1 = isY ? left : top;
const statEdge1Raw = isY ? rect.left : rect.top;
const statEdge2 = isY ? left + width : top + height;
const statEdge2Raw = isY ? rect.left + rect.width : rect.top + rect.height;
const posFirst = isY ? item.y : item.x;
const posSecond = isEdge1 ? statEdge2 : origEdge2;
const pos2 = `${posFirst}px`;
const size = isEdge1 ? origEdge1 - statEdge2 : statEdge1 - origEdge2;
const sizeRaw = isEdge1 ? origEdge1Raw - statEdge2Raw : statEdge1Raw - origEdge2Raw;
const sizePercent = (sizeRaw / (isY ? matched.originRect.height : matched.originRect.width)) * 100; // TODO: fix calculation
// INFO: skip rendering the guide info if the option is set
if (!this?.opts?.skipGuidesRender) {
if (guideInfoStyle) {
guideInfoStyle.display = '';
guideInfoStyle[isY ? 'top' : 'left'] = pos2;
guideInfoStyle[isY ? 'left' : 'top'] = `${posSecond}px`;
guideInfoStyle[isY ? 'width' : 'height'] = `${size}px`;
}
if (elGuideInfoCnt) {
elGuideInfoCnt.innerHTML = `${Math.round(sizeRaw)}px`;
}
}
guideMatched = {
guide: item,
guidesStatic,
matched,
posFirst,
posSecond,
size,
sizeRaw,
sizePercent,
elGuideInfo,
elGuideInfoCnt,
};
this.em.trigger(`${evName}:active`, {
...this.getEventOpts(),
...guideMatched,
});
}
return guideMatched;
});
return guidesData.filter(Boolean) as MatchedGuide[];
return null;
})
.filter(Boolean) as MatchedGuide[];
},
toggleDrag(enable) {
@ -580,7 +558,9 @@ interface ComponentDragProps {
onDrag: DraggerOptions['onDrag'];
onEnd: DraggerOptions['onEnd'];
hideGuidesInfo: () => void;
renderGuideInfo: (guides?: Guide[]) => MatchedGuide[];
renderGuideInfo: (guides?: Guide[]) => void;
renderSingleGuideInfo: (matchedGuide: MatchedGuide) => void;
getMatchedGuides: (guides?: Guide[]) => MatchedGuide[];
toggleDrag: (enable?: boolean) => void;
}

Loading…
Cancel
Save