and also specifying part of // an image with an IMAGE control. // // class HTML_ImageMap_Area { var $href; var $name; var $id; var $alt; var $z; var $extrahtml; function common_html() { $h = ''; if ($this->name !== '') { $h .= ' id="' . $this->name . '" '; } if ($this->href !== '') { $h .= ' href="' . $this->href . '" '; } else { $h .= ' nohref '; } if ($this->extrahtml !== '') { $h .= ' ' . $this->extrahtml . ' '; } return $h; } } class HTML_ImageMap_Area_Polygon extends HTML_ImageMap_Area { var $points = array (); var $minx, $maxx, $miny, $maxy; // bounding box var $npoints; function asHTML() { $s1 = ""; $i = 0; foreach ($this->points as $point) { if ($i > 0) { $s1 .= ", "; } $s1 .= $point[0]. "," . $point[1]; $i++; } $coordstring = $s1; return 'common_html() . ' shape="poly" coords="' . $coordstring . '" />'; } function asJSON() { $json = "{ \"shape\":'poly', \"npoints\":" . $this->npoints . ", \"name\":'" . $this->name . "',"; $xlist = ''; $ylist = ''; foreach ($this->points as $point) { $xlist .= $point[0] . ','; $ylist .= $point[1] . ','; } $xlist = rtrim($xlist, ', '); $ylist = rtrim($ylist, ', '); $json .= ' "x": [ ' . $xlist . ' ], "y":[ ' . $ylist . ' ], "minx": ' . $this->minx . ', "miny": ' . $this->miny . ', "maxx":' . $this->maxx . ', "maxy":' . $this->maxy . '}'; return ($json); } function hitTest($x, $y) { $c = 0; // do the easy bounding-box test first. if (($x < $this->minx) || ($x > $this->maxx) || ($y < $this->miny) || ($y > $this->maxy)) { return false; } // Algotithm from from // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html#The%20C%20Code for ($i = 0, $j = $this->npoints - 1; $i < $this->npoints; $j = $i++) { $x1 = $this->points[$i][0]; $y1 = $this->points[$i][1]; $x2 = $this->points[$j][0]; $y2 = $this->points[$j][1]; if (((($y1 <= $y) && ($y < $y2)) || (($y2 <= $y) && ($y < $y1))) && ($x < ($x2 - $x1) * ($y - $y1) / ($y2 - $y1) + $x1)) { $c = !$c; } } return ($c); } function Draw($im, $col) { $pts = array(); foreach ($this->points as $point) { $pts[] = $point[0]; $pts[] = $point[1]; } imagepolygon($im, $pts, count($pts)/2, $col); } function HTML_ImageMap_Area_Polygon($name = '', $href = '', $coords) { $c = $coords[0]; $this->name = $name; $this->href = $href; $this->npoints = count($c) / 2; if (intval($this->npoints) !== ($this->npoints)) { die('Odd number of points in HTML_ImageMap_Area_Polygon!'); } for ($i = 0; $i < count($c); $i += 2) { $x = round($c[$i]); $y = round($c[$i + 1]); $point = array ( $x, $y ); $xlist[] = $x; // these two are used to get the bounding box in a moment $ylist[] = $y; $this->points[] = $point; } $this->minx = min($xlist); $this->maxx = max($xlist); $this->miny = min($ylist); $this->maxy = max($ylist); } } class HTML_ImageMap_Area_Rectangle extends HTML_ImageMap_Area { var $x1, $x2, $y1, $y2; function HTML_ImageMap_Area_Rectangle($name = '', $href = '', $coords) { $c = $coords[0]; $x1 = round($c[0]); $y1 = round($c[1]); $x2 = round($c[2]); $y2 = round($c[3]); // sort the points, so that the first is the top-left if ($x1 > $x2) { $this->x1 = $x2; $this->x2 = $x1; } else { $this->x1 = $x1; $this->x2 = $x2; } if ($y1 > $y2) { $this->y1 = $y2; $this->y2 = $y1; } else { $this->y1 = $y1; $this->y2 = $y2; } $this->name = $name; $this->href = $href; } function hitTest($x, $y) { return (($x > $this->x1) && ($x < $this->x2) && ($y > $this->y1) && ($y < $this->y2)); } function Draw($im, $col) { imagerectangle($im, $this->x1, $this->y1, $this->x2, $this->y2, $col); } function asHTML() { $coordstring = join(',', array ( $this->x1, $this->y1, $this->x2, $this->y2 )); return 'common_html() . ' shape="rect" coords="' . $coordstring . '" />'; } function asJSON() { $json = "{ \"shape\":'rect', "; $json .= ' "x1":' . $this->x1 . ', "y1":' . $this->y1 . ', "x2":' . $this->x2 . ', "y2":' . $this->y2 . ', "name":\'' . $this->name . "'}"; return ($json); } } class HTML_ImageMap_Area_Circle extends HTML_ImageMap_Area { var $centx, $centy, $edgex, $edgey; function asHTML() { $coordstring = join(',', array ( $this->centx, $this->centy, $this->edgex, $this->edgey )); return 'common_html() . ' shape="circle" coords="' . $coordstring . '" />'; } function hitTest($x, $y) { $radius1 = ($this->edgey - $this->centy) * ($this->edgey - $this->centy) + ($this->edgex - $this->centx) * ($this->edgex - $this->centx); $radius2 = ($this->centy - $y) * ($this->centy - $y) + ($this->centx - $x) * ($this->centx - $x); return ($radius2 <= $radius1); } function Draw($im, $col) { $radius = abs($this->centx - $this->edgex); imageellipse($image, $this->centx, $this->centy, $radius, $radius, $col); imagerectangle($im, $this->x1, $this->y1, $this->x2, $this->y2, $col); } function HTML_ImageMap_Area_Circle($name = '', $href = '', $coords) { $c = $coords[0]; $this->name = $name; $this->href = $href; $this->centx = round($c[0]); $this->centy = round($c[1]); $this->edgex = round($c[2]); $this->edgey = round($c[3]); } } class HTML_ImageMap { var $shapes; var $nshapes; var $name; function HTML_ImageMap($name = '') { $this->Reset(); $this->name = $name; } function Reset() { $this->shapes = array (); $this->nshapes = 0; $this->name = ''; } /** * Draw the outlines for the imagemap - for debugging * * @param GDImageRef $im * @param GDColorRef $col */ function Draw($im, $col) { foreach ($this->shapes as $shape) { $shape->Draw($im, $col); } } // add an element to the map - takes an array with the info, in a similar way to HTML_QuickForm /** * * @param string OR object $element * @param optional string name * @param optional string href * @param optional type-specific stuff * @return null */ function addArea($element) { if ((true === is_object($element)) && (true === is_subclass_of($element, 'html_imagemap_area'))) { $elementObject = &$element; } else { $args = func_get_args(); $className = 'HTML_ImageMap_Area_' . $element; $elementObject = new $className($args[1], $args[2], array_slice($args, 3)); } $this->shapes[$elementObject->name] = &$elementObject; $this->nshapes++; } // do a hit-test based on the current map // - can be limited to only match elements whose names match the filter // (e.g. pick a building, in a campus map) function hitTest($x, $y, $namefilter = '') { $preg = '/' . $namefilter . '/'; foreach ($this->shapes as $shape) { if (true === $shape->hitTest($x, $y)) { if (($namefilter === '') || (1 === preg_match($preg, $shape->name))) { return $shape->name; } } } return false; } // update a property on all elements in the map that match a name // (use it for retro-actively adding in link information to a pre-built geometry before generating HTML) // returns the number of elements that were matched/changed function setProp($which, $what, $where) { $count = 0; if (true === isset($this->shapes[$where])) { // this USED to be a substring match, but that broke some things // and wasn't actually used as one anywhere. switch ($which) { case 'href': $this->shapes[$where]->href = $what; $count++; break; case 'extrahtml': $this->shapes[$where]->extrahtml = $what; $count++; break; } } return $count; } // update a property on all elements in the map that match a name as a substring // (use it for retro-actively adding in link information to a pre-built geometry before generating HTML) // returns the number of elements that were matched/changed function setPropSub($which, $what, $where) { $count = 0; for ($i = 0; $i < count($this->shapes); $i++) { if (($where === '') || (strstr($this->shapes[$i]->name, $where) !== false)) { switch ($which) { case 'href': $this->shapes[$i]->href = $what; break; case 'extrahtml': $this->shapes[$i]->extrahtml = $what; break; } $count++; } } return $count; } // Return the imagemap as an HTML client-side imagemap for inclusion in a page function asHTML() { $html = 'name !== '') { $html .= ' name="' . $this->name . '"'; } $html .= ">\n"; foreach ($this->shapes as $shape) { $html .= $shape->asHTML() . "\n"; $html .= "\n"; } $html .= "\n"; return $html; } function subJSON($namefilter = '', $reverseorder = false) { $json = ''; $preg = '/' . $namefilter . '/'; foreach ($this->shapes as $shape) { if (($namefilter === '') || (1 === preg_match($preg, $shape->name))) { if ($reverseorder === true) { $json = $shape->asJSON() . ",\n" . $json; } else { $json .= $shape->asJSON() . ",\n"; } } } $json = rtrim($json, "\n, "); $json .= "\n"; return $json; } // return HTML for a subset of the map, specified by the filter string // (suppose you want some partof your UI to have precedence over another part // - the imagemap is checked from top-to-bottom in the HTML) // - skipnolinks -> in normal HTML output, we don't need areas for things with no href function subHTML($namefilter = '', $reverseorder = false, $skipnolinks = false) { $html = ''; $l = strlen($namefilter); foreach ($this->shapes as $shape) { if (($namefilter === '') || (strstr($shape->name, $namefilter) !== false)) { if ((false === $skipnolinks) || ($shape->href !== '') || ($shape->extrahtml !== '')) { if ($reverseorder === true) { $html = $shape->asHTML() . "\n" . $html; } else { $html .= $shape->asHTML() . "\n"; } } } } return $html; } function exactHTML($name = '', $reverseorder = false, $skipnolinks = false) { $html = ''; $shape = $this->shapes[$name]; if (true === isset($shape)) { if ((false === $skipnolinks) || ($shape->href !== '') || ($shape->extrahtml !== '')) { if ($reverseorder === true) { $html = $shape->asHTML() . "\n" . $html; } else { $html .= $shape->asHTML() . "\n"; } } } return $html; } } // vim:ts=4:sw=4: ?>