Skip to content

Commit

Permalink
[Canvas] Alignment and distribution (#39132)
Browse files Browse the repository at this point in the history
[Canvas] Alignment and distribution
  • Loading branch information
monfera authored Jun 27, 2019
1 parent c0af1d2 commit 5fb13a8
Show file tree
Hide file tree
Showing 6 changed files with 357 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,16 @@ const handlers = {
createCustomElement: action('createCustomElement'),
groupNodes: action('groupNodes'),
ungroupNodes: action('ungroupNodes'),
alignLeft: action('alignLeft'),
alignMiddle: action('alignMiddle'),
alignRight: action('alignRight'),
alignTop: action('alignTop'),
alignCenter: action('alignCenter'),
alignBottom: action('alignBottom'),
distributeHorizontally: action('distributeHorizontally'),
distributeVertically: action('distributeVertically'),
};

storiesOf('components/Sidebar/SidebarHeader', module)
.addDecorator(story => <div style={{ width: '300px' }}>{story()}</div>)
.add('default', () => <SidebarHeader title="Selected layer" {...handlers} />)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
clipboardHandlerCreators,
basicHandlerCreators,
groupHandlerCreators,
alignmentDistributionHandlerCreators,
} from '../../lib/element_handler_creators';
import { crawlTree } from '../workpad_page/integration_utils';
import { selectToplevelNodes } from './../../state/actions/transient';
Expand Down Expand Up @@ -62,5 +63,6 @@ export const SidebarHeader = compose(
withHandlers(basicHandlerCreators),
withHandlers(clipboardHandlerCreators),
withHandlers(layerHandlerCreators),
withHandlers(groupHandlerCreators)
withHandlers(groupHandlerCreators),
withHandlers(alignmentDistributionHandlerCreators)
)(Component);
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,38 @@ interface Props {
* ungroups selected group
*/
ungroupNodes: () => void;
/**
* left align selected elements
*/
alignLeft: () => void;
/**
* center align selected elements
*/
alignCenter: () => void;
/**
* right align selected elements
*/
alignRight: () => void;
/**
* top align selected elements
*/
alignTop: () => void;
/**
* middle align selected elements
*/
alignMiddle: () => void;
/**
* bottom align selected elements
*/
alignBottom: () => void;
/**
* horizontally distribute selected elements
*/
distributeHorizontally: () => void;
/**
* vertically distribute selected elements
*/
distributeVertically: () => void;
}

interface State {
Expand All @@ -98,6 +130,11 @@ interface State {
isModalVisible: boolean;
}

interface MenuTuple {
menuItem: EuiContextMenuPanelItemDescriptor;
panel: EuiContextMenuPanelDescriptor;
}

const contextMenuButton = (handleClick: (event: MouseEvent) => void) => (
<EuiButtonIcon
color="text"
Expand Down Expand Up @@ -125,6 +162,14 @@ export class SidebarHeader extends Component<Props, State> {
selectedNodes: PropTypes.array,
groupNodes: PropTypes.func.isRequired,
ungroupNodes: PropTypes.func.isRequired,
alignLeft: PropTypes.func.isRequired,
alignCenter: PropTypes.func.isRequired,
alignRight: PropTypes.func.isRequired,
alignTop: PropTypes.func.isRequired,
alignMiddle: PropTypes.func.isRequired,
alignBottom: PropTypes.func.isRequired,
distributeHorizontally: PropTypes.func.isRequired,
distributeVertically: PropTypes.func.isRequired,
};

public static defaultProps = {
Expand Down Expand Up @@ -229,10 +274,7 @@ export class SidebarHeader extends Component<Props, State> {
);
};

private _getLayerMenuItems = (): {
menuItem: EuiContextMenuPanelItemDescriptor;
panel: EuiContextMenuPanelDescriptor;
} => {
private _getLayerMenuItems = (): MenuTuple => {
const { bringToFront, bringForward, sendBackward, sendToBack } = this.props;

return {
Expand Down Expand Up @@ -266,6 +308,74 @@ export class SidebarHeader extends Component<Props, State> {
};
};

private _getAlignmentMenuItems = (close: (fn: () => void) => () => void): MenuTuple => {
const { alignLeft, alignCenter, alignRight, alignTop, alignMiddle, alignBottom } = this.props;

return {
menuItem: { name: 'Align elements', className: 'canvasContextMenu', panel: 2 },
panel: {
id: 2,
title: 'Alignment',
items: [
{
name: 'Left',
icon: 'editorItemAlignLeft',
onClick: close(alignLeft),
},
{
name: 'Center',
icon: 'editorItemAlignCenter',
onClick: close(alignCenter),
},
{
name: 'Right',
icon: 'editorItemAlignRight',
onClick: close(alignRight),
},
{
name: 'Top',
icon: 'editorItemAlignTop',
onClick: close(alignTop),
},
{
name: 'Middle',
icon: 'editorItemAlignMiddle',
onClick: close(alignMiddle),
},
{
name: 'Bottom',
icon: 'editorItemAlignBottom',
onClick: close(alignBottom),
},
],
},
};
};

private _getDistributionMenuItems = (close: (fn: () => void) => () => void): MenuTuple => {
const { distributeHorizontally, distributeVertically } = this.props;

return {
menuItem: { name: 'Distribute elements', className: 'canvasContextMenu', panel: 3 },
panel: {
id: 3,
title: 'Distribution',
items: [
{
name: 'Horizontal',
icon: 'editorDistributeHorizontal',
onClick: close(distributeHorizontally),
},
{
name: 'Vertical',
icon: 'editorDistributeVertical',
onClick: close(distributeVertically),
},
],
},
};
};

private _getGroupMenuItems = (
close: (fn: () => void) => () => void
): EuiContextMenuPanelItemDescriptor[] => {
Expand Down Expand Up @@ -341,12 +451,21 @@ export class SidebarHeader extends Component<Props, State> {
},
];

const fillMenu = ({ menuItem, panel }: MenuTuple) => {
items.push(menuItem); // add Order menu item to first panel
panels.push(panel); // add nested panel for layers controls
};

if (showLayerControls) {
const { menuItem, panel } = this._getLayerMenuItems();
// add Order menu item to first panel
items.push(menuItem);
// add nested panel for layers controls
panels.push(panel);
fillMenu(this._getLayerMenuItems());
}

if (this.props.selectedNodes.length > 1) {
fillMenu(this._getAlignmentMenuItems(close));
}

if (this.props.selectedNodes.length > 2) {
fillMenu(this._getDistributionMenuItems(close));
}

items.push({
Expand Down
27 changes: 22 additions & 5 deletions x-pack/legacy/plugins/canvas/public/lib/aeroelastic/layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,15 @@ import {
cascadeProperties,
draggingShape,
getAdHocChildrenAnnotations,
getAlignAction,
getAlignDistributeTransformIntents,
getAlignmentGuideAnnotations,
getAlterSnapGesture,
getAnnotatedShapes,
getConfiguration,
getConstrainedShapesWithPreexistingAnnotations,
getCursor,
getDistributeAction,
getDraggedPrimaryShape,
getFocusedShape,
getGroupAction,
Expand Down Expand Up @@ -89,9 +92,7 @@ const mouseTransformState = select(getMouseTransformState)(
dragVector
);

const mouseTransformGesture = select(getMouseTransformGesture)(mouseTransformState);

const transformGestures = mouseTransformGesture;
const directManipulationTransformGestures = select(getMouseTransformGesture)(mouseTransformState);

const selectedShapeObjects = select(getSelectedShapeObjects)(scene, shapes);

Expand All @@ -117,16 +118,32 @@ const symmetricManipulation = optionHeld; // as in comparable software applicati

const resizeManipulator = select(getResizeManipulator)(configuration, symmetricManipulation);

const transformIntents = select(getTransformIntents)(
const directManipulationTransformIntents = select(getTransformIntents)(
configuration,
transformGestures,
directManipulationTransformGestures,
selectedShapes,
shapes,
cursorPosition,
alterSnapGesture,
resizeManipulator
);

const alignAction = select(getAlignAction)(actionEvent);
const distributeAction = select(getDistributeAction)(actionEvent);

const alignDistributeTransformIntents = select(getAlignDistributeTransformIntents)(
alignAction,
distributeAction,
shapes,
selectedShapes
);

const commandTransformIntents = alignDistributeTransformIntents; // will expand in the future, eg. nudge

const transformIntents = select((directIntents, commandIntents) =>
directIntents.concat(commandIntents)
)(directManipulationTransformIntents, commandTransformIntents);

const transformedShapes = select(applyLocalTransforms)(shapes, transformIntents);

const draggedPrimaryShape = select(getDraggedPrimaryShape)(shapes, draggedShape);
Expand Down
Loading

0 comments on commit 5fb13a8

Please sign in to comment.