| [ Index ] |
|
Code source de phpMyVisites 2.3 |
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 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
| Généré le : Mon Nov 26 14:10:01 2007 | par Balluche grâce à PHPXref 0.7 |
|