Search code examples
javascriptmodel-view-controllerfrontendweb-frontend

Is there a way to combine multiple divs into one


I have a dynamic group of n by m divs to form a grid. The items in this grid can be selected. The end result which I am hoping to achieve is to be able to combine and split the selected divs.

I have managed to get the divs to show correctly and select them, storing their id's in a list. Is there a way I could combine the selected divs, keeping the ones around it in their place?

@(Html.Kendo().Window()
.Name("window") //The name of the window is mandatory. It specifies the "id" attribute of the widget.
.Title("Dashboard Setup") //set the title of the window
.Content(@<text>
    <div id="divSetup">
        <div class="dvheader">
            <b>Dashboard Setup</b>
        </div>
        <div>
            <p>Enter the number of columns and rows of dashboard elements. This will create an empty dashboard with a set number of items which can be filled with KPI charts.</p>
            <br />
            <div class="dvform">
                <table>
                    <tr style="margin-bottom: 15px;">
                        <td>
                            @Html.Label("Number of Columns: ")

                        </td>
                        <td>
                            <input type="number" name="NumColumns" id="NoColumns" min="1" max="20" />
                        </td>
                    </tr>
                    <tr style="margin-bottom: 15px;">
                        <td>
                            @Html.Label("Number of Rows: ")

                        </td>
                        <td>
                            <input type="number" name="NumRows" id="NoRows" min="1" max="20" />
                        </td>
                    </tr>
                </table>
            </div>

        </div>
        <div style="float: right">
            <button id="btnSave" class="k-primary">Save</button>
            <button id="btnClose">Close</button>
        </div>
    </div>
    </text>)
    .Draggable() //Enable dragging of the window
    .Resizable() //Enable resizing of the window
    .Width(600) //Set width of the window
    .Modal(true)
    .Visible(false)
)

    <div id="dashboard">
    </div>

    <button id="combine" title="Combine">Combine</button>

 <script>
 $(document).ready(function () {
    debugger;

    $("#window").data("kendoWindow").open();

    $("#btnClose").kendoButton({
        click: close
    });

    $("#btnSave").kendoButton({
        click: Save
    });
    $("#combine").kendoButton();
});

var array = [];
function clicked(e)
{
    debugger;
    var selectedDiv = "";

    var x = document.getElementsByClassName('column')
    for (var i = 0; i < x.length; i++)
    {
        if (x[i].id == e.id)
        {
            x[i].classList.add("selected");
            array.push(x[i]);
        }
    }

    for (var x = 0; x < array.length - 1; x++) {
        array[x].classList.add("selected");
    }

}

function close() {
    $("#window").hide();
}

function Save()
{
    debugger;
    var col = document.getElementById("NoColumns").value;
    var row = document.getElementById("NoRows").value;

    for (var x = 1; x <= row; x++)
    {
        debugger;
        document.getElementById("dashboard").innerHTML += '<div class="row">';
        debugger;
        for (var i = 1; i <= col; i++)
        {
            document.getElementById("dashboard").innerHTML += '<div onclick="clicked(this)" id="Row ' + x + ' Col ' + i + '" class="column">' + i + '</div>';
        }

        document.getElementById("dashboard").innerHTML += '</div>';
    }

}

  <style>

.selected {
    background-color: #226fa3;
    transition: background-color 0.4s ease-in, border-color 0.4s ease-in;
    color: #ffffff;
}

#dashboard {
    width: 80%;
    margin: auto;
    background-color: grey;
    padding: 20px;
}
* {
    box-sizing: border-box;
}

/* Create three equal columns that floats next to each other */
.column {
    float: left;
    padding: 20px;
    border: 1px black solid;

}

/* Clear floats after the columns */
.row:after {
    content: "";
    display: table;
    clear: both;
}

Below is an image of the selected blocks I would like to combine into one, while keeping it's place Selected blocks


Solution

  • If you were using a table it would be much easier, for div's, I can think of a solution if the style position is absolute, maybe it would help you start at least.

    <div id="container"></div>
    <button id="combine" title="Combine" disabled="disabled">Combine</button>
    <div id="output"></div>
    

    the script:

    <script>
    var cc;
        function group() {
    
            var xx = $(".selected").map(function () { return $(this).attr("data-x"); }).get();
            var yy = $(".selected").map(function () { return $(this).attr("data-y"); }).get();
    
            this.minX = Math.min.apply(Math, xx);
            this.minY = Math.min.apply(Math, yy);
            this.maxX = Math.max.apply(Math, xx);
            this.maxY = Math.max.apply(Math, yy);
            this.selectedCount = $(".selected").length;
    
            this.CorrectGroup = function () {
                var s = this.selectedCount;
                return s == this.cellsCount() && s > 1;
            }
    
            this.width = function () {
                return this.maxX - this.minX + 1;
            }
            this.height = function () {
                return this.maxY - this.minY + 1;
            }
            this.cellsCount = function () {
                return this.width() * this.height();
            }
    
        }
        function cell(x, y, g) {
            this.x = x;
            this.y = y;
            this.g = g;
            this.spanX = 1;
            this.spanY = 1;
            this.visible = true;
            var cellWidth = 80;
            var cellHeight = 50;
    
    
            this.div = function () {
                var output = jQuery('<div/>');
                output.attr('id', 'y' + y + 'x' + x);
                output.attr('data-x', x);
                output.attr('data-y', y);
                output.attr('style', this.left() + this.top() + this.width() + this.height());
                output.addClass('clickable');
    
                output.html('(y=' + y + ' x=' + x + ')')
                return output;
            }
            this.left = function () {
                return 'left:' + (x * cellWidth) + 'px;';
            }
            this.top = function () {
               return  'top:' + (100 + y * cellHeight) + 'px;';
            }
            this.width = function () {
                return 'width:' + (this.spanX * cellWidth) + 'px;';
            }
            this.height = function () {
                return 'height:' + (this.spanY * cellHeight) + 'px;';
            }
        }
    
        function cells(xx, yy) {
    
            this.CellWidth = xx;
            this.CellHeight = yy;
            this.CellList = [];
    
            for (var y = 0; y < yy; y++)
                for (var x = 0; x < xx; x++) {
                    this.CellList.push(new cell(x, y, 1));
                }
    
    
            this.findCell = function (xx, yy) {
                return this.CellList.find(function (element) {
                    return (element.x == xx && element.y == yy);
                });
            }
    
            this.displayCells = function (container) {
                container.html('');
                for (var y = 0; y < yy; y++)
                    for (var x = 0; x < xx; x++) {
                        var cell = this.findCell(x, y);
                        if (cell.visible)
                            cell.div().appendTo(container);
                    }
            }
        }
    
        $(document).ready(function () {
            $('#combine').click(function () {
    
                $(".selected").each(function () {
                    var x = $(this).data('x');
                    var y = $(this).data('y');
                    var cell = cc.findCell(x, y);
    
                    cell.visible = false;
                    cell.g = 'y';
                });
    
                var first = $(".selected").first();
                var xx = $(first).data('x');
                var yy = $(first).data('y');
    
                var cell = cc.findCell(xx, yy);
                var g = new group();
                cell.visible = true;
                cell.g = xx + '_' + yy;
                cell.spanX = g.width();
                cell.spanY = g.height();
    
                cc.displayCells($('#container'));
    
            });
            //make divs clickable
            $('#container').on('click', 'div', function () {
                $(this).toggleClass('selected');
    
                if (CheckIfSelectedAreGroupable())
                    $('#combine').removeAttr("disabled");
                else
                    $('#combine').attr("disabled", "disabled");
            });
    
            cc = new cells(12, 10);
            cc.displayCells($('#container'));
        });
        function CheckIfSelectedAreGroupable() {
            var g = new group();
            return g.CorrectGroup();
        }
    
    
       </script>
    

    Style:

    <style>
    
        .selected {
            background-color: #226fa3 !important;
            transition: background-color 0.4s ease-in, border-color 0.4s ease-in;
            color: #ffffff;
        }
    
        .clickable {
            border: 1px solid lightgray;
            margin: 0px;
            padding: 0px;
            background-color: lightyellow;
            position: absolute;
        }
    
    </style>
    

    Im starting the divs by the following line, you can hock your form to trigger something similar.

    cc = new cells(12, 10);
    

    the combine button will not activate if you dont select a correct group, a rectangle shape selection.

    the split will not be hard too but I did not have time to put it together, if this solution help, I can update it for the split.

    Note: I wrote this quickly so its not optimized.

    to try the solution use : jsfiddle