<?php
/************************************************************************
* *
* Copyright (C) 2001 Stuart Reeves *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* The GNU General Public License is available from: *
* http://www.gnu.org/copyleft/gpl.html *
* *
************************************************************************/
/* Stuart's lns (lame node system) */
define(LINKS_MATCH, "|<a.+>(.*)</a>|U");
define(TWO_M_PI, 2 * M_PI);
define(FONT_ID, 2);
define(MSEC_IN_SEC, 1000000);
define(NODE_POS_DEV, 50);
/* The $mapdata array holds all the nodes and their associated links in place. The nodes are
* ordered in terms of the number of node links they have, and then placed on the image
* accordingly. */
class NodeMap
{
var $mapdata;
// Constructor
function NodeMap(){
$this->mapdata = array();
}
function getMapdata() {
return $this->mapdata;
}
function createNodeGraph($host, $user, $passwd, $db, $table) {
// Get a list of the distinct nodenames
$query = "SELECT DISTINCT nodename FROM $table WHERE link = '' AND protected != 't'";
$link = mysql_connect($host, $user, $passwd);
$dbselect = mysql_select_db($db, $link);
$dbqueryNodenames = mysql_query($query, $link);
$n = 0; // Counter for our array
/* Each node has the following data attached:
* nodename -- the name of the actual node
* links -- an array of the links to other nodes it has
* x -- x location it has been plotted to
* y -- y location it has been plotted to
* x_linkpt -- x location point to link a line to
* y_linkpt -- y location point to link a line to
*/
// Go through each distinct nodename
while ($nodenameList = mysql_fetch_object($dbqueryNodenames)) {
// Get all the links in this particular node's writeups
$query = "SELECT text FROM $table
WHERE nodename = '$nodenameList->nodename'";
$dbqueryTextbodies = mysql_query($query, $link);
$linksList = array();
if (mysql_num_rows($dbqueryTextbodies) < 1)
echo "Num rows less than 1, nodename = " . $nodenameList->nodename;
while ($textList = mysql_fetch_object($dbqueryTextbodies)) {
preg_match_all(LINKS_MATCH, $textList->text, $links);
$linksList = array_merge($links[1], $linksList);
}
$this->mapdata[$n++] = array("nodename" => $nodenameList->nodename,
"links" => $linksList,
"x" => 0,
"y" => 0,
"x_linkpt" => 0,
"y_linkpt" => 0);
}
mysql_close($link);
/* This is the compare function for the sort method used, and is created to sort the array
* based on the number of links a particular node contains. */
function cmp ($a, $b) {
if (sizeof($b["links"]) == sizeof($a["links"]))
return (0);
else
return (sizeof($b["links"]) > sizeof($a["links"])) ? 1 : -1;
}
usort($this->mapdata, "cmp");
}
/* Creates the nodemap PNG image and the nodemap imagemap file.
*
* Args: $args (array) - settings for picture generation (width, height, step, spacing
* and index size)
* $path (string) - path to place generated picture and imagemap files in
*
* Returns: true (boolean) - succeeded to create PNG and imagemap files
* false (boolean) - failed to create one or both files */
function createNodeMapImage($args, $path) {
$wid = $args[0];
$hgt = $args[1];
$step = $args[2];
$spacing = $args[3];
$ind_size = $args[4];
$imagemap = "base referer\n"; // The imagemap data text file
// Create the image space
$img = ImageCreate($wid, $hgt);
$bgcolour = ImageColorAllocate($img, 255, 255, 255);
$textcolour = ImageColorAllocate($img, 0, 0, 0);
$rectcolour = ImageColorAllocate($img, 255, 0, 0);
$linecolour = ImageColorAllocate($img, 0, 0, 255);
// Make sure that the maximum radius does not exceed the average length
$max_radius = ($wid + $hgt) / 4;
$theta = 0;
$i = 0; // counter for nodes
// Make the delta-theta step the maximum radius divided by the number of nodes
$radius_step = $max_radius;
if ($n > 0)
$radius_step /= $n;
// Make sure the elements in the centre are adequately separated
$radius_offset = 10;
// Put the starting node in the centre
$x_offset = $wid / 2;
$y_offset = $hgt / 2;
Util::reseed();
// First pass, create the text and associated boxes
reset($this->mapdata);
foreach ($this->mapdata as $node) {
$ls = sizeof($node["links"]);
/* The algorithm for drawing the nodes starts from the centre and spirals outwards. The
* step along the radius is increased and then multiplied by the number of links to
* ensure that those at the centre are widely spaced. The extra factor of radius offset
* adds to this. */
if ($ls > 0)
$radius += $radius_step;
else {
$ls = 1;
$radius = $max_radius;
}
// Randomise the plotting to make it more interesting
$x_rand = rand(-NODE_POS_DEV, NODE_POS_DEV) * ($ls * $spacing);
$y_rand = rand(-NODE_POS_DEV, NODE_POS_DEV) * ($ls * $spacing);
$x = $radius * cos($theta) + $x_offset + $x_rand;
$y = $radius * sin($theta) + $y_offset + $y_rand;
$len = strlen($node["nodename"]);
$t = ($ind_size + $len) / 2;
$rect_x1 = (int)($x - $t);
$rect_y1 = (int)($y - $t);
$rect_x2 = (int)($x + $t);
$rect_y2 = (int)($y + $t);
ImageFilledRectangle($img, $rect_x1, $rect_y1, $rect_x2, $rect_y2, $rectcolour);
// Append the imagemap data text for a link for each index shape
$conv_nodename = str_replace(array(">", "<", "'", """, "&"),
array(">", "<", "'", "\"", "&"),
$node["nodename"]);
$link_nodename = str_replace(" ", "%20", $conv_nodename);
$imagemap .= "rect ../index.php?node=" . $link_nodename .
" $rect_x1,$rect_y1 $rect_x2,$rect_y2\n";
ImageString($img, FONT_ID, $x, $y, $conv_nodename, $textcolour);
// Store the location of the node for linking up later
$this->mapdata[$i]["x"] = $x;
$this->mapdata[$i]["y"] = $y;
$this->mapdata[$i]["x_linkpt"] = ($rect_x1 + $rect_x2) / 2;
$this->mapdata[$i]["y_linkpt"] = ($rect_y1 + $rect_y2) / 2;
++$i;
($theta < TWO_M_PI) ? $theta += $step : $theta = 0;
}
// Second pass, join the nodes up
reset($this->mapdata);
foreach ($this->mapdata as $node) {
foreach ($node["links"] as $link) {
$i = 0;
while ($i < sizeof($this->mapdata) && $this->mapdata[$i]["nodename"] != $link)
++$i;
if ($i < sizeof($this->mapdata)) {
ImageLine ($img,
$node["x_linkpt"],
$node["y_linkpt"],
$this->mapdata[$i]["x_linkpt"],
$this->mapdata[$i]["y_linkpt"],
$linecolour);
}
}
}
// Create the PNG image and imagemap files
$fp1 = fopen($path . "/image.map", "w+");
$fp2 = fopen($path . "/image.png", "w+");
if ($fp1 && $fp2) {
fwrite($fp1, $imagemap);
ImagePNG($img, $path . "/image.png");
fclose($fp1);
fclose($fp2);
return true;
} else
return false;
}
}
?>