From 0178de4ab9ffd11630b700f9c02468b74beabd14 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 17 Aug 2022 12:31:26 -0400 Subject: fixed dragging docs on web and pdf to work better by temporarily adding transparent docs to the opaque layer so they can get drop events. cleaned eraser and pen interaction code and made erasing strokes work faster and avoid hanging by not intersecting strokes that are already partially deleted. --- .../collectionFreeForm/CollectionFreeFormView.tsx | 140 ++++++--------------- 1 file changed, 36 insertions(+), 104 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index f3074543b..45a5e30ff 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -109,8 +109,6 @@ export class CollectionFreeFormView extends CollectionSubView, props: Opt, property: string) => { let styleProp = this.props.styleProvider?.(doc, props, property); // bcz: check 'props' used to be renderDepth + 1 - if (property !== StyleProp.BackgroundColor) return styleProp; - const cluster = NumCast(doc?.cluster); - if (this.Document._useClusters) { - if (this._clusterSets.length <= cluster) { - setTimeout(() => doc && this.updateCluster(doc)); - } else { - // choose a cluster color from a palette - const colors = ['#da42429e', '#31ea318c', 'rgba(197, 87, 20, 0.55)', '#4a7ae2c4', 'rgba(216, 9, 255, 0.5)', '#ff7601', '#1dffff', 'yellow', 'rgba(27, 130, 49, 0.55)', 'rgba(0, 0, 0, 0.268)']; - styleProp = colors[cluster % colors.length]; - const set = this._clusterSets[cluster]?.filter(s => s.backgroundColor); - // override the cluster color with an explicitly set color on a non-background document. then override that with an explicitly set color on a background document - set?.map(s => (styleProp = StrCast(s.backgroundColor))); - } - } //else if (doc && NumCast(doc.group, -1) !== -1) styleProp = "gray"; + switch (property) { + case StyleProp.BackgroundColor: + const cluster = NumCast(doc?.cluster); + if (this.Document._useClusters) { + if (this._clusterSets.length <= cluster) { + setTimeout(() => doc && this.updateCluster(doc)); + } else { + // choose a cluster color from a palette + const colors = ['#da42429e', '#31ea318c', 'rgba(197, 87, 20, 0.55)', '#4a7ae2c4', 'rgba(216, 9, 255, 0.5)', '#ff7601', '#1dffff', 'yellow', 'rgba(27, 130, 49, 0.55)', 'rgba(0, 0, 0, 0.268)']; + styleProp = colors[cluster % colors.length]; + const set = this._clusterSets[cluster]?.filter(s => s.backgroundColor); + // override the cluster color with an explicitly set color on a non-background document. then override that with an explicitly set color on a background document + set?.map(s => (styleProp = StrCast(s.backgroundColor))); + } + } + break; + } return styleProp; }; @@ -523,17 +524,13 @@ export class CollectionFreeFormView extends CollectionSubView { - if (!InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) { - document.removeEventListener('pointermove', this.onEraserMove); - document.removeEventListener('pointerup', this.onEraserUp); - this._deleteList.forEach(ink => ink.props.removeDocument?.(ink.rootDoc)); - this._deleteList = []; - this._batch?.end(); - } - }; - - @action - onPointerUp = (e: PointerEvent): void => { - if (!InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) { - document.removeEventListener('pointermove', this.onPointerMove); - document.removeEventListener('pointerup', this.onPointerUp); - this.removeMoveListeners(); - this.removeEndListeners(); - } + this._deleteList.forEach(ink => ink.props.removeDocument?.(ink.rootDoc)); + this._deleteList = []; + this._batch?.end(); }; onClick = (e: React.MouseEvent) => { @@ -752,46 +735,42 @@ export class CollectionFreeFormView extends CollectionSubView { + onEraserMove = (e: PointerEvent, down: number[], delta: number[]) => { const currPoint = { X: e.clientX, Y: e.clientY }; - this.getEraserIntersections({ X: this._lastX, Y: this._lastY }, currPoint).forEach(intersect => { + this.getEraserIntersections({ X: currPoint.X - delta[0], Y: currPoint.Y - delta[1] }, currPoint).forEach(intersect => { if (!this._deleteList.includes(intersect.inkView)) { this._deleteList.push(intersect.inkView); SetActiveInkWidth(StrCast(intersect.inkView.rootDoc.strokeWidth?.toString()) || '1'); SetActiveInkColor(StrCast(intersect.inkView.rootDoc.color?.toString()) || 'black'); // create a new curve by appending all curves of the current segment together in order to render a single new stroke. - !e.shiftKey && + if (!e.shiftKey) { this.segmentInkStroke(intersect.inkView, intersect.t).forEach(segment => GestureOverlay.Instance.dispatchGesture( GestureUtils.Gestures.Stroke, segment.reduce((data, curve) => [...data, ...curve.points.map(p => intersect.inkView.ComponentView?.ptToScreen?.({ X: p.x, Y: p.y }) ?? { X: 0, Y: 0 })], [] as PointData[]) ) ); + } // Lower ink opacity to give the user a visual indicator of deletion. intersect.inkView.layoutDoc.opacity = 0.5; + intersect.inkView.layoutDoc.dontIntersect = true; } }); - this._lastX = currPoint.X; - this._lastY = currPoint.Y; - - e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document' however it does mark the event as cancelBubble=true which we test for in the move event handlers - e.preventDefault(); + return false; }; @action - onPointerMove = (e: PointerEvent): void => { - if (InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) return; + onPointerMove = (e: PointerEvent): boolean => { + if (InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) return false; if (InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) { Doc.ActiveTool = InkTool.None; if (this.props.isContentActive(true)) e.stopPropagation(); } else if (!e.cancelBubble) { if (this.tryDragCluster(e, this._hitCluster)) { - document.removeEventListener('pointermove', this.onPointerMove); - document.removeEventListener('pointerup', this.onPointerUp); + return true; } else this.pan(e); - e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document' however it does mark the event as cancelBubble=true which we test for in the move event handlers - e.preventDefault(); } + return false; }; /** @@ -801,6 +780,7 @@ export class CollectionFreeFormView extends CollectionSubView { const eraserMin = { X: Math.min(lastPoint.X, currPoint.X), Y: Math.min(lastPoint.Y, currPoint.Y) }; const eraserMax = { X: Math.max(lastPoint.X, currPoint.X), Y: Math.max(lastPoint.Y, currPoint.Y) }; + return this.childDocs .map(doc => DocumentManager.Instance.getDocumentView(doc, this.props.CollectionView)) .filter(inkView => inkView?.ComponentView instanceof InkingStroke) @@ -888,7 +868,7 @@ export class CollectionFreeFormView extends CollectionSubView doc.type === DocumentType.INK) + .filter(doc => doc.type === DocumentType.INK && !doc.dontIntersect) .forEach(doc => { const otherInk = DocumentManager.Instance.getDocumentView(doc, this.props.CollectionView)?.ComponentView as InkingStroke; const { inkData: otherInkData } = otherInk?.inkScaledData() ?? { inkData: [] }; @@ -919,7 +899,6 @@ export class CollectionFreeFormView extends CollectionSubView only want to do this when collection is selected' @@ -967,13 +946,6 @@ export class CollectionFreeFormView extends CollectionSubView { - switch (this._pullDirection) { - case 'left': - case 'right': - case 'top': - case 'bottom': - CollectionDockingView.AddSplit(Docs.Create.FreeformDocument([], { title: 'New Collection' }), this._pullDirection); - } - - this._pullDirection = ''; - this._pullCoords = [0, 0]; - - document.removeEventListener('pointermove', this.onPointerMove); - document.removeEventListener('pointerup', this.onPointerUp); this.removeMoveListeners(); this.removeEndListeners(); }; @@ -1380,7 +1321,7 @@ export class CollectionFreeFormView extends CollectionSubView -
+
{this.layoutDoc._backgroundGridShow ? (
} -
{ // uncomment to show snap lines
-- cgit v1.2.3-70-g09d2