User:Dschwen/Dynamap
Appearance
<?php
# Dynamap WikiMedia extension
#
# introduces
# * <dynamap></dynamap> Tags
# * Special:DynamapConstants
#
# Note: The output is not interpreted as WikiText but directly
# included in the HTML output. So Wiki markup is not supported.
# To activate the extension, include it from your LocalSettings.php
# with: include("extensions/ExampleExt.php");
if (!defined('MEDIAWIKI')) die();
$wgExtensionFunctions[] = "wfDynamapExtension";
function wfDynamapExtension() {
global $wgParser,$IP, $wgMessageCache;
require_once( "$IP/includes/SpecialPage.php" );
# register the extension with the WikiText parser
# the first parameter is the name of the new tag.
# In this case it defines the tag <example> ... </example>
# the second parameter is the callback function for
# processing the text between the tags
$wgParser->setHook( "dynamap", "renderDynamap" );
# register the dynamap constant list special page
$wgMessageCache->addMessages(array('dynamapconstants' => 'Dynamap Constants'));
class DynamapSpecialPage extends SpecialPage {
function DynamapSpecialPage() {
SpecialPage::SpecialPage( 'DynamapConstants' );
#$this->includable( true );
}
function execute( $par = null ) {
global $wgOut, $wgRequest;
require_once( "maps.inc" );
$out = "<h1>Dynamap Extension Constants</h1><h2>List of available Map Sources</h2><table border='1'>";
foreach ($maplist as $key => $value ) {
$out .= "<tr><td>$key</td><td>$value[1]</td></tr>\n";
}
$out .= "</table><h2>List of predefined Regions</h2>";
//$wgOut->addHTML( $out );
}
}
SpecialPage::addPage( new DynamapSpecialPage );
}
function dynamapError($text)
{
return '<pre>'.$text."</pre>";
}
function dynamapFindTemplate($haystack,$needle,&$offset)
{
$length=strlen($needle);
$pos1=strpos(trim($haystack),$needle,$offset);
if(!($pos1===false))
{
$pos2=strpos($haystack,'}}',$pos1);
if(!($pos2===false))
{
$offset=$pos2;
return trim(substr($haystack,$pos1+$length,$pos2-$pos1-$length));
}
}
return '';
}
function dynamapProject($x,$y,&$px,&$py,$w,$h,$minlat,$minlong,$maxlat,$maxlong)
{
$px=(($x-$minlong)/($maxlong-$minlong)*$w);
$py=$h-(($y-$minlat)/($maxlat-$minlat)*$h);
}
function dynamapGetRawText($title,$cur)
{
$mtitle=Title::newFromURL($title);
$dbr =& wfGetDB( DB_SLAVE );
$t = $dbr->strencode( $mtitle->getDBKey() );
$ns = $mtitle->getNamespace();
if($ns == NS_MEDIAWIKI) return wfMsg($t);
else {
$sql = "SELECT cur_id as id,cur_timestamp as timestamp,cur_user as user,cur_user_text as user_text," .
"cur_restrictions as restrictions,cur_comment as comment,cur_text as text FROM $cur " .
"WHERE cur_namespace=$ns AND cur_title='$t'";
$res = $dbr->query( $sql, $fname );
if( $s = $dbr->fetchObject( $res ) ) return Article::getRevisionText( $s, "" );
else return '';
}
}
function renderDynamap( $input, $argv="" )
{
# $argv is an array containing any arguments passed to the extension like <example argument="foo" bar>..
$w=0; $h=0;
$maparea="";
$data=false;
$css="text {font-family:Verdana; font-size:12px; fill:black;}\n";
$alt_text="Map showing: ";
$paths="";
$outfilenamebase="images/dynamap/".md5($input);
$dbr =& wfGetDB( DB_SLAVE );
extract( $dbr->tableNames( 'cur' ) );
$level=1; $color="black"; $radius=3; $stroke=1; $textcolor="black";
$lines = explode("\n", $input);
foreach($lines as $line)
{
if($line[0]!='#')
{
$command = explode(":", $line);
$output.=$command[0];
if(!$data) switch($command[0])
{
case "image": $values=explode(",",$command[1]);
$w=intval($values[0]);
$h=intval($values[1]);
break;
case "area" : $maparea=$command[1];
list($minlat,$minlong,$maxlat,$maxlong)=explode(",",$command[1]);
if($minlat>$maxlat) list($maxlat,$minlat) = array($minlat,$maxlat);
if($minlong>$maxlong) list($maxlong,$minlong) = array($minlong,$maxlong);
$ah=abs($maxlat-$minlat);
$aw=abs($maxlong-$minlong);
//return "minlat=$minlat,minlong=$minlong,maxlat=$maxlat,maxlong=$maxlong, ah=$ah,aw=$aw, maparea=$maparea";
break;
case "start": if($maparea=="" || $ah==0) return dynamapError("No propper area:latmin,longmin,latmax,longmax command found!");
if($w!=0 && $h==0)
{
$h=intval(($ah/$aw)*floatval($w));
}
if($w==0 || $h==0) return dynamapError("No propper image:w,h or image:w command found!");
$data=true;
//return "$w x $h";
break;
}
else switch($command[0])
{
case "level": $level=intval($command[1]);
break;
case "color": $color=$command[1];
break;
case "radius":$radius=floatval($command[1]);
break;
case "stroke":$stroke=floatval($command[1]);
break;
case "layer": $dirtylayer=trim($command[1]);
$layer=str_replace(array('"','/','.','%','\\','?','*','!','(',')','{','}'),'',$dirtylayer);
# check if raw map exists, otherwise create
$map_raw_cache="images/dynamap/".md5($maparea.'_'.$w.'x'.$h.$layer.$level)."raw.svg";
if ( is_readable($map_raw_cache) )
{
$paths.=file_get_contents($map_raw_cache);
}
else
{
$command="extensions/dynamap/drawmap ".escapeshellcmd($maparea)." $w,$h $level $layer";
//exec("$command 2>&1", $out1, $err);
exec("$command", $out1, $err);
$out2=implode("\n",$out1);
//file_put_contents($map_raw_cache,$out2);
$res=fopen($map_raw_cache,'w');
fwrite($res,$out2);
fclose($res);
$paths.=$out2;
}
$css.=" path.$layer {fill: gray; stroke: $color; stroke-width:$stroke }\n";
break;
case "poly": $text=dynamapGetRawText(trim($command[1]),$cur);
$alt_text.=$text.', ';
$mtitle=Title::newFromURL(trim($command[1]));
$link=$mtitle->getDBKey();
$pos=0;
$coords=explode('|',dynamapFindTemplate($text,'{{geopoly',$pos));
$mode=trim(array_shift($coords));
$px=0; $py=0; $first=true;
$paths.="<a xlink:href=\"/index.php/$link\">";
while(count($coords)>=4)
{
$y=trim(array_shift($coords));
if(strtoupper(trim(array_shift($coords)))=='S') $y*=-1;
$x=trim(array_shift($coords));
if(strtoupper(trim(array_shift($coords)))=='W') $x*=-1;
dynamapProject($x,$y,$px,$py,$w,$h,$minlat,$minlong,$maxlat,$maxlong);
if($first)
{
$paths.="<path d=\"M $px $py ";
$first=false;
}
else $paths.="L $px $py ";
}
if(!$first) $paths.="\" style=\"stroke:$color; fill:none; stroke-width:$stroke\" />\n";
$paths.="</a>\n";
break;
case "point": $text=dynamapGetRawText(trim($command[1]),$cur);
$alt_text.=$text.' ';
$mtitle=Title::newFromURL(trim($command[1]));
$link=$mtitle->getDBKey();
$pos=0;
$coords=explode('|',dynamapFindTemplate($text,'{{coor',$pos));
$mode=trim(array_shift($coords));
$px=0; $py=0; $first=true;
while(count($coords)>=4)
{
$y=trim(array_shift($coords));
if(strtoupper(trim(array_shift($coords)))=='S') $y*=-1;
$x=trim(array_shift($coords));
if(strtoupper(trim(array_shift($coords)))=='W') $x*=-1;
dynamapProject($x,$y,$px,$py,$w,$h,$minlat,$minlong,$maxlat,$maxlong);
$paths.="<a xlink:href=\"/index.php/$link\">";
$paths.="<circle cx=\"$px\" cy=\"$py\" r=\"$radius\" style=\"fill:$color; stroke:none\" />\n";
$px+=$radius; $py-=$radius;
$paths.="<text x=\"$px\" y=\"$py\" style=\"fill:$textcolor; stroke:none\" >".trim($command[1])."</text></a>\n";
}
break;
}
}
}
$res=fopen($outfilenamebase.'.svg','w');
$buffer = <<<EOH1
<?xml version="1.0" encoding="iso-8859-1" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="$w" height="$h">
<defs>
<style type="text/css">
<![CDATA[
path.level0 {fill: #9EC7F3; stroke: #9EC7F3; stroke-width:3 }
path.level1 {fill: #FFFFD0; stroke: #4090D0; stroke-width:1 }
path.level2 {fill: #9EC7F3; stroke: #4090D0; stroke-width:1 }
path.level3 {fill: #FFFFD0; stroke: #4090D0; stroke-width:1 }
path.level4 {fill: #9EC7F3; stroke: #4090D0; stroke-width:1 }
$css
]]>
</style>
</defs>
<path class="level0" d="M 0 0 L $w 0 L $w $h L 0 $h L 0 0" />
EOH1;
fwrite($res,$buffer);
fwrite($res,$paths);
fwrite($res,"</svg>\n");
fclose($res);
exec("rsvg $outfilenamebase.svg $outfilenamebase.png");
# return '<img src="/'.$outfilenamebase.'.png"><br><a href="/wiki/'.$outfilenamebase.'.svg">SVG version with clickable links</a>';
return '<object data="/'.$outfilenamebase.'.svg" width="'.$w.'" height="'.$h.'" type="image/svg+xml"><img src="/'.$outfilenamebase.'.png" width="'.$w.'" height="'.$h.'" border="0"><br><a href="/'.$outfilenamebase.'.svg">SVG version with clickable links</a></object>';
}
?>