mirror of
https://github.com/PHPOffice/PhpSpreadsheet.git
synced 2026-09-04 14:38:16 +00:00
Some Problems with Conditional Colorscale for Html
Fix #4838. Some processing of Html Conditional Formatting which worked with PhpSpreadsheet 5.3 does not work with 5.4. There are 2 problems. The first was caused by PR 4763, which moved some code out of Html Writer to an easier-to-access location. One of the intermediate variables in Html Writer was not available in the new location; its simulation turned out to be imperfect. When evaluating Colorscale, the cells in question need to be ranked. This was done using `rangesToArray` with the formatting option set to `true`. This code, inherited from 5.3, was a mistake; it should have been set to `false`. As coded, it created problems for cells formatted as percentages (it is not clear why 5.3 did not suffer a similar fate). Making that change fixes the problem. The fix is demonstrated in the first new test `testPercentages`. A second problem affected 5.3. The code to assign a colorscale color to a cell concatenated the alpha, red, green, and blue colors expressed in hex digits. But it did not properly handle the case when any of those was only 1 digit long. The second new test `testPercentages2` demonstrates that this problem is now fixed.
This commit is contained in:
@@ -120,7 +120,7 @@ class ConditionalColorScale
|
||||
public function setScaleArray(): self
|
||||
{
|
||||
if ($this->sqref !== null && $this->worksheet !== null) {
|
||||
$values = $this->worksheet->rangesToArray($this->sqref, null, true, true, true);
|
||||
$values = $this->worksheet->rangesToArray($this->sqref, null, true, false, true);
|
||||
$this->valueArray = [];
|
||||
foreach ($values as $key => $value) {
|
||||
/** @var array<float|int|string> $value */
|
||||
@@ -166,20 +166,23 @@ class ConditionalColorScale
|
||||
$green2 = hexdec(substr($midColor, 4, 2));
|
||||
$blue1 = hexdec(substr($minColor, 6, 2));
|
||||
$blue2 = hexdec(substr($midColor, 6, 2));
|
||||
|
||||
return strtoupper(dechex((int) ($alpha2 * $blend + $alpha1 * (1 - $blend))) . '' . dechex((int) ($red2 * $blend + $red1 * (1 - $blend))) . '' . dechex((int) ($green2 * $blend + $green1 * (1 - $blend))) . '' . dechex((int) ($blue2 * $blend + $blue1 * (1 - $blend))));
|
||||
} else {
|
||||
$blend = ($value - $this->midValue) / ($this->maxValue - $this->midValue);
|
||||
$alpha1 = hexdec(substr($midColor, 0, 2));
|
||||
$alpha2 = hexdec(substr($maxColor, 0, 2));
|
||||
$red1 = hexdec(substr($midColor, 2, 2));
|
||||
$red2 = hexdec(substr($maxColor, 2, 2));
|
||||
$green1 = hexdec(substr($midColor, 4, 2));
|
||||
$green2 = hexdec(substr($maxColor, 4, 2));
|
||||
$blue1 = hexdec(substr($midColor, 6, 2));
|
||||
$blue2 = hexdec(substr($maxColor, 6, 2));
|
||||
}
|
||||
$blend = ($value - $this->midValue) / ($this->maxValue - $this->midValue);
|
||||
$alpha1 = hexdec(substr($midColor, 0, 2));
|
||||
$alpha2 = hexdec(substr($maxColor, 0, 2));
|
||||
$red1 = hexdec(substr($midColor, 2, 2));
|
||||
$red2 = hexdec(substr($maxColor, 2, 2));
|
||||
$green1 = hexdec(substr($midColor, 4, 2));
|
||||
$green2 = hexdec(substr($maxColor, 4, 2));
|
||||
$blue1 = hexdec(substr($midColor, 6, 2));
|
||||
$blue2 = hexdec(substr($maxColor, 6, 2));
|
||||
$alpha = (int) ($alpha2 * $blend + $alpha1 * (1 - $blend));
|
||||
$red = (int) ($red2 * $blend + $red1 * (1 - $blend));
|
||||
$green = (int) ($green2 * $blend + $green1 * (1 - $blend));
|
||||
$blue = (int) ($blue2 * $blend + $blue1 * (1 - $blend));
|
||||
|
||||
return strtoupper(dechex((int) ($alpha2 * $blend + $alpha1 * (1 - $blend))) . '' . dechex((int) ($red2 * $blend + $red1 * (1 - $blend))) . '' . dechex((int) ($green2 * $blend + $green1 * (1 - $blend))) . '' . dechex((int) ($blue2 * $blend + $blue1 * (1 - $blend))));
|
||||
return sprintf('%02X%02X%02X%02X', $alpha, $red, $green, $blue);
|
||||
}
|
||||
|
||||
private function getLimitValue(string $type, float $value = 0, float $formula = 0): float
|
||||
|
||||
@@ -6,6 +6,11 @@ namespace PhpOffice\PhpSpreadsheetTests\Writer\Html;
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
|
||||
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PhpOffice\PhpSpreadsheet\Style\Color;
|
||||
use PhpOffice\PhpSpreadsheet\Style\Conditional;
|
||||
use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalColorScale;
|
||||
use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalFormatValueObject;
|
||||
use PhpOffice\PhpSpreadsheet\Writer\Html as HtmlWriter;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
@@ -13,7 +18,7 @@ class HtmlConditionalFormattingTest extends TestCase
|
||||
{
|
||||
private string $data = '';
|
||||
|
||||
protected function setUp(): void
|
||||
private function populateData(): void
|
||||
{
|
||||
$file = 'samples/templates/BasicConditionalFormatting.xlsx';
|
||||
$reader = new XlsxReader();
|
||||
@@ -46,6 +51,7 @@ class HtmlConditionalFormattingTest extends TestCase
|
||||
|
||||
public function testConditionalFormattingHtmLOutput(): void
|
||||
{
|
||||
$this->populateData();
|
||||
$expectedMatches = [
|
||||
['B1', 'class="column1 style1 s">Jan<', 'no conditional styling for B1'],
|
||||
['F2', 'background-color:#C6EFCE;">120<', 'conditional style for F2'],
|
||||
@@ -62,4 +68,96 @@ class HtmlConditionalFormattingTest extends TestCase
|
||||
self::assertStringContainsString($expectedString, $string, $message);
|
||||
}
|
||||
}
|
||||
|
||||
public function testPercentages(): void
|
||||
{
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$sheet->fromArray([
|
||||
[0.0014676309754806],
|
||||
[0.0058290134726582],
|
||||
[0.00031478256190473],
|
||||
[0.0075923486102745],
|
||||
[0.0041865730298472],
|
||||
]);
|
||||
$sheet->getStyle('A1:A5')
|
||||
->getNumberFormat()
|
||||
->setFormatCode('0.00%');
|
||||
$conditionals = [];
|
||||
$conditional1 = new Conditional();
|
||||
$colorscale = new ConditionalColorScale();
|
||||
$min = new ConditionalFormatValueObject('min');
|
||||
$max = new ConditionalFormatValueObject('max');
|
||||
$mid = new ConditionalFormatValueObject('percentile', 50);
|
||||
$colorscale
|
||||
->setSqref('A1:A5', $sheet)
|
||||
->setMinimumColor(new Color('83CCEB'))
|
||||
->setMidpointColor(new Color('AEAEAE'))
|
||||
->setMaximumColor(new Color('FF6CAD'))
|
||||
->setMinimumConditionalFormatValueObject($min)
|
||||
->setMidpointConditionalFormatValueObject($mid)
|
||||
->setMaximumConditionalFormatValueObject($max)
|
||||
->setScaleArray();
|
||||
$conditional1->setColorScale($colorscale)
|
||||
->setConditionType(Conditional::CONDITION_COLORSCALE);
|
||||
$conditionals = [$conditional1];
|
||||
$sheet->getStyle('$A$1:$A$5')
|
||||
->setConditionalStyles($conditionals);
|
||||
$writer = new HtmlWriter($spreadsheet);
|
||||
$writer->setConditionalFormatting(true);
|
||||
$html = $writer->generateHtmlAll();
|
||||
self::assertStringContainsString('<td class="column0 style1 n" style="color:#000000;background-color:#8FC3D8;">0.15%</td>', $html);
|
||||
self::assertStringContainsString('<td class="column0 style1 n" style="color:#000000;background-color:#D58EAD;">0.58%</td>', $html);
|
||||
self::assertStringContainsString('<td class="column0 style1 n" style="color:#000000;background-color:#83CCEB;">0.03%</td>', $html);
|
||||
self::assertStringContainsString('<td class="column0 style1 n" style="color:#000000;background-color:#FF6CAD;">0.76%</td>', $html);
|
||||
self::assertStringContainsString('<td class="column0 style1 n" style="color:#000000;background-color:#AEAEAE;">0.42%</td>', $html);
|
||||
$spreadsheet->disconnectWorksheets();
|
||||
}
|
||||
|
||||
public function testPercentages2(): void
|
||||
{
|
||||
// fill color was being returned incorrectly
|
||||
// because some of the colors required leading 0.
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$sheet->fromArray([
|
||||
[0.0014676309754806],
|
||||
[0.0058290134726582],
|
||||
[0.00031478256190473],
|
||||
[0.0075923486102745],
|
||||
[0.0041865730298472],
|
||||
]);
|
||||
$sheet->getStyle('A1:A5')
|
||||
->getNumberFormat()
|
||||
->setFormatCode('0.00%');
|
||||
$conditionals = [];
|
||||
$conditional1 = new Conditional();
|
||||
$colorscale = new ConditionalColorScale();
|
||||
$min = new ConditionalFormatValueObject('min');
|
||||
$max = new ConditionalFormatValueObject('max');
|
||||
$mid = new ConditionalFormatValueObject('percentile', 50);
|
||||
$colorscale
|
||||
->setSqref('A1:A5', $sheet)
|
||||
->setMinimumColor(new Color('FF0000'))
|
||||
->setMidpointColor(new Color('00FF00'))
|
||||
->setMaximumColor(new Color('0000FF'))
|
||||
->setMinimumConditionalFormatValueObject($min)
|
||||
->setMidpointConditionalFormatValueObject($mid)
|
||||
->setMaximumConditionalFormatValueObject($max)
|
||||
->setScaleArray();
|
||||
$conditional1->setColorScale($colorscale)
|
||||
->setConditionType(Conditional::CONDITION_COLORSCALE);
|
||||
$conditionals = [$conditional1];
|
||||
$sheet->getStyle('$A$1:$A$5')
|
||||
->setConditionalStyles($conditionals);
|
||||
$writer = new HtmlWriter($spreadsheet);
|
||||
$writer->setConditionalFormatting(true);
|
||||
$html = $writer->generateHtmlAll();
|
||||
self::assertStringContainsString('<td class="column0 style1 n" style="color:#000000;background-color:#B34B00;">0.15%</td>', $html);
|
||||
self::assertStringContainsString('<td class="column0 style1 n" style="color:#000000;background-color:#00847A;">0.58%</td>', $html);
|
||||
self::assertStringContainsString('<td class="column0 style1 n" style="color:#000000;background-color:#FF0000;">0.03%</td>', $html);
|
||||
self::assertStringContainsString('<td class="column0 style1 n" style="color:#000000;background-color:#0000FF;">0.76%</td>', $html);
|
||||
self::assertStringContainsString('<td class="column0 style1 n" style="color:#000000;background-color:#00FF00;">0.42%</td>', $html);
|
||||
$spreadsheet->disconnectWorksheets();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user