Shape Alignment

SpreadJS makes it easy to fine-tune multiple shape's positions using shape alignment options, distribution options or snapping them to other shapes or grids.

Description
app.js
index.html
styles.css
Copy to CodeMine

You can align shapes using the following code:

    var commandManager = spread.commandManager();
    commandManager.execute({
        cmd: 'moveShapesByHAlign',
        sheetName: sheet.name(),
        shapeNames: ['rect1','line1','heart1','group1'],
        alignment: GC.Spread.Sheets.Shapes.HorizontalAlign.left
    });
    commandManager.execute({
        cmd: 'moveShapesByVAlign',
        sheetName: sheet.name(),
        shapeNames: ['rect1','line1','heart1','group1'],
        alignment: GC.Spread.Sheets.Shapes.VerticalAlign.bottom
    });
    commandManager.execute({
            cmd: 'moveShapesByHDistribute',
            sheetName: sheet.name(),
            shapeNames: ['rect1','line1','heart1','group1']
        });
    });
    commandManager.execute({
            cmd: 'moveShapesByVDistribute',
            sheetName: sheet.name(),
            shapeNames: ['rect1','line1','heart1','group1']
        });
    });

You can change snapMode to align shapes easily

    var sheet = spread.getActiveSheet();
    sheet.shapes.snapMode(GC.Spread.Sheets.Shapes.SnapMode.grid);

Now when you drag or resize a shape, the shape will align to grid lines automatically.

You can also align to other shapes:

    var sheet = spread.getActiveSheet();
    sheet.shapes.snapMode(GC.Spread.Sheets.Shapes.SnapMode.grid | GC.Spread.Sheets.Shapes.SnapMode.shape);
You can align shapes using the following code: You can change snapMode to align shapes easily Now when you drag or resize a shape, the shape will align to grid lines automatically. You can also align to other shapes:
window.onload = function () { var spread = new GC.Spread.Sheets.Workbook(document.getElementById("ss"), { sheetCount: 1 }); initSpread(spread); }; function initSpread(spread) { let sheet = spread.getActiveSheet(); var rect1 = sheet.shapes.add('rect1', GC.Spread.Sheets.Shapes.AutoShapeType.rectangle, 100, 50, 230, 100); var rect2 = sheet.shapes.add('rect2', GC.Spread.Sheets.Shapes.AutoShapeType.rectangle, 200, 200, 150, 100); var rect3 = sheet.shapes.add('rect3', GC.Spread.Sheets.Shapes.AutoShapeType.rectangle, 500, 300, 200, 100); spread.bind(GC.Spread.Sheets.Events.ShapeSelectionChanged, function () { shapeSelectionChangedHandler(spread); }); document.querySelectorAll('.align').forEach(function (btn) { btn.addEventListener('click', function (e) { let activeSheet = spread.getActiveSheet(); let activeShapes = activeSheet.shapes.all().filter(function (sp) { return sp.isSelected(); }); let classNames = e.target.className.split(' '); let cmd = classNames[1]; let alignment = classNames[2]; var commandManager = spread.commandManager(); commandManager.execute({ cmd: cmd, sheetName: activeSheet.name(), shapeNames: activeShapes.map(function (s) { return s.name(); }), alignment: getAlignmentEnum(alignment) }); }); }); document.querySelectorAll('.align-dd').forEach(function (dd) { dd.addEventListener('change', function (e) { let activeSheet = spread.getActiveSheet(); let activeShapes = activeSheet.shapes.all().filter(function (sp) { return sp.isSelected(); }); let classNames = e.target.className.split(' '); let cmd = classNames[1]; var commandManager = spread.commandManager(); commandManager.execute({ cmd: cmd, sheetName: activeSheet.name(), shapeNames: activeShapes.map(function (s) { return s.name(); }), alignment: getAlignmentEnum(e.target.value) }); }); }); document.querySelector('#changeSnapMode').addEventListener('change', function (e) { let sheet = spread.getActiveSheet(); switch (e.target.value) { case '0': sheet.shapes.snapMode(GC.Spread.Sheets.Shapes.SnapMode.none); return; case '1': sheet.shapes.snapMode(GC.Spread.Sheets.Shapes.SnapMode.grid); return; case '2': sheet.shapes.snapMode(GC.Spread.Sheets.Shapes.SnapMode.shape); return; case '3': sheet.shapes.snapMode(GC.Spread.Sheets.Shapes.SnapMode.grid | GC.Spread.Sheets.Shapes.SnapMode.shape); return; default: return; } }); shapeSelectionChangedHandler(spread); } function toggleEnable(enable, className) { document.querySelectorAll('.' + className).forEach(function (btn) { if (enable) { btn.removeAttribute('disabled'); } else { btn.setAttribute('disabled', ''); } }) } function getAlignmentEnum(alignment) { switch (alignment) { case 'left': return GC.Spread.Sheets.Shapes.HorizontalAlign.left; case 'center': return GC.Spread.Sheets.Shapes.HorizontalAlign.center; case 'right': return GC.Spread.Sheets.Shapes.HorizontalAlign.right; case 'top': return GC.Spread.Sheets.Shapes.VerticalAlign.top; case 'middle': return GC.Spread.Sheets.Shapes.VerticalAlign.middle; case 'bottom': return GC.Spread.Sheets.Shapes.VerticalAlign.bottom; default: return; } } function _getElementById(id) { return document.getElementById(id); } function shapeSelectionChangedHandler(spread) { let activeSheet = spread.getActiveSheet(); let shapes = activeSheet.shapes.all(), activeShapes = []; for (let i = 0; i < shapes.length; i++) { let shape = shapes[i]; if (shape.isSelected()) { activeShapes.push(shape); } } if (activeShapes.length > 1) { toggleEnable(true, 'justify'); } else { toggleEnable(false, 'justify'); } if (activeShapes.length > 2) { toggleEnable(true, 'distribute'); } else { toggleEnable(false, 'distribute'); } }
<!doctype html> <html style="height:100%;font-size:14px;"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" type="text/css" href="$DEMOROOT$/en/purejs/node_modules/@mescius/spread-sheets/styles/gc.spread.sheets.excel2013white.css"> <script src="$DEMOROOT$/en/purejs/node_modules/@mescius/spread-sheets/dist/gc.spread.sheets.all.min.js" type="text/javascript"></script> <script src="$DEMOROOT$/en/purejs/node_modules/@mescius/spread-sheets-shapes/dist/gc.spread.sheets.shapes.min.js" type="text/javascript"></script> <script src="$DEMOROOT$/spread/source/js/license.js" type="text/javascript"></script> <script src="app.js" type="text/javascript"></script> <link rel="stylesheet" type="text/css" href="styles.css"> </head> <body> <div class="sample-tutorial"> <div id="ss" class="sample-spreadsheets"></div> <div class="options-container"> <div class="option-row"> Select two or more shapes then change the different alignment options below to see the effects. </div> <div class="option-row"> *for the vertical and horizontal distribution, all three shapes must be selected. </div> <div class="option-row"> <label>- Horizontal Alignment</label> <hr> <select id="moveShapesByHAlign" class="align-dd moveShapesByHAlign"> <option value="left" selected>left</option> <option value="center">center</option> <option value="right">right</option> </select> <br /> <br /> <label>Horizontal Distribute Selected Shapes</label> <input type="button" class="align moveShapesByHDistribute distribute" value="Horizontal"> <br /> <label>- Vertical Alignment</label> <hr> <select id="moveShapesByVAlign" class="align-dd moveShapesByVAlign"> <option value="top" selected>top</option> <option value="middle">middle</option> <option value="bottom">bottom</option> </select> <br /> <br /> <label>Vertical Distribute Selected Shapes</label> <input type="button" class="align moveShapesByVDistribute distribute" value="Vertical"> <br /> <label>Change the SnapMode options to align, drag, or resize shapes to the nearest edge based on gridlines or other shapes in the worksheet. </label> <hr> <select id="changeSnapMode"> <option value="0" selected>none</option> <option value="1">grid</option> <option value="2">shape</option> <option value="3">grid and shape</option> </select> <br /> </div> </div> </div> </body> </html>
.sample-tutorial { position: relative; height: 100%; overflow: hidden; } .sample-spreadsheets { width: calc(100% - 350px); height: 100%; overflow: hidden; float: left; } .options-container { float: right; width: 350px; padding: 12px; height: 100%; box-sizing: border-box; background: #fbfbfb; overflow: auto; } .option-row { font-size: 14px; padding: 5px; margin-top: 5px; } .sample-options { z-index: 1000; } label { display: block; margin-bottom: 6px; } p{ padding:2px 10px; background-color:#F4F8EB; } input { padding: 4px 6px; width: 160px; } input[type=button] { margin-top: 6px; display: block; } body { position: absolute; top: 0; bottom: 0; left: 0; right: 0; }