2014-03-05 74 views
6

我需要找出一種算法,將計算給定的列寬度的優化尺寸以下:算法,用於計算變量的列寬度爲集表寬度

  • 表的寬度被固定在尺寸頁面
  • 的列中的數據將是可變的從而列的寬度是可變的
  • 寬度必須進行優化,以知道何時換列和何時不

所以給出如下數據:

'From' => '03/06/2014', 
'To' => '03/06/2014', 
'First Name' => 'John Doe', 
'Status' => 'approved', 
'Type' => 'PTO', 
'Amount' => '8 Hours', 
'Notes' => 'Oops! Who knew I would need one more day. This should be all I need over the next week to support my trip.' 

我怎麼能計算出最佳的列寬,這樣的「註釋」列不擠壓其他的寬度降低到比可接受的寬度少了?

Sample of Problem

更新:我目前知道的頁面&的字體寬度的寬度,所以我可以計算每列的最大寬度的要求。它應該填充頁面上的可用空間。但是,我寧願列沒有包裝,除非必要。就像這樣:

enter image description here

+0

您可以詢問每個單元格他們的首選最小/最大widhts。 –

+0

只給每一列只有它需要的最小寬度。如果有解決方案,這是可能的 –

+0

你有任何約束像日期列不能換行?你是否允許在包裝之前有最少數量的應該顯示的字符? –

回答

6

一個簡單的解決方案是屬性分配給您的colums;例如您的Notes列可能是flexible。然後,您可以計算所有行上每列的最大寬度,爲所有非靈活列設置該寬度,然後均勻分配剩餘空間(或可能按其最大寬度加權)到靈活列。

但你也可以嘗試找出一些簡單的條件的屬性:

  • 一欄可以自動換行,如果它的任何條目中有空格。在你的例子中,日期和可能的狀態和類型條目不能被包裝。名稱不應該在正常情況下包裝,但可以包裝,如果名稱很長或者給出多個名稱。筆記列應該被包裝。
  • 如果一個色譜柱的最大寬度超過,例如,如果所有大小均勻分佈,則該色譜柱將具有的寬度。

然後按照如上所述進行操作:計算所有非靈活列的寬度。檢查是否有足夠的空間;如果不是這樣,則可以使包裝的柱子變得靈活。然後計算柔性單元的寬度,用它們的最大寬度加權。

可能的僞代碼算法如下。它會自由使用各種啓發式方法,所以你應該用一粒鹽。您可以根據自己的用例調整這些條件,但很難滿足所有可能的情況。

function layout(table[], width, gutter, col[]) 

    var maxw[col.length]  # max. text width over all rows 
    var maxl[col.length]  # max. width of longest word 
    var flex[col.length]  # is column flexible? 
    var wrap[col.length]  # can column be wrapped? 
    var colw[col.length]  # final width of columns 

    foreach row in table: 
     for i = 0 to col.length: 
      cell = row[i] 
      maxw[i] = max(maxw[i], textwidth(cell)) 
      if cell.find(" "): 
       maxl[i] = max(maxl[i], wordwidth(cell)) 

    var left = width - (col.length - 1) * gutter 
    var avg = left/col.length 
    var nflex = 0 

    # determine whether columns should be flexible and assign 
    # width of non-flexible cells 

    for i = 0 to col.length: 
     flex[i] = (maxw[i] > 2 * avg)  # ??? 
     if flex[i]: 
      nflex++ 
     else: 
      colw[i] = maxw[i] 
      left -= colw[i] 

    # if there is not enough space, make columns that could 
    # be word-wrapped flexible, too 

    if left < nflex * avg: 
     for i = 0 to col.length: 
      if !flex[i] and wrap[i]: 
       left += width[i] 
       colw[i] = 0 
       flex[i] = true 
       nflex += 1 

    # Calculate weights for flexible columns. The max width 
    # is capped at the page width to treat columns that have to 
    # be wrapped more or less equal 

    var tot = 0 
    for i = 0 to col.length: 
     if flex[i]: 
      maxw[i] = min(maxw[i], width)  # ??? 
      tot += maxw[i] 

    # Now assign the actual width for flexible columns. Make 
    # sure that it is at least as long as the longest word length 

    for i = 0 to col.length: 
     if flex[i]: 
      colw[i] = left * maxw[i]/tot 
      colw[i] = max(colw[i], maxl[i]) 
      left -= colw[i] 

    return colw 
+1

感謝您的詳細回覆! +1這與我已經構建的類似。我使用標準偏差計算來確定包裹的靈活性。它不需要手動指定哪些列是靈活的,因此它將處理自定義報告。我也做了平均計算,以知道如何必須分配給每列的空間。它適用於大部分。但它不是我需要它的地方。 –

+0

從你的例子來看,你的列只是有點太窄,導致所有列被包裝,甚至沒有中斷點。 (奇怪的是,「8小時」現在包裹了。)因此,您可能需要擴大窄小的列,並通過將空間遠離筆記列來將它們展開至最小寬度。 (或者也許是從所有足夠寬的列均勻分配空間。) –

+0

你是對的。但是,這些列寬度是動態計算的。我們沒有分配寬度。這是問題的目的。拋光算法,看看我們是否可以在統計上更接近正確的寬度。 –

0

我遇到了類似於使用ITextPDF和14列表的問題。數據是可變的,其中一些列可以包裝而其他列不可以。

我的解決方案是通過使用split(「」)來找到每列中最大的單詞。這減少了一個字,日期或數字減半的機率。這是代碼。抱歉,我沒有時間將其編輯爲更一般的格式,希望它能幫助別人。

//This array will store the largest word found in each of the 14 columns 
int[] maxStringLengthPerColumn = new int[14]; 
for(int i = 0; i < maxStringLengthPerColumn.length; i++) 
    maxStringLengthPerColumn[i]=0; 

//for each row in table... 

ArrayList<PdfPRow> rows = table.getRows(); 
for(int a = 0; a < rows.size(); a++){ 


    //for each cell in row 
    PdfPCell[] cellsInRow = rows.get(a).getCells(); 
    for(int b = 0; b < cellsInRow.length; b++){ 

     //Split cell contents at " " and find longest word in each cell 
     String[] splitCell = cellsInRow[b].getPhrase().getContent().split(" "); 


     //find the longest string left after split 
     int largestStringSize = 0; 
     for(int c = 0; c < splitCell.length; c++){ 
      if(splitCell[c].length()>largestStringSize){ 
       largestStringSize=splitCell[c].length(); 
      } 
     } 

     if(largestStringSize>maxStringLengthPerColumn[b]){ 
      //I found that adding 4 to the value worked, change this number to fine tune. 
      maxStringLengthPerColumn[b] = largestStringSize + 4; 
     } 
    } 
} 

/*The pdf library can set width with just an array, you may need to 
convert these values to something else depending on the application. For 
example if you have a width of 800 pixels, the width of col1 would be 
maxStringLengthPerColumn[0]/(sum of maxString0 - 13) * 800*/ 

table.setWidths(maxStringLengthPerColumn); 
0

W3C發佈這樣的東西的算法在它的CSS 3 Tables Algorithms

,我已成功地使用,是相當容易實現更簡單的算法可以在HTML4.1 specs找到:

最小和最大單元寬度,然後用來確定 對應的最小和最大寬度爲列。這些在 轉,用於查找表的最小和最大寬度。 請注意,單元格可以包含嵌套表格,但這並不會使代碼顯着複雜化。下一步是根據可用空間(即,當前的 左右邊距之間的空間)分配列寬度 。

對於跨越多列的單元格,簡單的方法由 將最小/最大寬度平均分配給每個組成部分 列組成。稍微複雜一些的方法是使用非單節單元格的最小/最大寬度來衡量如何分配跨度寬度。 實驗表明,這兩種方法的結合爲各種表提供了良好的 結果。

表格邊框和單元格間距需要包含在指定列寬的 中。有三種情況:

  • 最小表寬度等於或大於可用空間。在這種情況下,分配最小寬度並允許用戶水平滾動。爲了轉換爲盲文,有必要通過引用包含其全部內容的註釋來替換單元格。按照慣例,這些出現在表格之前。
  • 最大的桌子寬度符合可用空間。在這種情況下,將列設置爲其最大寬度。
  • 表的最大寬度大於可用空間,但最小表寬度較小。在這種情況下,找到可用空間和最小表寬度之間的差異,讓它稱爲W. Lets也稱爲D表中最大和最小寬度之間的差異。
    對於每一列,設d爲該列的最大和最小寬度之差。現在將列的寬度設置爲最小寬度加上D乘以D的D倍。這使得最小寬度和最大寬度之間差異較大的列比具有較小差異的列寬。