Files
pmgr/site/controllers/maps_controller.php

307 lines
11 KiB
PHP

<?php
class MapsController extends AppController {
/**************************************************************************
**************************************************************************
**************************************************************************
* action: index / all
* - Generate a listing of maps
*
* REVISIT <AP> 20090528:
* We'll need to present only those site area maps that correspond
* to the users particular site.
*/
function index() { $this->all(); }
function all() { $this->gridView('All Maps', 'all'); }
/**************************************************************************
**************************************************************************
**************************************************************************
* virtuals: gridData
* - With the application controller handling the gridData action,
* these virtual functions ensure that the correct data is passed
* to jqGrid.
*/
function gridDataTables(&$params, &$model) {
return array
('link' => array('SiteArea' => array('fields' => array('SiteArea.id', 'SiteArea.name')),
),
);
}
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
$links['Map'] = array('id');
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
}
/**************************************************************************
**************************************************************************
**************************************************************************
* action: view
* - Generates a site map page
*/
function view($id = null, $requested_width = 800) {
if (!$id) {
$this->Session->setFlash(__('Invalid Item.', true));
$this->redirect(array('action'=>'index'));
}
$this->sideMenuEnable('SITE', $this->op_area);
$this->set('info', $this->mapInfo($id, $requested_width));
$this->set('title', "Site Map");
}
/**************************************************************************
**************************************************************************
**************************************************************************
* action: map
* - Produces a PNG site map image
*/
function map($id = null, $requested_width = 800) {
if (!$id) {
$this->Session->setFlash(__('Invalid Item.', true));
$this->redirect(array('action'=>'index'));
}
$this->image($this->mapInfo($id, $requested_width));
}
/**************************************************************************
**************************************************************************
**************************************************************************
* mapInfo
*/
function mapInfo($id, $requested_width) {
// Set up array to hold the map information
$info = array('map_id' => $id,
'border' => true,
'units' => array());
// Find all of the map/unit information from this SiteArea
$map = $this->Map->find('first', array('contain' => false,
'conditions' => array('id' => $id)));
$units = $this->Map->Unit->find
('all',
array('link' =>
array('Map' =>
array('fields' => array()),
'CurrentLease' =>
array('fields' => array('id', 'paid_through_date',
$this->Map->Unit->CurrentLease->
delinquentField('CurrentLease')),
'Customer'),
'UnitSize' =>
array('fields' => array('id', 'depth', 'width',
'MapsUnit.pt_top',
'MapsUnit.pt_left',
'MapsUnit.transpose')),
),
'fields' => array('id', 'name', 'status'),
'conditions' => array('Map.id' => $id),
));
/* pr(compact('map', 'units')); */
/* $this->render('/empty'); */
/* return; */
/*****
* The preference would be to leave all things "screen" related
* to reside in the view. However, two separate views need this
* information. The 'view' needs it to include a clickable map
* that corresponds to the map image, and of course, the 'map'
* (or 'image') view needs it to render the image. So, in the
* controller for now, unless I come up with a better idea.
*****/
// Get the overall site limits, and then compute the
// actual boundary extents, adjusting for a border
$boundary_adjustment = 12;
$bottom = 2*$boundary_adjustment + $map['Map']['depth'];
$right = 2*$boundary_adjustment + $map['Map']['width'];
// Scale things according to desired display width
$screen_adjustment_factor = $requested_width / $right;
// Define the overall canvas size
$info['width'] = $right * $screen_adjustment_factor;
$info['depth'] = $bottom * $screen_adjustment_factor;
// Go through each unit in the map, calculating the map location
foreach ($units AS $unit) {
$lft = $unit['MapsUnit']['pt_left'] + $boundary_adjustment;
$top = $unit['MapsUnit']['pt_top'] + $boundary_adjustment;
$width =
$unit['MapsUnit']['transpose']
? $unit['UnitSize']['depth']
: $unit['UnitSize']['width'];
$depth =
$unit['MapsUnit']['transpose']
? $unit['UnitSize']['width']
: $unit['UnitSize']['depth'];
$lft *= $screen_adjustment_factor;
$top *= $screen_adjustment_factor;
$width *= $screen_adjustment_factor;
$depth *= $screen_adjustment_factor;
$info['units'][] =
array( 'id' => $unit['Unit']['id'],
'name' => $unit['Unit']['name'],
'left' => $lft,
'right' => $lft + $width,
'top' => $top,
'bottom' => $top + $depth,
'width' => $width,
'depth' => $depth,
'n-s' => $unit['MapsUnit']['transpose'] ? 0 : 1,
'status' => (($unit['Unit']['status'] === 'OCCUPIED' &&
!empty($unit[0]['delinquent']))
? 'LATE' : $unit['Unit']['status']),
'data' => $unit,
);
}
/* pr($info); */
/* $this->render('/empty'); exit(); */
return $info;
}
/**************************************************************************
**************************************************************************
**************************************************************************
* action: legend
* - Produces a PNG color legend image
*/
function legend($id = null, $requested_width = 400) {
$status = array_keys($this->Map->Unit->activeStatusEnums());
$occupied_key = array_search('OCCUPIED', $status);
array_splice($status, $occupied_key+1, 0, array('LATE'));
$rows = 2;
$cols = (int)((count($status) + $rows - 1) / $rows);
$info = array('units' => array());
// Get the overall site limits, and then compute the
// actual boundary extents, adjusting for a border
$boundary_adjustment = 1;
$item_width = 40; // Absolute values are irrelevant, as they
$item_depth = 10; // will be scaled in the end anyway.
$bottom = 2*$boundary_adjustment + $rows*$item_depth;
$right = 2*$boundary_adjustment + $cols*$item_width;
// Scale things according to desired display width
$screen_adjustment_factor = $requested_width / $right;
// Define the overall canvas size
$info['width'] = $right * $screen_adjustment_factor;
$info['depth'] = $bottom * $screen_adjustment_factor;
// Get a starting point for our top left position.
$top = $lft = $boundary_adjustment;
// Scale it appropriately.
$top *= $screen_adjustment_factor;
$lft *= $screen_adjustment_factor;
$item_width *= $screen_adjustment_factor;
$item_depth *= $screen_adjustment_factor;
foreach ($status AS $code) {
$info['units'][] = array('name' => $code,
'status' => $code,
'width' => $item_width,
'depth' => $item_depth,
'left' => $lft,
'right' => $lft + $item_width,
'top' => $top,
'bottom' => $top + $item_depth);
$top += $item_depth;
if ($top >= $item_depth * $rows) {
$top = $boundary_adjustment * $screen_adjustment_factor;
$lft += $item_width;
}
}
$this->image($info, true);
}
/**************************************************************************
**************************************************************************
**************************************************************************
* helper: image
* - used by actions map & legend to set up unit information and
* color palates before rendering the PNG image.
*/
function image($info, $legend = false) {
$debug = false;
if (!$debug) {
$this->layout = null;
$this->autoLayout = false;
Configure::write('debug', '0');
}
// Define our color palate
// REVISIT <AP>: 20090513
// Get colors from DB option tables
$info['palate']['main']['layout']['bg'] = array('red' => 255, 'green' => 255, 'blue' => 255);
$info['palate']['main']['layout']['border'] = array('red' => 192, 'green' => 192, 'blue' => 192);
$info['palate']['main']['layout']['wall'] = array('red' => 0, 'green' => 0, 'blue' => 0);
$info['palate']['unit']['DELETED']['bg'] = array('red' => 0, 'green' => 0, 'blue' => 0);
$info['palate']['unit']['DAMAGED']['bg'] = array('red' => 192, 'green' => 128, 'blue' => 128);
$info['palate']['unit']['COMPANY']['bg'] = array('red' => 128, 'green' => 192, 'blue' => 128);
$info['palate']['unit']['UNAVAILABLE']['bg'] = array('red' => 128, 'green' => 128, 'blue' => 192);
$info['palate']['unit']['RESERVED']['bg'] = array('red' => 192, 'green' => 192, 'blue' => 128);
$info['palate']['unit']['DIRTY']['bg'] = array('red' => 128, 'green' => 192, 'blue' => 192);
$info['palate']['unit']['VACANT']['bg'] = array('red' => 0, 'green' => 255, 'blue' => 128);
$info['palate']['unit']['OCCUPIED']['bg'] = array('red' => 0, 'green' => 128, 'blue' => 255);
$info['palate']['unit']['LATE']['bg'] = array('red' => 255, 'green' => 192, 'blue' => 192);
$info['palate']['unit']['LOCKED']['bg'] = array('red' => 255, 'green' => 64, 'blue' => 64);
$info['palate']['unit']['LIENED']['bg'] = array('red' => 255, 'green' => 0, 'blue' => 128);
// Determine text color to go with each background
foreach ($info['palate']['unit'] AS &$code) {
$component = $code['bg'];
$method = 3;
if ($method == 1) {
foreach (array('red', 'green', 'blue') AS $prim)
$component[$prim] = 255 - $component[$prim];
} elseif ($method == 2) {
foreach (array('red', 'green', 'blue') AS $prim)
$component[$prim] = ($component[$prim]) >= 128 ? 0 : 255;
} elseif ($method == 3) {
$val = (sqrt(pow($component['red'], 2) +
pow($component['green'], 2) +
pow($component['blue'], 2)) >= sqrt(3) * 128) ? 0 : 255;
foreach (array('red', 'green', 'blue') AS $prim)
$component[$prim] = $val;
}
$code['fg'] = $component;
}
$this->set(compact('info', 'debug'));
$this->render('image');
}
}
?>