Angular Inventory System - Drag and Drop Resizable Grid

by dekkard

HTML

<div ng-app="AngularInventory">
    <div ng-controller="Controller">
        <ng-inventory source="items" id="personal-inventory">
        </ng-inventory>
    </div>
</div>


<!--
<div class="inventory-table" id="personal-inventory">
    <div class="inventory-row">
        <div class="inventory-cell">
            <div class="inventory-item grape"></div>
        </div>
        <div class="inventory-cell">
            <div class="inventory-item sword1" data-item-type="weapon sword"></div>
        </div>
        <div class="inventory-cell">
            <div class="inventory-item carrot"></div>
        </div>
        <div class="inventory-cell">
        </div>
        <div class="inventory-cell">
        </div>
    </div>
    <div class="inventory-row">
        <div class="inventory-cell">
            <div class="inventory-item carrot" data-item-type="food"></div>
        </div>
        <div class="inventory-cell">
            <div class="inventory-item meat1" data-item-type="food cookable"></div>
        </div>
        <div class="inventory-cell">
            <div class="inventory-item meat1" data-item-type="food cookable"></div>
        </div>
        <div class="inventory-cell"></div>
        <div class="inventory-cell"></div>
    </div>
    <div class="inventory-row">
        <div class="inventory-cell">
            <div class="inventory-item axe1" data-item-type="weapon axe"></div>    
        </div>
        <div class="inventory-cell">
        </div>
        <div class="inventory-cell">
            <div class="inventory-item grape" data-item-type="food"></div>
        </div>
        <div class="inventory-cell"></div>
        <div class="inventory-cell"></div>
    </div>
</div>

<br />

Chest:
<div class="inventory-table">
    <div class="inventory-row">
        <div class="inventory-cell">
            <div class="inventory-item grape" data-item-type="food"></div>
        </div>
        <div class="inventory-cell">
            <div class="inventory-item sword1"...

CSS

html {
  box-sizing: border-box;
}
*, *:before, *:after {
    box-sizing: inherit;
}

body
{
    background: #332f2c;
  
    color: #dddddd;
    font-family: Arial;
}

/* Item atlas: http://i.imgur.com/ngGK5MF.png
 * Table atlas: http://i.imgur.com/nOqKSbE.png
*/

a, a:link, a:visited { 
  color: #c00;
  text-decoration: none;
  
  -webkit-transition: all 0.3s ease;  
  transition: all 0.3s ease;
}
a:hover { 
  color: #ff5c19;
  text-decoration: underline;
}  
a:active { 
  color: #6aff19;
}
input[type="range"]
{
    width: 400px;
}

.inventory-table
{

}

.inventory-row
{
    display: flex;
	flex-direction: row;
	justify-content: flex-start; /* align items in Main Axis */
	align-items: flex-start; /* align items in Cross Axis */
	align-content: flex-start; /* Extra space in Cross Axis */
}


.inventory-cell
{
    width: 36px;
    height: 36px;
    
    flex-shrink: 0;
    
    display: flex;
    flex-direction: row;
    justify-content: center; /* align items in Main Axis */
    align-items: center; /* align items in Cross Axis */
    align-content: center; /* Extra space in Cross Axis */
    
    background-image: url('http://i.imgur.com/nOqKSbE.png');
    background-position: -229px -331px;
}

/* left */
.inventory-cell:first-child
{
    width: 38px;
    padding-left: 2px;
    
    background-position: -190px -331px;
}

/* right */
.inventory-cell:last-child
{
    width: 38px;
    padding-right: 2px;
    
    background-position: -266px -331px;
}
    

/* top ROW */
.inventory-row:first-child .inventory-cell
{
    height: 38px;
    padding-top: 2px;
    
    background-position: -229px -292px;
}

/* bottom ROW */
.inventory-row:last-child .inventory-cell
{
    height: 38px;
    padding-bottom: 2px;
    
    background-position: -229px -368px;
}

/* top left */
.inventory-row:first-child .inventory-cell:first-child
{
    width: 38px;
    height: 38px;
    
    background-position: -190px -292px;
}

/* top right */
.inventory-row:first-child...

JavaScript

var app = angular.module("AngularInventory", [])
	.controller('Controller', function Controller($scope) {
        // 4x2 table
        $scope.items = [
            // row 1
            [ 
                { name: "grape"  },
                { name: "sword1", type: "weapon sword" },
                { name: "carrot"  },
                {}
            ],
            // row 2
            [
                { name: "meat1", type: "food cookable" },
                {},
                { name: "axe1", type: "weapon axe" },
                { name: "meat1", type: "food cookable" }
            ]
        ];
        
        $scope.tableLength = $scope.tableHeight = 0;
        
        var tableDimensions = (function scopeGetDimensions() {
            var tableLength = 0;
            var tableHeight = $scope.items.length;
            
        	for (var i = 0; i < tableHeight; ++i ) {
                var rowLength = $scope.items[i].length;
            	if ( tableLength < rowLength ) {
                	tableLength = rowLength;
                }
            }
            
            return { length: tableLength, height: tableHeight };
        })();
        
        $scope.tableLength = tableDimensions.length;
        $scope.tableHeight = tableDimensions.height;
	})

	.directive('ng-inventory', function directiveNgInventory(){
    	return {
        	restrict: 'E',
            replace: true,
            scope: {
                rows: '=source',
                id: '@'
            },
            template: 
            	'<div class="inventory-table" id="{{id}}">' +
            		'<div class="inventory-row" ng-repeat="row in items">' +
            			'<div class="inventory-cell" ng-repeat="column in row">' + 
            				'<div class="inventory-item {{column.name}}" ' +
            					'{{ column.type && "data-item-type=\"" + column.type + "\"" }}' +
            				'></div>' +
            			'</div>' +
            		'</div>' +
            	'</div>'
        }
    })
;


/*
"use...