[ Index ]
 

Code source de phpMyVisites 2.3

Accédez au Source d'autres logiciels libres

Classes | Fonctions | Variables | Constantes | Tables

title

Body

[fermer]

/plugins/clickheat/libs/classes/ -> Heatmap.class.php (source)

   1  <?php
   2  /**
   3   * ClickHeat : Classe de génération des cartes / Maps generation class
   4   * 
   5   * Cette classe est VOLONTAIREMENT écrite pour PHP 4
   6   * This class is VOLUNTARILY written for PHP 4
   7   * 
   8   * @author Yvan Taviaud - LabsMedia - www.labsmedia.com
   9   * @since 08/05/2007
  10  **/
  11  
  12  class Heatmap
  13  {
  14      /** @var integer $memory Limite de mémoire / Memory limit */
  15      var $memory = 8388608;
  16      /** @var integer $step Groupement des pixels / Pixels grouping */
  17      var $step = 5;
  18      /** @var integer $startStep */
  19      var $startStep;
  20      /** @var integer $dot Taille des points de chaleur / Heat dots size */
  21      var $dot = 19;
  22      /** @var boolean $heatmap Affichage sous forme de carte de température / Show as heatmap */
  23      var $heatmap = true;
  24      /** @var boolean $palette Correctif pour la gestion de palette (cas des carrés rouges) / Correction for palette (in case of red squares) */
  25      var $palette = false;
  26      /** @var boolean $rainbow Affichage de l'arc-en-ciel / Show rainbow */
  27      var $rainbow = true;
  28      /** @var boolean $copyleft Affichage du copyleft / Show copyleft */
  29      var $copyleft = true;
  30      /** @var integer $width Largeur de l'image / Image width */
  31      var $width;
  32      /** @var integer $height Hauteur de l'image / Image height */
  33      var $height;
  34      /** @var integer $maxClicks Nombre de clics maximum (sur 1 pixel) / Maximum clicks (on 1 pixel) */
  35      var $maxClicks;
  36      /** @var integer $maxY Hauteur maximale (point le plus bas) / Maximum height (lowest point) */
  37      var $maxY;
  38      /** @var resource $image Ressource image / Image resource */
  39      var $image;
  40      /** @var string $file Nom du fichier image (incluant le %d) / Image filename (including %d) */
  41      var $file;
  42      /** @var string $path Chemin du fichier image / Image path */
  43      var $path;
  44      /** @var string $cache Chemin du cache / Cache path */
  45      var $cache;
  46      /** @var string $error Erreur / Error */
  47      var $error = '';
  48      /** @var array $__colors Niveaux de dégradé (de 0 à 127) / Gradient levels (from 0 to 127) */
  49      var $__colors = array(50, 70, 90, 110, 120);
  50      /** @var integer $__low Niveau minimal de couleur RVB / Lower RGB level of color */
  51      var $__low = 0;
  52      /** @var integer $__high Niveau maximal de couleur RVB / Higher RGB level of color */
  53      var $__high = 255;
  54      /** @var integer $__grey Niveau du gris (couleur du 0 clic) / Grey level (color of no-click) */
  55      var $__grey = 240;
  56  
  57  	function Heatmap() {}
  58  
  59  	function generate($width, $height = 0)
  60      {
  61          /** First check paths */
  62          $this->path = rtrim($this->path, '/').'/';
  63          $this->cache = rtrim($this->cache, '/').'/';
  64          $this->file = str_replace('/', '', $this->file);
  65          if (!is_dir($this->path) || $this->path === '/')
  66          {
  67              return $this->raiseError('path = "'.$this->path.'" is not a directory or is "/"');
  68          }
  69          if (!is_dir($this->cache) || $this->cache === '/')
  70          {
  71              return $this->raiseError('cache = "'.$this->cache.'" is not a directory or is "/"');
  72          }
  73          if (strpos($this->file, '%d') === false)
  74          {
  75              return $this->raiseError('file = "'.$this->file.'" doesn\'t include a \'%d\' for image number');
  76          }
  77  
  78          $files = array('filenames' => array(), 'absolutes' => array()); /** Generated files list */
  79          $this->startStep = (int) floor(($this->step - 1) / 2);
  80          $nbOfImages = 1; /** Will be modified after the first image is created */
  81          $this->maxClicks = 1; /** Must not be zero for divisions */
  82          $this->maxY = 0;
  83          /**
  84           * Memory consumption :
  85           * imagecreate    : about 200,000 + 5 * $width * $height bytes
  86           * dots            : about 6,000 + 360 * DOT_WIDTH bytes each (100 dots)
  87           * imagepng        : about 4 * $width * $height bytes
  88           * So a rough idea of the memory is 10 * $width * $height + 500,000 (2 images) + 100 * (DOT_WIDTH * 360 + 6000)
  89          **/
  90          $this->width = (int) abs($width);
  91          if ($this->width === 0)
  92          {
  93              return $this->raiseError('Width can\'t be 0');
  94          }
  95          $height = (int) abs($height);
  96          if ($height === 0)
  97          {
  98              /** Calculating height from memory consumption, and add a 100% security margin : 10 => 20 */
  99              $this->height = floor(($this->memory - 500000 - 100 * ($this->dot * 360 + 6000)) / (20 * $width));
 100              /** Limit height to 1000px max, with a modulo of 10 */
 101              $this->height = (int) max(100, min(1000, $this->height - $this->height % 10));
 102          }
 103          else
 104          {
 105              /** Force height */
 106              $this->height = $height;
 107          }
 108  
 109          /** Startup tasks */
 110          if ($this->startDrawing() === false)
 111          {
 112              return false;
 113          }
 114          $files['width'] = $this->width;
 115          $files['height'] = $this->height;
 116          for ($image = 0; $image < $nbOfImages; $image++)
 117          {
 118              /** Image creation */
 119              $this->image = imagecreatetruecolor($this->width, $this->height);
 120              if ($this->heatmap === false)
 121              {
 122                  $grey = imagecolorallocate($this->image, $this->__grey, $this->__grey, $this->__grey);
 123                  imagefill($this->image, 0, 0, $grey);
 124              }
 125              else
 126              {
 127                  /** Image is filled in the color "0", which means 0 click */
 128                  imagefill($this->image, 0, 0, 0);
 129              }
 130  
 131              /** Draw next pixels for this image */
 132              if ($this->drawPixels($image) === false)
 133              {
 134                  return false;
 135              }
 136              if ($image === 0)
 137              {
 138                  if ($this->maxY === 0)
 139                  {
 140                      if (defined('LANG_ERROR_DATA') === true)
 141                      {
 142                          return $this->raiseError(LANG_ERROR_DATA);
 143                      }
 144                      else
 145                      {
 146                          $this->maxY = 1;
 147                      }
 148                  }
 149                  $nbOfImages = (int) ceil($this->maxY / $this->height);
 150                  $files['count'] = $nbOfImages;
 151              }
 152  
 153              if ($this->heatmap === true)
 154              {
 155                  imagepng($this->image, sprintf($this->cache.$this->file.'_temp', $image));
 156              }
 157              else
 158              {
 159                  /** "No clicks under this line" message */
 160                  if ($image === $nbOfImages - 1 && defined('LANG_NO_CLICK_BELOW') === true)
 161                  {
 162                      $black = imagecolorallocate($this->image, 0, 0, 0);
 163                      imageline($this->image, 0, $this->height - 1, $this->width, $this->height - 1, $black);
 164                      imagestring($this->image, 1, 1, $this->height - 9, LANG_NO_CLICK_BELOW, $black);
 165                  }
 166                  imagepng($this->image, sprintf($this->path.$this->file, $image));
 167              }
 168              imagedestroy($this->image);
 169  
 170              /** Result files */
 171              $files['filenames'][] = sprintf($this->file, $image);
 172              $files['absolutes'][] = sprintf($this->path.$this->file, $image);
 173          }
 174          /** End tasks */
 175          if ($this->finishDrawing() === false)
 176          {
 177              return false;
 178          }
 179  
 180          if ($this->heatmap === false)
 181          {
 182              return $files;
 183          }
 184          /** Now, our image is a direct representation of the clicks on each pixel, so create some fuzzy dots to put a nice blur effect if user asked for a heatmap */
 185          for ($i = 0; $i < 128; $i++)
 186          {
 187              $dots[$i] = imagecreatetruecolor($this->dot, $this->dot);
 188              imagealphablending($dots[$i], false);
 189          }
 190          for ($x = 0; $x < $this->dot; $x++)
 191          {
 192              for ($y = 0; $y < $this->dot; $y++)
 193              {
 194                  $sinX = sin($x * pi() / $this->dot);
 195                  $sinY = sin($y * pi() / $this->dot);
 196                  for ($i = 0; $i < 128; $i++)
 197                  {
 198                      $alpha = 127 - $i * $sinX * $sinY * $sinX * $sinY;
 199                      imagesetpixel($dots[$i], $x, $y, ((int) $alpha) * 16777216);
 200                  }
 201              }
 202          }
 203  
 204          /**
 205               * Colors creation :
 206               * grey    => deep blue (rgB)    => light blue (rGB)    => green (rGb)        => yellow (RGb)        => red (Rgb)
 207               * 0       $this->__colors[0]       $this->__colors[1]       $this->__colors[2]       $this->__colors[3]       128
 208              **/
 209          sort($this->__colors);
 210          $colors = array();
 211          for ($i = 0; $i < 128; $i++)
 212          {
 213              /** Red */
 214              if ($i < $this->__colors[0])
 215              {
 216                  $colors[$i][0] = $this->__grey + ($this->__low - $this->__grey) * $i / $this->__colors[0];
 217              }
 218              elseif ($i < $this->__colors[2])
 219              {
 220                  $colors[$i][0] = $this->__low;
 221              }
 222              elseif ($i < $this->__colors[3])
 223              {
 224                  $colors[$i][0] = $this->__low + ($this->__high - $this->__low) * ($i - $this->__colors[2]) / ($this->__colors[3] - $this->__colors[2]);
 225              }
 226              else
 227              {
 228                  $colors[$i][0] = $this->__high;
 229              }
 230              /** Green */
 231              if ($i < $this->__colors[0])
 232              {
 233                  $colors[$i][1] = $this->__grey + ($this->__low - $this->__grey) * $i / $this->__colors[0];
 234              }
 235              elseif ($i < $this->__colors[1])
 236              {
 237                  $colors[$i][1] = $this->__low + ($this->__high - $this->__low) * ($i - $this->__colors[0]) / ($this->__colors[1] - $this->__colors[0]);
 238              }
 239              elseif ($i < $this->__colors[3])
 240              {
 241                  $colors[$i][1] = $this->__high;
 242              }
 243              else
 244              {
 245                  $colors[$i][1] = $this->__high - ($this->__high - $this->__low) * ($i - $this->__colors[3]) / (127 - $this->__colors[3]);
 246              }
 247              /** Blue */
 248              if ($i < $this->__colors[0])
 249              {
 250                  $colors[$i][2] = $this->__grey + ($this->__high - $this->__grey) * $i / $this->__colors[0];
 251              }
 252              elseif ($i < $this->__colors[1])
 253              {
 254                  $colors[$i][2] = $this->__high;
 255              }
 256              elseif ($i < $this->__colors[2])
 257              {
 258                  $colors[$i][2] = $this->__high - ($this->__high - $this->__low) * ($i - $this->__colors[1]) / ($this->__colors[2] - $this->__colors[1]);
 259              }
 260              else
 261              {
 262                  $colors[$i][2] = $this->__low;
 263              }
 264          }
 265          for ($image = 0; $image < $nbOfImages; $image++)
 266          {
 267              $img = imagecreatetruecolor($this->width, $this->height);
 268              /** Allocate white, so that this will fill the newly created image */
 269              $white = imagecolorallocate($img, 255, 255, 255);
 270              imagefill($img, 0, 0, $white);
 271              imagealphablending($img, true);
 272  
 273              $imgSrc = @imagecreatefrompng(sprintf($this->cache.$this->file.'_temp', $image));
 274              @unlink(sprintf($this->cache.$this->file.'_temp', $image));
 275              if ($imgSrc === false)
 276              {
 277                  return $this->raiseError('::MEMORY_OVERFLOW::');
 278              }
 279              for ($x = $this->startStep; $x < $this->width; $x += $this->step)
 280              {
 281                  for ($y = $this->startStep; $y < $this->height; $y += $this->step)
 282                  {
 283                      $dot = (int) ceil(imagecolorat($imgSrc, $x, $y) / $this->maxClicks * 100);
 284                      if ($dot !== 0)
 285                      {
 286                          imagecopy($img, $dots[$dot], ceil($x - $this->dot / 2), ceil($y - $this->dot / 2), 0, 0, $this->dot, $this->dot);
 287                      }
 288                  }
 289              }
 290              /** Destroy image source */
 291              imagedestroy($imgSrc);
 292  
 293              /** Rainbow */
 294              if ($image === 0 && $this->rainbow === true)
 295              {
 296                  for ($i = 1; $i < 128; $i += 2)
 297                  {
 298                      /** Erase previous alpha channel so that clicks don't change the heatmap by combining their alpha */
 299                      imageline($img, ceil($i/2), 0, ceil($i/2), 10, 16777215);
 300                      /** Then put our alpha */
 301                      imageline($img, ceil($i/2), 0, ceil($i/2), 10, (127 - $i) * 16777216);
 302                  }
 303              }
 304  
 305              /** Some version of imagetruecolortopalette() don't transform alpha value to non alpha */
 306              if ($this->palette === true)
 307              {
 308                  for ($x = 0; $x < $this->width; $x++)
 309                  {
 310                      for ($y = 0; $y < $this->height; $y++)
 311                      {
 312                          /** Get Alpha value (0->127) and transform it to red (divide color by 16777216 and multiply by 65536 * 2 (red is 0->255), so divide it by 128) */
 313                          imagesetpixel($img, $x, $y, (imagecolorat($img, $x, $y) & 0x7F000000) / 128);
 314                      }
 315                  }
 316              }
 317  
 318              /** Change true color image to palette then change palette colors */
 319              imagetruecolortopalette($img, false, 127);
 320              for ($i = 0, $max = imagecolorstotal($img); $i < $max; $i++)
 321              {
 322                  $color = imagecolorsforindex($img, $i);
 323                  imagecolorset($img, $i, $colors[floor(127 - $color['red'] / 2)][0], $colors[floor(127 - $color['red'] / 2)][1], $colors[floor(127 - $color['red'] / 2)][2]);
 324              }
 325  
 326              $grey = imagecolorallocate($img, $this->__grey, $this->__grey, $this->__grey);
 327              $gray = imagecolorallocate($img, ceil($this->__grey / 2), ceil($this->__grey / 2), ceil($this->__grey / 2));
 328              $white = imagecolorallocate($img, 255, 255, 255);
 329              $black = imagecolorallocate($img, 0, 0, 0);
 330  
 331              /** maxClicks */
 332              if ($image === 0 && $this->rainbow === true)
 333              {
 334                  imagerectangle($img, 0, 0, 65, 11, $white);
 335                  imagefilledrectangle($img, 0, 11, 65, 18, $white);
 336                  imagestring($img, 1, 0, 11, '0', $black);
 337                  $right = 66 - strlen($this->maxClicks) * 5;
 338                  imagestring($img, 1, $right, 11, $this->maxClicks, $black);
 339                  imagestring($img, 1, floor($right / 2) - 12, 11, 'clicks', $black);
 340              }
 341  
 342              if ($image === $nbOfImages - 1)
 343              {
 344                  /** "No clicks under this line" message */
 345                  if (defined('LANG_NO_CLICK_BELOW') === true)
 346                  {
 347                      imageline($img, 0, $this->height - 1, $this->width, $this->height - 1, $gray);
 348                      imagestring($img, 1, 1, $this->height - 9, LANG_NO_CLICK_BELOW, $gray);
 349                  }
 350                  /** Copyleft */
 351                  if ($this->copyleft === true)
 352                  {
 353                      imagestring($img, 1, $this->width - 160, $this->height - 9, 'Open source heatmap by ClickHeat', $grey);
 354                      imagestring($img, 1, $this->width - 161, $this->height - 9, 'Open source heatmap by ClickHeat', $gray);
 355                  }
 356              }
 357  
 358              /** Save PNG file */
 359              imagepng($img, sprintf($this->path.$this->file, $image));
 360              imagedestroy($img);
 361          }
 362          for ($i = 0; $i < 100; $i++)
 363          {
 364              imagedestroy($dots[$i]);
 365          }
 366          return $files;
 367      }
 368  
 369      /**
 370       * Retourne une erreur / Returns an error
 371       *
 372       * @param string $error
 373      **/
 374  	function raiseError($error)
 375      {
 376          $this->error = $error;
 377          return false;
 378      }
 379  }
 380  ?>


Généré le : Mon Nov 26 14:10:01 2007 par Balluche grâce à PHPXref 0.7
  Clicky Web Analytics