Skip to content

Commit

Permalink
Feat + Fix: translation snapping [activated] (elastic#853)
Browse files Browse the repository at this point in the history
* Feat: translation and resize snapping

* Feat: improvements to snapping

* Chore: post-conflict resolution lint
  • Loading branch information
monfera authored Jul 27, 2018
1 parent f55d85e commit 8d0f7c6
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 25 deletions.
4 changes: 2 additions & 2 deletions public/lib/aeroelastic/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const alignmentGuideName = 'alignmentGuide';
const atopZ = 1000;
const depthSelect = false;
const devColor = 'magenta';
const guideDistance = 2;
const guideDistance = 4;
const hoverAnnotationName = 'hoverAnnotation';
const resizeAnnotationOffset = 0;
const resizeAnnotationOffsetZ = 0.1; // causes resize markers to be slightly above the shape plane
Expand All @@ -20,7 +20,7 @@ const resizeHandleName = 'resizeHandle';
const rotateSnapInPixels = 10;
const shortcuts = false;
const singleSelect = true;
const snapConstraint = false;
const snapConstraint = true;

module.exports = {
alignmentGuideName,
Expand Down
81 changes: 58 additions & 23 deletions public/lib/aeroelastic/layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -524,8 +524,13 @@ const getUpstreams = (shapes, shape) =>

const shapeCascadeTransforms = shapes => shape => {
const upstreams = getUpstreams(shapes, shape);
const upstreamTransforms = upstreams.map(shape => shape.localTransformMatrix);
const upstreamTransforms = upstreams.map(shape => {
return shape.snapDeltaMatrix
? matrix.multiply(shape.localTransformMatrix, shape.snapDeltaMatrix)
: shape.localTransformMatrix;
});
const cascadedTransforms = matrix.reduceTransforms(upstreamTransforms);

return {
...shape,
transformMatrix: cascadedTransforms,
Expand All @@ -552,12 +557,12 @@ const alignmentGuides = (shapes, guidedShapes) => {
for (let i = 0; i < guidedShapes.length; i++) {
const d = guidedShapes[i];
if (d.type === 'annotation') continue;
const dTransformMatrix = d.transformMatrix;
const dTransformMatrix = d.localTransformMatrix;
for (let j = 0; j < shapes.length; j++) {
const s = shapes[j];
if (d.id === s.id) continue;
if (s.type === 'annotation') continue;
const sTransformMatrix = s.transformMatrix;
const sTransformMatrix = s.localTransformMatrix;
for (let k = -1; k < 2; k++) {
for (let l = -1; l < 2; l++) {
if ((k && !l) || (!k && l)) continue; // don't worry about midpoints of the edges, only the center
Expand Down Expand Up @@ -591,7 +596,11 @@ const alignmentGuides = (shapes, guidedShapes) => {
const radius = midPoint - lowPoint;
result[key] = {
id: counter++,
transformMatrix: matrix.translate(dim ? midPoint : ss, dim ? ss : midPoint, 100),
localTransformMatrix: matrix.translate(
dim ? midPoint : ss,
dim ? ss : midPoint,
config.atopZ
),
a: dim ? radius : 0.5,
b: dim ? 0.5 : radius,
lowPoint,
Expand Down Expand Up @@ -631,19 +640,19 @@ const directionalConstraint = (constraints, filterFun) => {
return closest && closest.constraint;
};

const alignmentGuideAnnotations = select((shapes, guidedShapes) => {
const alignmentGuideAnnotations = select((shapes, draggedShape) => {
const guidedShapes = draggedShape ? [shapes.find(s => s.id === draggedShape.id)] : [];
return guidedShapes.length
? alignmentGuides(shapes, guidedShapes).map(shape => ({
...shape,
id: config.alignmentGuideName + '_' + shape.id,
type: 'annotation',
subtype: config.alignmentGuideName,
interactive: false,
localTransformMatrix: shape.transformMatrix,
backgroundColor: 'magenta',
}))
: [];
})(transformedShapes, hoveredShapes);
})(transformedShapes, draggedShape);

const hoverAnnotations = select((hoveredShape, selectedPrimaryShapeIds) => {
return hoveredShape &&
Expand Down Expand Up @@ -709,7 +718,7 @@ const resizePointAnnotations = (parent, a, b) => ([x, y]) => {
const pixelOffset = matrix.translate(
-x * config.resizeAnnotationOffset,
-y * config.resizeAnnotationOffset,
config.atopZ
config.atopZ + 10
);
const transform = matrix.multiply(markerPlace, pixelOffset);
const xName = xNames[x];
Expand All @@ -732,7 +741,7 @@ const resizePointAnnotations = (parent, a, b) => ([x, y]) => {
const resizeEdgeAnnotations = (parent, a, b) => ([[x0, y0], [x1, y1]]) => {
const x = a * mean(x0, x1);
const y = b * mean(y0, y1);
const markerPlace = matrix.translate(x, y, config.atopZ);
const markerPlace = matrix.translate(x, y, config.atopZ - 10);
const transform = markerPlace; // no offset etc. at the moment
const horizontal = y0 === y1;
const length = horizontal ? a * Math.abs(x1 - x0) : b * Math.abs(y1 - y0);
Expand Down Expand Up @@ -826,7 +835,14 @@ const interactedAnnotations = select(
*/

const annotatedShapes = select(
(shapes, alignmentGuideAnnotations, hoverAnnotations, rotationAnnotations, resizeAnnotations) => {
(
shapes,
draggedShape,
alignmentGuideAnnotations,
hoverAnnotations,
rotationAnnotations,
resizeAnnotations
) => {
const annotations = [].concat(
alignmentGuideAnnotations,
hoverAnnotations,
Expand All @@ -841,31 +857,42 @@ const annotatedShapes = select(
const horizontalConstraint = directionalConstraint(constraints, isHorizontal);
const verticalConstraint = directionalConstraint(constraints, isVertical);
const snappedShapes = contentShapes.map(shape => {
const snapOffsetX =
const constrainedShape = draggedShape && shape.id === draggedShape.id;
const constrainedX =
config.snapConstraint &&
horizontalConstraint &&
horizontalConstraint.constrained === shape.id
? -horizontalConstraint.signedDistance
: 0;
const snapOffsetY =
config.snapConstraint && verticalConstraint && verticalConstraint.constrained === shape.id
? -verticalConstraint.signedDistance
: 0;
if (snapOffsetX || snapOffsetY) {
horizontalConstraint.constrained === shape.id;
const constrainedY =
config.snapConstraint && verticalConstraint && verticalConstraint.constrained === shape.id;
const snapOffsetX = constrainedX ? -horizontalConstraint.signedDistance : 0;
const snapOffsetY = constrainedY ? -verticalConstraint.signedDistance : 0;
if (constrainedX || constrainedY) {
const snapOffset = matrix.translate(snapOffsetX, snapOffsetY, 0);
return {
...shape,
constrainedLocalTransformMatrix: matrix.multiply(shape.localTransformMatrix, snapOffset),
snapDeltaMatrix: snapOffset,
};
} else if (constrainedShape) {
return {
...shape,
snapDeltaMatrix: null,
};
} else {
return shape;
return {
...shape,
snapDeltaMatrix: null,
localTransformMatrix: shape.snapDeltaMatrix
? matrix.multiply(shape.localTransformMatrix, shape.snapDeltaMatrix)
: shape.localTransformMatrix,
};
}
});
const result = snappedShapes.concat(annotations); // add current annotations
return result;
}
)(
transformedShapes,
draggedShape,
alignmentGuideAnnotations,
hoverAnnotations,
rotationAnnotations,
Expand All @@ -878,16 +905,24 @@ const globalTransformShapes = select(cascadeTransforms)(annotatedShapes);
// it's _the_ state representation (at a PoC level...) comprising of transient properties eg. draggedShape, and the
// collection of shapes themselves
const nextScene = select(
(hoveredShape, selectedShapes, selectedPrimaryShapes, shapes, gestureEnd) => {
(hoveredShape, selectedShapes, selectedPrimaryShapes, shapes, gestureEnd, draggedShape) => {
return {
hoveredShape,
selectedShapes,
selectedPrimaryShapes,
shapes,
gestureEnd,
draggedShape,
};
}
)(hoveredShape, selectedShapeIds, selectedPrimaryShapeIds, globalTransformShapes, gestureEnd);
)(
hoveredShape,
selectedShapeIds,
selectedPrimaryShapeIds,
globalTransformShapes,
gestureEnd,
draggedShape
);

module.exports = {
cursorPosition,
Expand Down

0 comments on commit 8d0f7c6

Please sign in to comment.