diff --git a/core/lib/Drupal/Core/Layout/IconGenerator.php b/core/lib/Drupal/Core/Layout/IconGenerator.php
index 1daa0b0..621672d 100644
--- a/core/lib/Drupal/Core/Layout/IconGenerator.php
+++ b/core/lib/Drupal/Core/Layout/IconGenerator.php
@@ -10,7 +10,7 @@ class IconGenerator implements IconGeneratorInterface {
/**
* {@inheritdoc}
*/
- public function generateSvgFromIconMap(array $icon_map, $width = 250, $height = 300, $stroke_width = 2, $padding = 5, $fill = 'lightgray', $stroke = 'black') {
+ public function generateSvg(array $regions, $width, $height, $stroke_width, $fill, $stroke) {
$build = [
'#type' => 'html_tag',
'#tag' => 'svg',
@@ -20,40 +20,8 @@ public function generateSvgFromIconMap(array $icon_map, $width = 250, $height =
],
];
- $region_rects = [];
- $num_rows = count($icon_map);
- foreach ($icon_map as $row => $cols) {
- $num_cols = count($cols);
- foreach ($cols as $col => $region) {
- if (!isset($region_rects[$region])) {
- // The first instance of a region is always the starting point.
- $x = $col * ($width / $num_cols);
- $y = ($row / $num_rows) * $height;
- $region_rects[$region] = [
- 'x' => $x,
- 'y' => $y,
- 'width' => ($width / $num_cols) - $padding,
- 'height' => ($height / $num_rows) - $padding,
- 'last_col' => $col,
- 'last_row' => $row,
- ];
- }
- else {
- // Only increase the width/height if we've moved in that direction.
- if ($region_rects[$region]['last_col'] != $col) {
- $region_rects[$region]['width'] += ($width / $num_cols);
- $region_rects[$region]['last_col'] = $col;
- }
- if ($region_rects[$region]['last_row'] != $row) {
- $region_rects[$region]['height'] += ($height / $num_rows);
- $region_rects[$region]['last_row'] = $row;
- }
- }
- }
- }
-
// Append each polygon to the SVG.
- foreach ($region_rects as $region => $attributes) {
+ foreach ($regions as $region => $attributes) {
// Group our regions allows for metadata, nested elements, and tooltips.
$build[$region] = [
'#type' => 'html_tag',
@@ -85,4 +53,110 @@ public function generateSvgFromIconMap(array $icon_map, $width = 250, $height =
return $build;
}
+ /**
+ * {@inheritdoc}
+ */
+ public function generateSvgFromIconMap(array $icon_map, $width, $height, $stroke_width, $padding, $fill, $stroke) {
+ $regions = $this->calculateSvgValues($icon_map, $width, $height, $stroke_width, $padding);
+ return $this->generateSvg($regions, $width, $height, $stroke_width, $fill, $stroke);
+
+ }
+
+ /**
+ * Calculates the dimensions and offsets of all regions.
+ *
+ * @param array $rows
+ * A two dimensional array representing the visual output of the layout.
+ * See \Drupal\Core\Layout\IconGeneratorInterface::generateSvgFromIconMap().
+ * @param int $width
+ * The width of the generated SVG.
+ * @param int $height
+ * The height of the generated SVG.
+ * @param int $stroke_width
+ * The width of region borders.
+ * @param int $padding
+ * The padding between regions. Any value above 0 is valid.
+ *
+ * @return mixed[]
+ * An array keyed by region name, with each element containing the 'height',
+ * 'width', and 'x' and 'y' offsets of each region.
+ */
+ protected function calculateSvgValues(array $rows, $width, $height, $stroke_width, $padding) {
+ $region_rects = [];
+ if (!$rows) {
+ return $region_rects;
+ }
+
+ $num_rows = count($rows);
+ $row_height = $this->getLength($num_rows, $height, $stroke_width, $padding);
+ foreach ($rows as $row => $cols) {
+ $num_cols = count($cols);
+ $column_width = $this->getLength($num_cols, $width, $stroke_width, $padding);
+ $vertical_offset = $this->getOffset($row, $row_height, $stroke_width, $padding);
+ foreach ($cols as $col => $region) {
+ if (!isset($region_rects[$region])) {
+ $region_rects[$region] = [
+ 'x' => $this->getOffset($col, $column_width, $stroke_width, $padding),
+ 'y' => $vertical_offset,
+ 'width' => $column_width,
+ 'height' => $row_height,
+ // Store the original values.
+ 'original_width' => $column_width,
+ 'original_height' => $row_height,
+ ];
+ }
+ else {
+ $region_rects[$region]['width'] = $this->getOffset($col, $column_width, $stroke_width, $padding) - $region_rects[$region]['x'] + $region_rects[$region]['original_width'];
+ $region_rects[$region]['height'] = $this->getOffset($row, $row_height, $stroke_width, $padding) - $region_rects[$region]['y'] + $region_rects[$region]['original_height'];
+ }
+ }
+ }
+ return $region_rects;
+ }
+
+ /**
+ * Gets the offset for this region.
+ *
+ * @param int $delta
+ * The zero-based delta of the region.
+ * @param int $length
+ * The height or width of the region.
+ * @param int $stroke_width
+ * The width of the region borders.
+ * @param int $padding
+ * The padding between regions.
+ *
+ * @return int
+ * The offset for this region.
+ */
+ protected function getOffset($delta, $length, $stroke_width, $padding) {
+ // Half of the stroke width is drawn outside the dimensions.
+ $stroke_width /= 2;
+ // For every region in front of this add two strokes, as well as one
+ // directly in front.
+ $num_of_strokes = 2 * $delta + 1;
+ return ($num_of_strokes * $stroke_width) + ($delta * ($length + $padding));
+ }
+
+ /**
+ * Gets the height or width of a region.
+ *
+ * @param int $number_of_regions
+ * The total number of regions.
+ * @param int $length
+ * The total height or width of the icon.
+ * @param int $stroke_width
+ * The width of the region borders.
+ * @param int $padding
+ * The padding between regions.
+ *
+ * @return float|int
+ * The height or width of a region.
+ */
+ protected function getLength($number_of_regions, $length, $stroke_width, $padding) {
+ $total_stroke = $number_of_regions * $stroke_width;
+ $total_padding = ($number_of_regions - 1) * $padding;
+ return ($length - $total_padding - $total_stroke) / $number_of_regions;
+ }
+
}
diff --git a/core/lib/Drupal/Core/Layout/IconGeneratorInterface.php b/core/lib/Drupal/Core/Layout/IconGeneratorInterface.php
index 711f8c9..56777f9 100644
--- a/core/lib/Drupal/Core/Layout/IconGeneratorInterface.php
+++ b/core/lib/Drupal/Core/Layout/IconGeneratorInterface.php
@@ -8,7 +8,7 @@
interface IconGeneratorInterface {
/**
- * Generates a SVG based on a Layout's icon map.
+ * Generates an SVG based on an icon map.
*
* @param array $icon_map
* A two dimensional array representing the visual output of the layout.
@@ -31,22 +31,43 @@
* - [first, second, second, third]
* - [bottom].
* @param int $width
- * (optional) The width of the generated SVG. Defaults to 250.
+ * The width of the generated SVG.
* @param int $height
- * (optional) The height of the generated SVG. Defaults to 300.
+ * The height of the generated SVG.
* @param int $stroke_width
- * (optional) The width of region borders. Defaults to 2.
+ * The width of region borders.
* @param int $padding
- * (optional) The padding between regions. Any value above 0 is valid.
- * Defaults to 5.
+ * The padding between regions.
* @param string $fill
- * (optional) The fill color of regions. Defaults to 'lightgray'.
+ * The fill color of regions.
* @param string $stroke
- * (optional) The color of region borders. Defaults to 'black'.
+ * The color of region borders.
*
* @return array
* A render array representing a SVG icon.
*/
- public function generateSvgFromIconMap(array $icon_map, $width = 250, $height = 300, $stroke_width = 2, $padding = 5, $fill = 'lightgray', $stroke = 'black');
+ public function generateSvgFromIconMap(array $icon_map, $width, $height, $stroke_width, $padding, $fill, $stroke);
+
+ /**
+ * Generates an SVG.
+ *
+ * @param mixed[] $regions
+ * An array keyed by region name, with each element containing the 'height',
+ * 'width', and 'x' and 'y' offsets of each region.
+ * @param int $width
+ * The width of the generated SVG.
+ * @param int $height
+ * The height of the generated SVG.
+ * @param int $stroke_width
+ * The width of region borders.
+ * @param string $fill
+ * The fill color of regions.
+ * @param string $stroke
+ * The color of region borders.
+ *
+ * @return array
+ * A render array representing a SVG icon.
+ */
+ public function generateSvg(array $regions, $width, $height, $stroke_width, $fill, $stroke);
}
diff --git a/core/lib/Drupal/Core/Layout/LayoutDefinition.php b/core/lib/Drupal/Core/Layout/LayoutDefinition.php
index cc452a7..a8e43dc 100644
--- a/core/lib/Drupal/Core/Layout/LayoutDefinition.php
+++ b/core/lib/Drupal/Core/Layout/LayoutDefinition.php
@@ -428,7 +428,7 @@ public function setIconMap($icon_map) {
* @return array
* A render array for the icon.
*/
- public function getIcon($width = 250, $height = 300, $stroke_width = 2, $padding = 5, $fill = 'lightgray', $stroke = 'black') {
+ public function getIcon($width = 125, $height = 150, $stroke_width = 1, $padding = 4, $fill = '#f5f5f2', $stroke = '#666') {
$icon = [];
if ($icon_path = $this->getIconPath()) {
$icon = [
diff --git a/core/tests/Drupal/KernelTests/Core/Layout/IconGeneratorTest.php b/core/tests/Drupal/KernelTests/Core/Layout/IconGeneratorTest.php
index bc69478..c08475a 100644
--- a/core/tests/Drupal/KernelTests/Core/Layout/IconGeneratorTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Layout/IconGeneratorTest.php
@@ -13,14 +13,18 @@
class IconGeneratorTest extends KernelTestBase {
/**
+ * @covers ::generateSvg
* @covers ::generateSvgFromIconMap
+ * @covers ::calculateSvgValues
+ * @covers ::getLength
+ * @covers ::getOffset
*
* @dataProvider providerTestGenerateSvgFromIconMap
*/
- public function testGenerateSvgFromIconMap($icon_map, $expected) {
+ public function testGenerateSvgFromIconMap($icon_map, $expected, $stroke_width = 2) {
$renderer = $this->container->get('renderer');
$icon_generator = new IconGenerator();
- $build = $icon_generator->generateSvgFromIconMap($icon_map);
+ $build = $icon_generator->generateSvgFromIconMap($icon_map, 250, 300, $stroke_width, 4, 'lightgray', 'black');
$output = (string) $renderer->executeInRenderContext(new RenderContext(), function () use ($build, $renderer) {
return $renderer->render($build);
});
@@ -38,15 +42,28 @@ public function providerTestGenerateSvgFromIconMap() {
$data['two_column'][] = [['left', 'right']];
$data['two_column'][] = <<<'EOD'
EOD;
+ $data['two_column_no_stroke'][] = [['left', 'right']];
+ $data['two_column_no_stroke'][] = <<<'EOD'
+
+
+EOD;
+ $data['two_column_no_stroke'][] = 0;
+
$data['stacked'][] = [
['sidebar', 'top', 'top'],
['sidebar', 'left', 'right'],
@@ -56,28 +73,28 @@ public function providerTestGenerateSvgFromIconMap() {
];
$data['stacked'][] = <<<'EOD'