2

我有一个由 50 个对象组成的数组,每个对象的宽度和高度都不同。我的目标是创建面板来容纳这些对象并使它们保持有序,但是这个面板不能超过 300 像素的宽度或 600 像素的高度,所以我必须在这个面板中尽可能多地放置对象,如果它们不适合然后我需要创建一个新面板,直到没有更多项目要附加。
因此,例如,如果我有一个尺寸为 150x75 的项目,那么我只能放置另一个相同尺寸的对象,如果下一个项目没有这个尺寸,那么我创建一个空对象来占用这些空白空间。可以在Codepen.io上找到一个示例 现在只要每个项目的高度为 75px 就可以工作,但是当高度超过这个值时就会出现问题。几天来,我一直在尝试解决这个问题,但是这个特殊的任务似乎会抛出整个设计。这是我检查物品是否合适的逻辑:

layout.prototype.createPanel = function(){
//create a new panel
var panel = '<div style="float:left;margin:5px;border:2px solid black;min-width:'+this.WIDTH+'px;min-height:'+this.HEIGHT+'px;">';
var h = 0;
//as long as the panel height does not exceed the constant height
while(h < this.HEIGHT){
    //this.commands += h+'<br>';
    var w = 0;
    panel += '<div>'; //create a new row
    //as long as the panel width does not exceed the constant width
    while(w < this.WIDTH){
        var el = this.items[0]; //grab the first item for checking purposes
        var fits = false;
        //if the current column is the first one, then just check if the item fits vertically
        if(w < this.int_width){
            //as long as the item's height plus the current height of this panel is less than the static height, then it fits
            fits = h + el.height <= this.HEIGHT ? true : false;
        }
        //else check if it fits horizontal and vertically
        else{
            if(this.fitsHorizontal(w,el.width) && h + el.height <= this.HEIGHT){
                fits = true;
            }
            else{
                fits = false;
            }
        }
        //if the item fits, remove it from the array and append it to the panel
        if(fits){
            el = this.items.shift();
            panel += el.html;
            w+= el.width;   //update the width
            this.desired_height = el.height;    //update the new desired height     

            //if this shifted item was the last one then terminate execution to avoid any infinite loops
            if(this.items.length == 0){
                this.has_items = false;
                break;
            }
        }
        //else create an empty element to fill up the space needed
        else{
            panel += '<div style="float:left;width:'+(this.WIDTH - w)+'px;height:'+this.desired_height+'px;background-color:#ccc;margin:1px;"></div>';
            el.height = this.int_height;
            break;
        }
    }
    panel += '</div>'; //close the row

    //if this shifted item was the last one then terminate execution to avoid any infinite loops
    if(!this.has_items){
        this.has_items = false;
        break;
    }
    h+=this.desired_height;
}
panel += '</div>'; //close the panel
return panel;
}
layout.prototype.fitsHorizontal = function(current_width,item_width){
//if the current width plus the item width is less than the constant width them the item fits horizontal
if(current_width + item_width <= this.WIDTH){
    return true;
}
return false;
}
layout.prototype.fitsVertical = function(current_height,item_height){
if(current_height + item_height <= this.HEIGHT && item_height == this.desired_height){
    return true;
}
return false;
}

逻辑有什么问题吗?如果我重新排序这些物品,我现在可以解决它,但它们必须保持有序。完整代码可以在Codepen.io上找到

4

1 回答 1

0

更新

关于您的代码,我不明白是什么问题,因为不清楚。我想给你一些提示:
- 当你需要和某人一起工作时(比如这里,如果你需要帮助,或者在一个项目中等),你应该分享你知道的相同的东西。
- 在这种情况下,语言不是规范,你应该尽可能地抽象代码,伪代码是一个好的开始。
-您可以通过一些示例以及图像和方案来描述您遇到的问题。
- 如果您添加特定的编码来代表问题,您应该尊重该编码。

目前还不清楚您的代码是如何工作的,因为它似乎是 js 和伪代码之间的混合体。据我所知,第一个逻辑错误似乎与空间划分(行列)有关:例如,如果您有 4 个元素 1x1(行 x 列),它们将填充 1 行但是,如果您有 1 个元素 1x1 ,1 个元素 2x1(行 x 列)、1 个元素 1x1(行 x 列)和另一个元素 2x1(行 x 列),它们完成了一行,但您也会在下面的行中找到一些片段,而您没有似乎在您的代码中注册了这种行为。

例如

我希望能很好地理解,这里是jsfiddle,这里是代码:

<!DOCTYPE html>
<head>
<style>
.pad div{
    margin:1px;
}
.pad{
    background-color:#FFF;
    border:#000 1px solid;
}
</style>
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
<body>
<script>
var pieceN=50;
var pieces = [];
const multip = 75;
var actualmaxheight=0;
const h=600;
const w=300;
const maxrows = 5;
const maxcols = 4;
var id="";
var actualcontent=0;
$('body').append('<div id="content'+actualcontent+'" class="pad" style="'+
                        'height:'+(h+4)+'px;width:'+(w+4)+'px"></div>');
id='content'+actualcontent;
actualcontent++;
//creating objects n times
for(var i=0; i<(pieceN); i++){
    color=(Math.floor(Math.random()*16777215)).toString(16);
    if(color.length==5){ color=color+'0'};
    if(color.length==4){ color=color+'00'};
    //for faster thing I'll use an already sorted array
    eit = Math.floor((Math.random()*maxrows)+1);
    wid = Math.floor((Math.random()*maxcols)+1);
    pieces.push({
        'height': eit*multip,
        'width': wid*multip,
        'rows': eit,
        'cols': wid,
        'color':'#'+color
    });
}
var copy=pieces;
var i =0;
//while i is less then the number of the objects -1
//the last element will be inserted afther this cycle
//it can be also inserted in the cylce, anyway it's only 1 loop
while(i<pieces.length-1){
    //if there is enough height for the element in the container
    if(h-actualmaxheight>=parseInt(pieces[i].height)){ 
        //the width fill te container width (insert)
        if(parseInt(pieces[i].width)==w){
            document.getElementById(id).innerHTML+=
                '<div id="'+pieces.length+'" style="'+
                'width:'+pieces[i].width+'px;'+
                'height:'+pieces[i].height+'px;'+
                'background-color:'+pieces[i].color+';'+
                'float:left"></div>';
            actualmaxheight+=parseInt(pieces[i].height);
        }else{//if the width don't fill te container
          //if this elem+nextone width fill the container width (insert x 2)
          if(((parseInt(pieces[i].width)+parseInt(pieces[i+1].width))==w) && (parseInt(pieces[i].height)==parseInt(pieces[i+1].height))){
              document.getElementById(id).innerHTML+=
                  '<div id="'+i+'" style="'+
                  'width:'+pieces[i].width+'px;'+
                  'height:'+pieces[i].height+'px;'+
                  'background-color:'+pieces[i].color+';'+
                  'float:left"></div>'+
                  '<div id="'+(i+1)+'" style="'+
                  'width:'+pieces[i+1].width+'px;'+
                  'height:'+pieces[i+1].height+'px;'+
                  'background-color:'+pieces[i+1].color+';'+
                  'float:left"></div>';
              actualmaxheight+=parseInt(pieces[i].height);
              i++;//because 2 inserted
          }else{
              //else we insert 1 elem + 1 filling element
              document.getElementById(id).innerHTML+=
                  '<div id="'+i+'" style="'+
                  'width:'+pieces[i].width+'px;'+
                  'height:'+pieces[i].height+'px;'+
                  'background-color:'+pieces[i].color+';'+
                  'float:left"></div>'+
                  '<div id="'+(pieces.length+100)+'" style="'+
                  'width:'+(w-pieces[i].width)+'px;'+
                  'height:'+pieces[i].height+'px;'+
                  'background-color:'+pieces[i].color+';'+
                  'float:left"></div>';
              actualmaxheight+=parseInt(pieces[i].height);
          }
        }
    i++;//we surely inserted an elem
    }else{
        //else the container have not enough height for this elem
        //fill the height with a black block and don't increase i
        //because we inserted nothing
        document.getElementById(id).innerHTML+=
            '<div id="'+(pieces.length+1000)+'" style="'+
            'width:'+w+'px;'+
            'height:'+(h-actualmaxheight)+'px;'+
            'background-color:#000000;'+
            'float:left;color:#FFFFFF">here to fill H</div>';
        $('body').append('<div id="content'+actualcontent+'" class="pad" style="'+
                        'height:'+(h+6+actualcontent*1.2)+'px;width:'+(w+4)+'px;color:#FFFFFF"></div>');
        id='content'+actualcontent++; //id of the container updated
        actualmaxheight=0;//reset height
    }
}
//insert last element
i=pieces.length-1;//get its array index
if(h-actualmaxheight>=pieces[i].height){//there is enough height in this container
    //the elem fill the width
    if(parseInt(pieces[i].width)==w){
      actualmaxheight+=pieces[i].height;
      document.getElementById(id).innerHTML+=
          '<div id="'+pieces.length+'" style="'+
          'width:'+pieces[i].width+'px;'+
          'height:'+pieces[i].height+'px;'+
          'background-color:'+pieces[i].color+';'+
          'float:left"></div>'+
          '<div id="'+(pieces.length+1000)+'" style="'+
          'width:'+w+'px;'+
          'height:'+(h-actualmaxheight)+'px;'+
          'background-color:#000000;color:#FFFFFF;'+
          'float:left">here to fill H</div>';
    }else{ //the elem don't fill the width
      actualmaxheight+=pieces[i].height;
      document.getElementById(id).innerHTML+=
          '<div id="'+pieces.length+'" style="'+
          'width:'+pieces[i].width+'px;'+
          'height:'+pieces[i].height+'px;'+
          'background-color:'+pieces[i].color+';'+
          'float:left"></div>'+
          '<div id="'+(pieces.length+10000)+'" style="'+
          'width:'+(w-pieces[i].width)+'px;'+
          'height:'+pieces[i].height+'px;'+
          'background-color:'+pieces[i].color+';'+
          'float:left"></div>'+
          '<div id="'+(pieces.length+1000)+'" style="'+
          'width:'+w+'px;'+
          'height:'+(h-actualmaxheight)+'px;'+
          'background-color:#000000;color:#FFFFFF;'+
          'float:left">here to fill H</div>';
    }
}else{//there is not enough height in this container
    if(parseInt(pieces[i].width)==w){//the elem fill the width
      //fill the height with a black block
      document.getElementById(id).innerHTML+=
          '<div id="'+(pieces.length+1000)+'" style="'+
          'width:'+pieces[i].width+'px;'+
          'height:'+(h-actualmaxheight)+'px;'+
          'background-color:#000000;color:#FFFFFF;'+
          'float:left">here to fill H</div>';
      //create another container and add the elem + black block to fill the height
      actualmaxheight=parseInt(pieces[i].height);
          $('body').append('<div id="content'+actualcontent+'" class="pad" style="'+
          'height:'+(h+4)+'px;width:'+(w+4)+'px">'+
          '<div id="'+pieces.length+'" style="'+
          'width:'+pieces[i].width+'px;'+
          'height:'+pieces[i].height+'px;'+
          'background-color:'+pieces[i].color+';'+
          'float:left"></div>'+
          '<div id="'+(pieces.length+1000)+'" style="'+
          'width:'+w+'px;'+
          'height:'+(h-actualmaxheight)+'px;'+
          'background-color:#000000;color:#FFFFFF;'+
          'float:left">here to fill H</div>'+
          '</div>');
    }else{//the elem don't fill the width
      //fill the height with a black block to fill the height
      document.getElementById(id).innerHTML+=
          '<div id="'+(pieces.length+1000)+'" style="'+
          'width:'+w+'px;'+
          'height:'+(h-actualmaxheight)+'px;'+
          'background-color:#000000;color:#FFFFFF;'+
          'float:left">here to fill H</div>';
          actualmaxheight=parseInt(pieces[i].height);
      //create another container and add the elem + 1 elem to fill the width 
      //+ 1 black block to fill the height
      $('body').append('<div id="content'+actualcontent+'" class="pad" style="'+
          'height:'+(h+4)+'px;width:'+(w+4)+'px">'+
          '<div id="'+pieces.length+'" style="'+
          'width:'+pieces[i].width+'px;'+
          'height:'+pieces[i].height+'px;'+
          'background-color:'+pieces[i].color+';'+
          'float:left"></div>'+
          '<div id="'+(pieces.length+100)+'" style="'+
          'width:'+(w-pieces[i].width)+'px;'+
          'height:'+pieces[i].height+'px;'+
          'background-color:'+pieces[i].color+';'+
          'float:left"></div>'+
          '<div id="'+(pieces.length+1000)+'" style="'+
          'width:'+w+'px;'+
          'height:'+(h-actualmaxheight)+'px;'+
          'background-color:#000000;color:#FFFFFF;'+
          'float:left">here to fill H</div>'+
          '</div>');
    }
}
/*
//print the elments
for(var i=0; i<(copy.length); i++){
    $('body').append('<div id="el'+i+'"'+ 
        'style="width:'+copy[i].width+'px;'+
        'height:'+copy[i].height+'px;'+
        'background-color:'+copy[i].color+';float:left"></div>'
    );
}
*/
</script>
</body>
</html>

我想澄清一些观点

  1. 对象尺寸是某物的倍数还是它们只是随机的?
  2. 您需要在哪里添加填充块,靠近您找不到另一块具有相同高度且宽度总和为 300 的块?
  3. 根据您要搜索的对象数量,一个对象可以与多个对象匹配或更少,这显然会增加所需的时间。

无论如何,为了呈现一些东西,我编写了这个算法(jsfiddle),它可能有用也可能没用,具体取决于你在搜索什么:

<!DOCTYPE html>
<head>
<style>
.pad div{
    margin:1px;
}
.pad{
    background-color:#FFF;
    border:#000 1px solid;
}
</style>
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
<body>
<script>
var pieceN=50;
var pieces = [];
var actualmaxheight=0;
var h=600;
var w=300;
var flag=0;

$('body').append('<div id="content0" class="pad" style="'+
                        'height:'+(h+4)+'px;width:'+(w+4)+'px"></div>');
//creating objects n times
for(var i=0; i<(pieceN); i++){
    color=(Math.floor(Math.random()*16777215)).toString(16);
    if(color.length==5){ color=color+'0'};
    //for faster thing I'll use an already sorted array
    pieces.push({
        'height': Math.floor((Math.random()*600)+1),
        'width':Math.floor((Math.random()*150)+1),
        'color':'#'+color
    });
}
var copy=pieces;
id='content0';
//for all the elements aren't placed(i remove every placed element)
for(i=0;i<pieces.length;i++){
    flag=0;
    k=0;
    //while k<pieces.length confront every piece[k] with piece[i]
    while(k<pieces.length){
        //if exist 2 piece with sum of width==w(300), the same height and the actual container have enough height, let's add them 
        if(parseInt(pieces[i].width)+parseInt(pieces[k].width)==w && pieces[i].height==pieces[k].height && ((h-actualmaxheight)>parseInt(pieces[i].height))){
            document.getElementById(id).innerHTML+='<div id="e'+(i+k)+'"'+ 
            'style="width:'+pieces[i].width+'px;'+
            'height:'+pieces[i].height+'px;'+
            'background-color:'+pieces[i].color+';float:left"></div>'+
            '<div id="e'+(k+i)+'2"'+ 
            'style="width:'+pieces[k].width+'px;'+
            'height:'+pieces[k].height+'px;'+
            'background-color:'+pieces[k].color+';float:left"></div>';
            actualmaxheight+=parseInt(pieces[i].height);
            //remove them from the array
            pieces = $.grep( pieces, function(n,index){
                return index != k;
            });
            pieces = $.grep( pieces, function(n,index){
                return index != i;
            });
            flag=1;
        }
        k++;
    }
    //if we inserted 0 elements in the while before, we have 2 reason
    //1) there aren't 2 elements which satisfy the rules
    //in this case we add the element with an element created to fill the empty space orizontal
    if(flag==0){
        for(j=0;j<pieces.length;j++){
            if((h-actualmaxheight)>parseInt(pieces[j].height)){
                document.getElementById(id).innerHTML+='<div id="e'+i+'"'+ 
                'style="width:'+pieces[j].width+'px;'+
                'height:'+pieces[j].height+'px;'+
                'background-color:'+pieces[j].color+';float:left"></div>'+
                '<div id="e'+i+'2"'+ 
                'style="width:'+(w-parseInt(pieces[j].width))+'px;'+
                'height:'+pieces[j].height+'px;'+
                'background-color:'+pieces[j].color+';float:left"></div>';
                actualmaxheight+=parseInt(pieces[j].height);
                pieces = $.grep( pieces, function(n,index){
                    return index != j;
                });
            }
        }
    }
    //2) there isn't an element which can be conained in the space remained in the container
    //in this case we add a black stripe to fill the space vertical
    if(actualmaxheight<h){
        document.getElementById(id).innerHTML+='<div id="e'+j+i*k+'"'+ 
        'style="width:300px;'+
        'height:'+(h-actualmaxheight)+'px;'+
        'background-color:#000000;float:left;color:#FFFFFF">i fill the space</div>';                
    }
    //then we create a new container to repeat until all the elements are placed
    $('body').append('<div class="pad" id="content'+j+'"'+
        'style="margin-top:10px;'+
        'height:'+(h+4)+'px;width:'+(w+4)+'px"></div>');
    id='content'+j;
    actualmaxheight=0;
    i=0;
}
//print the elments
for(var i=0; i<(copy.length); i++){
    $('body').append('<div id="el'+i+'"'+ 
        'style="width:'+copy[i].width+'px;'+
        'height:'+copy[i].height+'px;'+
        'background-color:'+copy[i].color+';float:left"></div>'
    );
}
</script>
</body>
</html>
于 2013-06-18T15:07:09.887 回答