-
-
Notifications
You must be signed in to change notification settings - Fork 638
Enable est column width calculation #866
base: master
Are you sure you want to change the base?
Changes from 5 commits
4f0e72c
d53be7b
8ba78df
a41040d
88afc3d
1b45aff
ea22cac
0a56c40
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,6 +22,21 @@ class Worksheet | |
|
|
||
| /** @var int Index of the last written row */ | ||
| private $lastWrittenRowIndex; | ||
|
|
||
| /** @var array Array of the column widths */ | ||
| protected $columnWidths; | ||
|
|
||
| /** @var int Width calculation style */ | ||
| protected $widthCalcuationStyle; | ||
|
|
||
| /** @var int Fixed sheet width for fixed width calculation style */ | ||
| protected $fixedSheetWidth; | ||
|
|
||
| public const W_FULL = 1; | ||
| public const W_FIXED = 2; | ||
| public const W_NONE = 0; | ||
| public const DEFAULT_COL_WIDTH = 30; | ||
| public const DEFAULT_FIXED_WIDTH = 320; | ||
|
|
||
| /** | ||
| * Worksheet constructor. | ||
|
|
@@ -36,6 +51,8 @@ public function __construct($worksheetFilePath, Sheet $externalSheet) | |
| $this->externalSheet = $externalSheet; | ||
| $this->maxNumColumns = 0; | ||
| $this->lastWrittenRowIndex = 0; | ||
| $this->columnWidths = []; | ||
| $this->widthCalcuationStyle = 0; | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -78,6 +95,79 @@ public function getMaxNumColumns() | |
| return $this->maxNumColumns; | ||
| } | ||
|
|
||
| /** | ||
| * @return array | ||
| */ | ||
| public function getColumnWidths() | ||
| { | ||
| return $this->columnWidths; | ||
| } | ||
|
|
||
| /** | ||
| * Gets the calculated max column width for the specified index | ||
| * @param int $zeroBasedIndex | ||
| * @return int | ||
| */ | ||
| public function getMaxColumnWidth($zeroBasedIndex) | ||
| { | ||
| if (isset($this->columnWidths[$zeroBasedIndex])) { | ||
| return $this->columnWidths[$zeroBasedIndex]; | ||
| } | ||
|
|
||
| $this->columnWidths[$zeroBasedIndex] = self::DEFAULT_COL_WIDTH; | ||
| return $this->columnWidths[$zeroBasedIndex]; | ||
| } | ||
|
|
||
| /** | ||
| * Sets the calculated max column width for the specified index | ||
| * @param int $zeroBasedIndex | ||
| * @param int $value Value to set to | ||
| * @return void | ||
| */ | ||
| public function setMaxColumnWidth($zeroBasedIndex, $value) | ||
| { | ||
| $curSize = $this->columnWidths[$zeroBasedIndex] ?? 0; | ||
| if ($curSize < $value) { | ||
| $this->columnWidths[$zeroBasedIndex] = $value; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Automatically calculates and sets the max column width for the specified cell | ||
| * @param Cell $cell The cell | ||
| * @param Style $style Row/Cell style | ||
| * @param int $zeroBasedIndex of cell | ||
| * @return void | ||
| */ | ||
| public function autoSetWidth($cell, $style, $zeroBasedIndex) | ||
| { | ||
| $size = 1 + strlen($cell->getValue());//ensure we have at least 1 space | ||
| $size *= $style->isFontBold() ? 1.2 : 1.0; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How did you come up with the 1.2 ratio?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's actually meant to be 700/400.. but the 1.2 seemed to fit better.. and that may be because tinier letters like 'i', like you rightly pointed out; occupy less space.. |
||
| $this->setMaxColumnWidth($zeroBasedIndex, $size); | ||
| } | ||
|
|
||
| /** | ||
| * Gets the fixed sheet width or returns the default if not available | ||
| * @return int | ||
| */ | ||
| public function getFixedSheetWidth() | ||
| { | ||
| if (!$this->fixedSheetWidth) { | ||
| return Worksheet::DEFAULT_FIXED_WIDTH; | ||
| } | ||
| return $this->fixedSheetWidth; | ||
| } | ||
|
|
||
| /** | ||
| * Sets the fixed sheet width | ||
| * @param int $width | ||
| * @return void | ||
| */ | ||
| public function setFixedSheetWidth($width) | ||
| { | ||
| $this->fixedSheetWidth = $width; | ||
| } | ||
|
|
||
| /** | ||
| * @param int $maxNumColumns | ||
| */ | ||
|
|
@@ -86,6 +176,29 @@ public function setMaxNumColumns($maxNumColumns) | |
| $this->maxNumColumns = $maxNumColumns; | ||
| } | ||
|
|
||
| /** | ||
| * Set the with calculation style for this sheet. | ||
| * 1=FullExpand,2=FixedWidth,0=None | ||
| * | ||
| * @return Worksheet Enable method chaining for easy set width | ||
| */ | ||
| public function setWidthCalculation($widthStyle) | ||
| { | ||
| $this->widthCalcuationStyle = $widthStyle; | ||
| return $this; | ||
| } | ||
|
|
||
| /** | ||
| * Get the with calculation style for this sheet. | ||
| * 1=FullExpand,2=FixedWidth,0=None | ||
| * | ||
| * @return void | ||
| */ | ||
| public function getWidthCalculation() | ||
| { | ||
| return $this->widthCalcuationStyle; | ||
| } | ||
|
|
||
| /** | ||
| * @return int | ||
| */ | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| <?php | ||
|
|
||
| namespace Box\Spout\Writer\Common\Helper; | ||
|
|
||
| class AppendHelper { | ||
|
|
||
| /** | ||
| * Instead of seeking and re-writing from position, a better hack might be to write dummy empty data | ||
| * Enough to take care of any length, then carefully overwrite | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, that's the strategy I've used elsewhere
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @adrilo Benchmark result with overwriting empty spaces... (negligible again but may be useful)
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tested 5,000 rows, 500,000 rows and 50,000 rows... The script is included below.. |
||
| * | ||
| */ | ||
|
|
||
| /** | ||
| * This function will truncate from specified position | ||
| * Write data to be inserted and re-append the truncated data | ||
| * | ||
| * @param $fp Pointer to file only | ||
| * @param $pos Position to insert | ||
| * @param $content Content to insert | ||
| */ | ||
| public static function insertToFile($fp, $pos, $content) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This can be very costly to rewrite the contents, especially with large spreadsheet
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. True, I will try both approaches and do a benchmark today. It didn't seem to matter for small files.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @adrilo So I ran some tests and this is not actually a bad solution at all... (performance differences range from 3% to 7% and seems to get better for larger amount of rows).. (Only tested 100,000, 500,000 and 1 million rows though) The difference are quite negligible most likely because the file is still in memory the whole time and the only costly operation here is really calling |
||
| { | ||
| fseek($fp, $pos); | ||
| $trailer = stream_get_contents($fp); | ||
| ftruncate($fp, $pos); | ||
| fseek($fp, $pos); | ||
| fwrite($fp, $content); | ||
| fwrite($fp, $trailer); | ||
| return $fp; | ||
| } | ||
| } | ||



Uh oh!
There was an error while loading. Please reload this page.