summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rettberg2019-03-18 17:50:59 +0100
committerSimon Rettberg2019-03-18 17:51:19 +0100
commit892cba67fba9c442d77be1d467e2152b188c3a81 (patch)
treeddf58d419339314c4170e48ef2c01427fde90bd9
parent[locations] Fix division by zero (diff)
downloadslx-admin-892cba67fba9c442d77be1d467e2152b188c3a81.tar.gz
slx-admin-892cba67fba9c442d77be1d467e2152b188c3a81.tar.xz
slx-admin-892cba67fba9c442d77be1d467e2152b188c3a81.zip
[roomplanner] Implement (auto)rotating SVG, make SVG pretty
-rw-r--r--modules-available/roomplanner/api.inc.php5
-rw-r--r--modules-available/roomplanner/inc/pvsgenerator.inc.php91
-rw-r--r--modules-available/roomplanner/templates/svg-plan.html52
3 files changed, 121 insertions, 27 deletions
diff --git a/modules-available/roomplanner/api.inc.php b/modules-available/roomplanner/api.inc.php
index 1494ba28..055c6b2e 100644
--- a/modules-available/roomplanner/api.inc.php
+++ b/modules-available/roomplanner/api.inc.php
@@ -1,8 +1,9 @@
<?php
if (Request::any('show') === 'svg') {
- $ret = PvsGenerator::generateSvg(Request::any('locationid', 0, 'int'),
- Request::any('machineuuid', false, 'string'));
+ $ret = PvsGenerator::generateSvg(Request::any('locationid', false, 'int'),
+ Request::any('machineuuid', false, 'string'),
+ Request::any('rotate', 0, 'int'));
if ($ret === false) {
Header('HTTP/1.1 404 Not Found');
exit;
diff --git a/modules-available/roomplanner/inc/pvsgenerator.inc.php b/modules-available/roomplanner/inc/pvsgenerator.inc.php
index 4cda4582..6bc8ebee 100644
--- a/modules-available/roomplanner/inc/pvsgenerator.inc.php
+++ b/modules-available/roomplanner/inc/pvsgenerator.inc.php
@@ -145,38 +145,96 @@ class PvsGenerator
}
/**
- * Render given location's room plan as SVG
- * @param int $locationId
+ * Render given location's room plan as SVG.
+ * If locationId is given, show roomplan for that location.
+ * If additionally, machineUuid is given, try to highlight
+ * the given machine in the plan. If only machineUuid is
+ * given, determine locationId from machine.
+ *
+ * @param int|false $locationId
* @param string|false $highlightUuid
+ * @param int $rotate rotate plan (0-3 for N E S W up, -1 for "auto" if highlightUuid is given)
* @return string SVG
*/
- public static function generateSvg($locationId, $highlightUuid = false)
+ public static function generateSvg($locationId = false, $highlightUuid = false, $rotate = 0)
{
+ if ($locationId === false) {
+ $locationId = Database::queryFirst('SELECT locationid FROM machine WHERE machineuuid = :uuid',
+ ['uuid' => $highlightUuid]);
+ if ($locationId !== false) {
+ $locationId = $locationId['locationid'];
+ }
+ }
$machines = self::getMachines($locationId);
if (empty($machines))
return false;
- PvsGenerator::boundingBox($machines, $minX, $minY, $maxX, $maxY);
- $clientSizeX = 4; /* TODO: optimize */
- $clientSizeY = 4; /* TODO: optimize */
- $sizeX = max($maxX - $minX + $clientSizeX, 1); /* never negative */
- $sizeY = max($maxY - $minY + $clientSizeY, 1); /* and != 0 to avoid divide-by-zero in pvsmgr */
+
+ $ORIENTATION = ['north' => 2, 'east' => 3, 'south' => 0, 'west' => 1];
if (is_string($highlightUuid)) {
- $highlightUuid = strtolower($highlightUuid);
+ $highlightUuid = strtoupper($highlightUuid);
+ }
+ // Figure out autorotate
+ $auto = ($rotate < 0);
+ if ($auto && $highlightUuid !== false) {
+ foreach ($machines as &$machine) {
+ if ($machine['machineuuid'] === $highlightUuid) {
+ $rotate = $ORIENTATION[$machine['rotation']];
+ break;
+ }
+ }
}
+ $rotate %= 4;
+ // Highlight given machine, rotate it's "keyboard"
foreach ($machines as &$machine) {
- if (strtolower($machine['machineuuid']) === $highlightUuid) {
+ if ($machine['machineuuid'] === $highlightUuid) {
$machine['class'] = 'hl';
}
+ $machine['rotation'] = $ORIENTATION[$machine['rotation']] * 90;
+ }
+ PvsGenerator::boundingBox($machines, $minX, $minY, $maxX, $maxY);
+ $clientSizeX = 4; /* TODO: optimize */
+ $clientSizeY = 4; /* TODO: optimize */
+ $minX--;
+ $minY--;
+ $maxX++;
+ $maxY++;
+ $sizeX = max($maxX - $minX + $clientSizeX, 1); /* never negative */
+ $sizeY = max($maxY - $minY + $clientSizeY, 1); /* and != 0 to avoid divide-by-zero in pvsmgr */
+ if ($rotate === 0) {
+ $centerY = $centerX = 0;
+ } elseif ($rotate === 1) {
+ $centerX = $minX + min($sizeX, $sizeY) / 2;
+ $centerY = $minY + min($sizeX, $sizeY) / 2;
+ self::swap($sizeX, $sizeY);
+ } elseif ($rotate === 2) {
+ $centerX = $minX + $sizeX / 2;
+ $centerY = $minY + $sizeY / 2;
+ } else {
+ $centerX = $minX + max($sizeX, $sizeY) / 2;
+ $centerY = $minY + max($sizeX, $sizeY) / 2;
+ self::swap($sizeX, $sizeY);
}
return Render::parse('svg-plan', [
- 'width' => $sizeX + 2,
- 'height' => $sizeY + 2,
- 'minX' => $minX - 1,
- 'minY' => $minY - 1,
+ 'width' => $sizeX,
+ 'height' => $sizeY,
+ 'centerX' => $centerX,
+ 'centerY' => $centerY,
+ 'rotate' => $rotate * 90,
+ 'shiftX' => -$minX,
+ 'shiftY' => -$minY,
'machines' => $machines,
+ 'line' => ['x1' => $minX, 'y1' => $maxY + $clientSizeY,
+ 'x2' => $maxX + $clientSizeX, 'y2' => $maxY + $clientSizeY],
], 'roomplanner'); // FIXME: Needs module param if called from api.inc.php
}
+ private static function swap(&$a, &$b)
+ {
+ $tmp = $a;
+ $a = $b;
+ $b = $tmp;
+ }
+
/**
* Get all clients for given room with IP and position.
*
@@ -197,11 +255,16 @@ class PvsGenerator
if ($position === false || !isset($position['gridRow']) || !isset($position['gridCol']))
continue; // TODO: Remove entry/set to NULL?
+ $rotation = 'north';
+ if (preg_match('/(north|east|south|west)/', $position['itemlook'], $out)) {
+ $rotation = $out[1];
+ }
$machines[] = array(
'machineuuid' => $row['machineuuid'],
'clientip' => $row['clientip'],
'gridRow' => $position['gridRow'],
'gridCol' => $position['gridCol'],
+ 'rotation' => $rotation,
);
}
diff --git a/modules-available/roomplanner/templates/svg-plan.html b/modules-available/roomplanner/templates/svg-plan.html
index 1fdb5d1a..5e1e13b2 100644
--- a/modules-available/roomplanner/templates/svg-plan.html
+++ b/modules-available/roomplanner/templates/svg-plan.html
@@ -7,24 +7,54 @@
height="{{height}}mm">
<style type="text/css">
<![CDATA[
- rect {
+ rect {
stroke: #000;
- fill: #fff;
- stroke-width: .5;
+ }
+ rect.kb {
+ fill: #999;
+ stroke-width: .1;
+ }
+ rect.scrn {
+ stroke-width: .2;
+ fill: url(#screen);
}
rect.hl {
- fill: #f00;
+ fill: url(#screenhl);
}
]]>
</style>
- <g transform="translate(-{{minX}}, -{{minY}})">
+ <defs>
+ <radialGradient id="screen" cx=".4" cy=".3" r="1">
+ <stop offset="0%" stop-color="#888" />
+ <stop offset="100%" stop-color="#000" />
+ </radialGradient>
+ <radialGradient id="screenhl" cx=".4" cy=".3" r="1">
+ <stop offset="0%" stop-color="#f83" />
+ <stop offset="100%" stop-color="#b55" />
+ </radialGradient>
+ </defs>
+ <g transform="translate({{shiftX}}, {{shiftY}}) rotate({{rotate}} {{centerX}} {{centerY}})">
+ <line x1="{{line.x1}}" y1="{{line.y1}}"
+ x2="{{line.x2}}" y2="{{line.y2}}"
+ style="stroke:#555;stroke-width:.2;opacity:.5" />
{{#machines}}
- <rect
- x="{{gridCol}}"
- y="{{gridRow}}"
- height="3.8"
- width="3.8"
- class="{{class}}" />
+ <g transform="translate({{gridCol}} {{gridRow}})">
+ <rect transform="rotate({{rotation}} 1.9 1.9)"
+ x=".1"
+ y="2.6"
+ height="1"
+ width="3.6"
+ class="kb" />
+ <rect transform="rotate({{rotation}} 1.9 1.9)"
+ x=".2"
+ y=".2"
+ rx=".4"
+ ry=".4"
+ height="2.2"
+ width="3.4"
+ class="scrn {{class}}"
+ />
+ </g>
{{/machines}}
</g>
</svg>