add osm plugin
parent
78737cbfbf
commit
9f56a417a1
|
@ -0,0 +1,682 @@
|
||||||
|
#!/usr/bin/perl
|
||||||
|
# Copyright 2011 Blars Blarson
|
||||||
|
# Released under GPL version 2
|
||||||
|
|
||||||
|
package IkiWiki::Plugin::osm;
|
||||||
|
use utf8;
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use IkiWiki 3.0;
|
||||||
|
|
||||||
|
sub import {
|
||||||
|
add_underlay("javascript");
|
||||||
|
hook(type => "getsetup", id => "osm", call => \&getsetup);
|
||||||
|
hook(type => "format", id => "osm", call => \&format);
|
||||||
|
hook(type => "preprocess", id => "osm", call => \&preprocess); # backward compatibility
|
||||||
|
hook(type => "preprocess", id => "waypoint", call => \&process_waypoint);
|
||||||
|
hook(type => "savestate", id => "waypoint", call => \&savestate);
|
||||||
|
hook(type => "cgi", id => "osm", call => \&cgi);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub getsetup () {
|
||||||
|
return
|
||||||
|
plugin => {
|
||||||
|
safe => 1,
|
||||||
|
rebuild => 1,
|
||||||
|
section => "special-purpose",
|
||||||
|
},
|
||||||
|
osm_default_zoom => {
|
||||||
|
type => "integer",
|
||||||
|
example => "15",
|
||||||
|
description => "the default zoon when you click on the map link",
|
||||||
|
safe => 1,
|
||||||
|
rebuild => 1,
|
||||||
|
},
|
||||||
|
osm_default_icon => {
|
||||||
|
type => "string",
|
||||||
|
example => "img/osm.png",
|
||||||
|
description => "the icon showed on links and on the main map",
|
||||||
|
safe => 0,
|
||||||
|
rebuild => 1,
|
||||||
|
},
|
||||||
|
osm_alt => {
|
||||||
|
type => "string",
|
||||||
|
example => "",
|
||||||
|
description => "the alt tag of links, defaults to empty",
|
||||||
|
safe => 0,
|
||||||
|
rebuild => 1,
|
||||||
|
},
|
||||||
|
osm_format => {
|
||||||
|
type => "string",
|
||||||
|
example => "KML",
|
||||||
|
description => "the output format for waypoints, can be KML, GeoJSON or CSV (one or many, comma-separated)",
|
||||||
|
safe => 1,
|
||||||
|
rebuild => 1,
|
||||||
|
},
|
||||||
|
osm_tag_default_icon => {
|
||||||
|
type => "string",
|
||||||
|
example => "icon.png",
|
||||||
|
description => "the icon attached to a tag so that pages tagged with that tag will have that icon on the map",
|
||||||
|
safe => 0,
|
||||||
|
rebuild => 1,
|
||||||
|
},
|
||||||
|
osm_tag_icons => {
|
||||||
|
type => "string",
|
||||||
|
example => { 'test' => '/img/test.png',
|
||||||
|
'trailer' => '/img/trailer.png' ,},
|
||||||
|
description => "tag to icon mapping, leading slash is important!",
|
||||||
|
safe => 0,
|
||||||
|
rebuild => 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
sub preprocess {
|
||||||
|
my %params=@_;
|
||||||
|
my $page = $params{'page'};
|
||||||
|
my $dest = $params{'destpage'};
|
||||||
|
my $loc = $params{'loc'}; # sanitized below
|
||||||
|
my $lat = $params{'lat'}; # sanitized below
|
||||||
|
my $lon = $params{'lon'}; # sanitized below
|
||||||
|
my $href = $params{'href'};
|
||||||
|
|
||||||
|
my $fullscreen = defined($params{'fullscreen'}); # sanitized here
|
||||||
|
my ($width, $height, $float);
|
||||||
|
if ($fullscreen) {
|
||||||
|
$height = '100%';
|
||||||
|
$width = '100%';
|
||||||
|
$float = 0;
|
||||||
|
} else {
|
||||||
|
$height = scrub($params{'height'} || "300px", $page, $dest); # sanitized here
|
||||||
|
$width = scrub($params{'width'} || "500px", $page, $dest); # sanitized here
|
||||||
|
$float = (defined($params{'right'}) && 'right') || (defined($params{'left'}) && 'left'); # sanitized here
|
||||||
|
}
|
||||||
|
my $zoom = scrub($params{'zoom'} // $config{'osm_default_zoom'} // 15, $page, $dest); # sanitized below
|
||||||
|
my $map;
|
||||||
|
if ($fullscreen) {
|
||||||
|
$map = $params{'map'} || $page;
|
||||||
|
} else {
|
||||||
|
$map = $params{'map'} || 'map';
|
||||||
|
}
|
||||||
|
$map = scrub($map, $page, $dest); # sanitized here
|
||||||
|
my $name = scrub($params{'name'} || $map, $page, $dest);
|
||||||
|
|
||||||
|
if (defined($lon) || defined($lat) || defined($loc)) {
|
||||||
|
($lon, $lat) = scrub_lonlat($loc, $lon, $lat);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($zoom !~ /^\d\d?$/ || $zoom < 2 || $zoom > 18) {
|
||||||
|
error("Bad zoom");
|
||||||
|
}
|
||||||
|
$pagestate{$page}{'osm'}{$map}{'displays'}{$name} =
|
||||||
|
{
|
||||||
|
'height' => $height,
|
||||||
|
'width' => $width,
|
||||||
|
'float' => $float,
|
||||||
|
'zoom' => $zoom,
|
||||||
|
'fullscreen' => $fullscreen,
|
||||||
|
'editable' => defined($params{'editable'}),
|
||||||
|
'lat' => $lat,
|
||||||
|
'lon' => $lon,
|
||||||
|
'href' => $href,
|
||||||
|
};
|
||||||
|
return "<div id=\"mapdiv-$name\"></div>";
|
||||||
|
}
|
||||||
|
|
||||||
|
sub process_waypoint {
|
||||||
|
my %params=@_;
|
||||||
|
my $loc = $params{'loc'}; # sanitized below
|
||||||
|
my $lat = $params{'lat'}; # sanitized below
|
||||||
|
my $lon = $params{'lon'}; # sanitized below
|
||||||
|
my $page = $params{'page'}; # not sanitized?
|
||||||
|
my $dest = $params{'destpage'}; # not sanitized?
|
||||||
|
my $hidden = defined($params{'hidden'}); # sanitized here
|
||||||
|
my ($p) = $page =~ /(?:^|\/)([^\/]+)\/?$/; # shorter page name
|
||||||
|
my $name = scrub($params{'name'} || $p, $page, $dest); # sanitized here
|
||||||
|
my $desc = scrub($params{'desc'} || '', $page, $dest); # sanitized here
|
||||||
|
my $zoom = scrub($params{'zoom'} // $config{'osm_default_zoom'} // 15, $page, $dest); # sanitized below
|
||||||
|
my $icon = $config{'osm__default_icon'} || "img/osm.png"; # sanitized: we trust $config
|
||||||
|
my $map = scrub($params{'map'} || 'map', $page, $dest); # sanitized here
|
||||||
|
my $alt = $config{'osm_alt'} ? "alt=\"$config{'osm_alt'}\"" : ''; # sanitized: we trust $config
|
||||||
|
if ($zoom !~ /^\d\d?$/ || $zoom < 2 || $zoom > 18) {
|
||||||
|
error("Bad zoom");
|
||||||
|
}
|
||||||
|
|
||||||
|
($lon, $lat) = scrub_lonlat($loc, $lon, $lat);
|
||||||
|
if (!defined($lat) || !defined($lon)) {
|
||||||
|
error("Must specify lat and lon");
|
||||||
|
}
|
||||||
|
|
||||||
|
my $tag = $params{'tag'};
|
||||||
|
if ($tag) {
|
||||||
|
if (!defined($config{'osm_tag_icons'}->{$tag})) {
|
||||||
|
error("invalid tag specified, see osm_tag_icons configuration or don't specify any");
|
||||||
|
}
|
||||||
|
$icon = $config{'osm_tag_icons'}->{$tag};
|
||||||
|
} else {
|
||||||
|
foreach my $t (keys %{$typedlinks{$page}{'tag'}}) {
|
||||||
|
if ($icon = get_tag_icon($t)) {
|
||||||
|
$tag = $t;
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
$t =~ s!/$config{'tagbase'}/!!;
|
||||||
|
if ($icon = get_tag_icon($t)) {
|
||||||
|
$tag = $t;
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$icon = "/img/unknown.png" unless $icon;
|
||||||
|
$tag = '' unless $tag;
|
||||||
|
if ($page eq $dest) {
|
||||||
|
if (!defined($config{'osm_format'}) || !$config{'osm_format'}) {
|
||||||
|
$config{'osm_format'} = 'KML';
|
||||||
|
}
|
||||||
|
my %formats = map { $_ => 1 } split(/, */, $config{'osm_format'});
|
||||||
|
if ($formats{'GeoJSON'}) {
|
||||||
|
will_render($page,$config{destdir} . "/$map/pois.json");
|
||||||
|
}
|
||||||
|
if ($formats{'CSV'}) {
|
||||||
|
will_render($page,$config{destdir} . "/$map/pois.txt");
|
||||||
|
}
|
||||||
|
if ($formats{'KML'}) {
|
||||||
|
will_render($page,$config{destdir} . "/$map/pois.kml");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
my $href = "/ikiwiki.cgi?do=osm&map=$map&lat=$lat&lon=$lon&zoom=$zoom";
|
||||||
|
if (defined($destsources{htmlpage($map)})) {
|
||||||
|
$href = urlto($map,$page) . "?lat=$lat&lon=$lon&zoom=$zoom";
|
||||||
|
}
|
||||||
|
$pagestate{$page}{'osm'}{$map}{'waypoints'}{$name} =
|
||||||
|
{
|
||||||
|
'page' => $page,
|
||||||
|
'desc' => $desc,
|
||||||
|
'icon' => $icon,
|
||||||
|
'tag' => $tag,
|
||||||
|
'lat' => $lat,
|
||||||
|
'lon' => $lon,
|
||||||
|
'href' => urlto($page,$map), # how to link back to the page from the map, not to be confused with the URL of the map itself sent to the embeded map below
|
||||||
|
};
|
||||||
|
my $output = '';
|
||||||
|
if (defined($params{'embed'})) {
|
||||||
|
$params{'href'} = $href; # propagate down to embeded
|
||||||
|
$output .= preprocess(%params);
|
||||||
|
}
|
||||||
|
if (!$hidden) {
|
||||||
|
$href =~ s!&!&!g;
|
||||||
|
$output .= "<a href=\"$href\"><img class=\"img\" src=\"$icon\" $alt /></a>";
|
||||||
|
}
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
|
# get the icon from the given tag
|
||||||
|
sub get_tag_icon($) {
|
||||||
|
my $tag = shift;
|
||||||
|
# look for an icon attached to the tag
|
||||||
|
my $attached = $tag . '/' . $config{'osm_tag_default_icon'};
|
||||||
|
if (srcfile($attached)) {
|
||||||
|
return $attached;
|
||||||
|
}
|
||||||
|
# look for the old way: mappings
|
||||||
|
if ($config{'osm_tag_icons'}->{$tag}) {
|
||||||
|
return $config{'osm_tag_icons'}->{$tag};
|
||||||
|
} else {
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub scrub_lonlat($$$) {
|
||||||
|
my ($loc, $lon, $lat) = @_;
|
||||||
|
if($loc) {
|
||||||
|
if($loc =~ /^\s*(\-?\d+(?:\.\d*°?|(?:°?|\s)\s*\d+(?:\.\d*\'?|(?:\'|\s)\s*\d+(?:\.\d*)?\"?|\'?)°?)[NS]?)\s*\,?\;?\s*(\-?\d+(?:\.\d*°?|(?:°?|\s)\s*\d+(?:\.\d*\'?|(?:\'|\s)\s*\d+(?:\.\d*)?\"?|\'?)°?)[EW]?)\s*$/) {
|
||||||
|
$lat = $1;
|
||||||
|
$lon = $2;
|
||||||
|
} else {
|
||||||
|
error("Bad loc");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(defined($lat)) {
|
||||||
|
if($lat =~ /^(\-?)(\d+)(?:(\.\d*)°?|(?:°|\s)\s*(\d+)(?:(\.\d*)\'?|(?:\'|\s)\s*(\d+(?:\.\d*)?\"?)|\'?)|°?)\s*([NS])?\s*$/) {
|
||||||
|
$lat = $2 + ($3//0) + ((($4//0) + (($5//0) + (($6//0)/60.)))/60.);
|
||||||
|
if (($1 eq '-') || (($7//'') eq 'S')) {
|
||||||
|
$lat = - $lat;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error("Bad lat");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(defined($lon)) {
|
||||||
|
if($lon =~ /^(\-?)(\d+)(?:(\.\d*)°?|(?:°|\s)\s*(\d+)(?:(\.\d*)\'?|(?:\'|\s)\s*(\d+(?:\.\d*)?\"?)|\'?)|°?)\s*([EW])?$/) {
|
||||||
|
$lon = $2 + ($3//0) + ((($4//0) + (($5//0) + (($6//0)/60.)))/60.);
|
||||||
|
if (($1 eq '-') || (($7//'') eq 'W')) {
|
||||||
|
$lon = - $lon;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error("Bad lon");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($lat < -90 || $lat > 90 || $lon < -180 || $lon > 180) {
|
||||||
|
error("Location out of range");
|
||||||
|
}
|
||||||
|
return ($lon, $lat);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub savestate {
|
||||||
|
my %waypoints = ();
|
||||||
|
my %linestrings = ();
|
||||||
|
foreach my $page (keys %pagestate) {
|
||||||
|
if (exists $pagestate{$page}{'osm'}) {
|
||||||
|
foreach my $map (keys %{$pagestate{$page}{'osm'}}) {
|
||||||
|
foreach my $name (keys %{$pagestate{$page}{'osm'}{$map}{'waypoints'}}) {
|
||||||
|
debug("found waypoint $name");
|
||||||
|
$waypoints{$map}{$name} = $pagestate{$page}{'osm'}{$map}{'waypoints'}{$name};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach my $page (keys %pagestate) {
|
||||||
|
if (exists $pagestate{$page}{'osm'}) {
|
||||||
|
foreach my $map (keys %{$pagestate{$page}{'osm'}}) {
|
||||||
|
# examine the links on this page
|
||||||
|
foreach my $name (keys %{$pagestate{$page}{'osm'}{$map}{'waypoints'}}) {
|
||||||
|
if (exists $links{$page}) {
|
||||||
|
foreach my $otherpage (@{$links{$page}}) {
|
||||||
|
if (exists $waypoints{$map}{$otherpage}) {
|
||||||
|
push(@{$linestrings{$map}}, [ [ $waypoints{$map}{$name}{'lon'}, $waypoints{$map}{$name}{'lat'} ],
|
||||||
|
[ $waypoints{$map}{$otherpage}{'lon'}, $waypoints{$map}{$otherpage}{'lat'} ] ]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# clear the state, it will be regenerated on the next parse
|
||||||
|
# the idea here is to clear up removed waypoints...
|
||||||
|
$pagestate{$page}{'osm'} = ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!defined($config{'osm_format'}) || !$config{'osm_format'}) {
|
||||||
|
$config{'osm_format'} = 'KML';
|
||||||
|
}
|
||||||
|
my %formats = map { $_ => 1 } split(/, */, $config{'osm_format'});
|
||||||
|
if ($formats{'GeoJSON'}) {
|
||||||
|
writejson(\%waypoints, \%linestrings);
|
||||||
|
}
|
||||||
|
if ($formats{'CSV'}) {
|
||||||
|
writecsvs(\%waypoints, \%linestrings);
|
||||||
|
}
|
||||||
|
if ($formats{'KML'}) {
|
||||||
|
writekml(\%waypoints, \%linestrings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub writejson($;$) {
|
||||||
|
my %waypoints = %{$_[0]};
|
||||||
|
my %linestrings = %{$_[1]};
|
||||||
|
eval q{use JSON};
|
||||||
|
error $@ if $@;
|
||||||
|
foreach my $map (keys %waypoints) {
|
||||||
|
my %geojson = ( "type" => "FeatureCollection", "features" => []);
|
||||||
|
foreach my $name (keys %{$waypoints{$map}}) {
|
||||||
|
my %marker = ( "type" => "Feature",
|
||||||
|
"geometry" => { "type" => "Point", "coordinates" => [ $waypoints{$map}{$name}{'lon'}, $waypoints{$map}{$name}{'lat'} ] },
|
||||||
|
"properties" => $waypoints{$map}{$name} );
|
||||||
|
push(@{$geojson{'features'}}, \%marker);
|
||||||
|
}
|
||||||
|
foreach my $linestring (@{$linestrings{$map}}) {
|
||||||
|
my %json = ( "type" => "Feature",
|
||||||
|
"geometry" => { "type" => "LineString", "coordinates" => $linestring });
|
||||||
|
push(@{$geojson{'features'}}, \%json);
|
||||||
|
}
|
||||||
|
debug('writing pois file pois.json in ' . $config{destdir} . "/$map");
|
||||||
|
writefile("pois.json",$config{destdir} . "/$map",to_json(\%geojson));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub writekml($;$) {
|
||||||
|
my %waypoints = %{$_[0]};
|
||||||
|
my %linestrings = %{$_[1]};
|
||||||
|
eval q{use XML::Writer};
|
||||||
|
error $@ if $@;
|
||||||
|
foreach my $map (keys %waypoints) {
|
||||||
|
debug("writing pois file pois.kml in " . $config{destdir} . "/$map");
|
||||||
|
|
||||||
|
=pod
|
||||||
|
Sample placemark:
|
||||||
|
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<kml xmlns="http://www.opengis.net/kml/2.2">
|
||||||
|
<Placemark>
|
||||||
|
<name>Simple placemark</name>
|
||||||
|
<description>Attached to the ground. Intelligently places itself
|
||||||
|
at the height of the underlying terrain.</description>
|
||||||
|
<Point>
|
||||||
|
<coordinates>-122.0822035425683,37.42228990140251,0</coordinates>
|
||||||
|
</Point>
|
||||||
|
</Placemark>
|
||||||
|
</kml>
|
||||||
|
|
||||||
|
Sample style:
|
||||||
|
|
||||||
|
|
||||||
|
<Style id="sh_sunny_copy69">
|
||||||
|
<IconStyle>
|
||||||
|
<scale>1.4</scale>
|
||||||
|
<Icon>
|
||||||
|
<href>http://waypoints.google.com/mapfiles/kml/shapes/sunny.png</href>
|
||||||
|
</Icon>
|
||||||
|
<hotSpot x="0.5" y="0.5" xunits="fraction" yunits="fraction"/>
|
||||||
|
</IconStyle>
|
||||||
|
<LabelStyle>
|
||||||
|
<color>ff00aaff</color>
|
||||||
|
</LabelStyle>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
use IO::File;
|
||||||
|
my $output = IO::File->new(">".$config{destdir} . "/$map/pois.kml");
|
||||||
|
|
||||||
|
my $writer = XML::Writer->new( OUTPUT => $output, DATA_MODE => 1, ENCODING => 'UTF-8');
|
||||||
|
$writer->xmlDecl();
|
||||||
|
$writer->startTag("kml", "xmlns" => "http://www.opengis.net/kml/2.2");
|
||||||
|
|
||||||
|
|
||||||
|
# first pass: get the icons
|
||||||
|
foreach my $name (keys %{$waypoints{$map}}) {
|
||||||
|
my %options = %{$waypoints{$map}{$name}};
|
||||||
|
$writer->startTag("Style", id => $options{tag});
|
||||||
|
$writer->startTag("IconStyle");
|
||||||
|
$writer->startTag("Icon");
|
||||||
|
$writer->startTag("href");
|
||||||
|
$writer->characters($options{icon});
|
||||||
|
$writer->endTag();
|
||||||
|
$writer->endTag();
|
||||||
|
$writer->endTag();
|
||||||
|
$writer->endTag();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach my $name (keys %{$waypoints{$map}}) {
|
||||||
|
my %options = %{$waypoints{$map}{$name}};
|
||||||
|
$writer->startTag("Placemark");
|
||||||
|
$writer->startTag("name");
|
||||||
|
$writer->characters($name);
|
||||||
|
$writer->endTag();
|
||||||
|
$writer->startTag("styleUrl");
|
||||||
|
$writer->characters('#' . $options{tag});
|
||||||
|
$writer->endTag();
|
||||||
|
#$writer->emptyTag('atom:link', href => $options{href});
|
||||||
|
$writer->startTag('href'); # to make it easier for us as the atom:link parameter is hard to access from javascript
|
||||||
|
$writer->characters($options{href});
|
||||||
|
$writer->endTag();
|
||||||
|
$writer->startTag("description");
|
||||||
|
$writer->characters($options{desc});
|
||||||
|
$writer->endTag();
|
||||||
|
$writer->startTag("Point");
|
||||||
|
$writer->startTag("coordinates");
|
||||||
|
$writer->characters($options{lon} . "," . $options{lat});
|
||||||
|
$writer->endTag();
|
||||||
|
$writer->endTag();
|
||||||
|
$writer->endTag();
|
||||||
|
}
|
||||||
|
|
||||||
|
my $i = 0;
|
||||||
|
foreach my $linestring (@{$linestrings{$map}}) {
|
||||||
|
$writer->startTag("Placemark");
|
||||||
|
$writer->startTag("name");
|
||||||
|
$writer->characters("linestring " . $i++);
|
||||||
|
$writer->endTag();
|
||||||
|
$writer->startTag("LineString");
|
||||||
|
$writer->startTag("coordinates");
|
||||||
|
my $str = '';
|
||||||
|
foreach my $coord (@{$linestring}) {
|
||||||
|
$str .= join(',', @{$coord}) . " \n";
|
||||||
|
}
|
||||||
|
$writer->characters($str);
|
||||||
|
$writer->endTag();
|
||||||
|
$writer->endTag();
|
||||||
|
$writer->endTag();
|
||||||
|
}
|
||||||
|
$writer->endTag();
|
||||||
|
$writer->end();
|
||||||
|
$output->close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub writecsvs($;$) {
|
||||||
|
my %waypoints = %{$_[0]};
|
||||||
|
foreach my $map (keys %waypoints) {
|
||||||
|
my $poisf = "lat\tlon\ttitle\tdescription\ticon\ticonSize\ticonOffset\n";
|
||||||
|
foreach my $name (keys %{$waypoints{$map}}) {
|
||||||
|
my %options = %{$waypoints{$map}{$name}};
|
||||||
|
my $line =
|
||||||
|
$options{'lat'} . "\t" .
|
||||||
|
$options{'lon'} . "\t" .
|
||||||
|
$name . "\t" .
|
||||||
|
$options{'desc'} . '<br /><a href="' . $options{'page'} . '">' . $name . "</a>\t" .
|
||||||
|
$options{'icon'} . "\n";
|
||||||
|
$poisf .= $line;
|
||||||
|
}
|
||||||
|
debug("writing pois file pois.txt in " . $config{destdir} . "/$map");
|
||||||
|
writefile("pois.txt",$config{destdir} . "/$map",$poisf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# pipe some data through the HTML scrubber
|
||||||
|
#
|
||||||
|
# code taken from the meta.pm plugin
|
||||||
|
sub scrub($$$) {
|
||||||
|
if (IkiWiki::Plugin::htmlscrubber->can("sanitize")) {
|
||||||
|
return IkiWiki::Plugin::htmlscrubber::sanitize(
|
||||||
|
content => shift, page => shift, destpage => shift);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return shift;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# taken from toggle.pm
|
||||||
|
sub format (@) {
|
||||||
|
my %params=@_;
|
||||||
|
|
||||||
|
if ($params{content}=~m!<div[^>]*id="mapdiv-[^"]*"[^>]*>!g) {
|
||||||
|
if (! ($params{content}=~s!</body>!include_javascript($params{page})."</body>"!em)) {
|
||||||
|
# no <body> tag, probably in preview mode
|
||||||
|
$params{content}=$params{content} . include_javascript($params{page});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $params{content};
|
||||||
|
}
|
||||||
|
|
||||||
|
sub prefered_format() {
|
||||||
|
if (!defined($config{'osm_format'}) || !$config{'osm_format'}) {
|
||||||
|
$config{'osm_format'} = 'KML';
|
||||||
|
}
|
||||||
|
my @spl = split(/, */, $config{'osm_format'});
|
||||||
|
return shift @spl;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub include_javascript ($) {
|
||||||
|
my $page=shift;
|
||||||
|
my $loader;
|
||||||
|
|
||||||
|
eval q{use JSON};
|
||||||
|
error $@ if $@;
|
||||||
|
if (exists $pagestate{$page}{'osm'}) {
|
||||||
|
foreach my $map (keys %{$pagestate{$page}{'osm'}}) {
|
||||||
|
foreach my $name (keys %{$pagestate{$page}{'osm'}{$map}{'displays'}}) {
|
||||||
|
my %options = %{$pagestate{$page}{'osm'}{$map}{'displays'}{$name}};
|
||||||
|
$options{'map'} = $map;
|
||||||
|
$options{'format'} = prefered_format();
|
||||||
|
$loader .= "mapsetup(\"mapdiv-$name\", " . to_json(\%options) . ");\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($loader) {
|
||||||
|
return embed_map_code() . "<script type=\"text/javascript\" charset=\"utf-8\">$loader</script>";
|
||||||
|
} else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub cgi($) {
|
||||||
|
my $cgi=shift;
|
||||||
|
|
||||||
|
return unless defined $cgi->param('do') &&
|
||||||
|
$cgi->param("do") eq "osm";
|
||||||
|
|
||||||
|
IkiWiki::decode_cgi_utf8($cgi);
|
||||||
|
|
||||||
|
my $map = $cgi->param('map');
|
||||||
|
if (!defined $map || $map !~ /^[a-z]*$/) {
|
||||||
|
error("invalid map parameter");
|
||||||
|
}
|
||||||
|
|
||||||
|
print "Content-Type: text/html\r\n";
|
||||||
|
print ("\r\n");
|
||||||
|
print "<html><body>";
|
||||||
|
print "<div id=\"mapdiv-$map\"></div>";
|
||||||
|
print embed_map_code($map);
|
||||||
|
print "<script type=\"text/javascript\" charset=\"utf-8\">mapsetup( 'mapdiv-$map', { 'map': '$map', 'lat': urlParams['lat'], 'lon': urlParams['lon'], 'zoom': urlParams['zoom'], 'fullscreen': 1, 'editable': 1, 'format': '" . prefered_format() . "'});</script>";
|
||||||
|
print "</body></html>";
|
||||||
|
|
||||||
|
exit 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub embed_map_code() {
|
||||||
|
return <<EOF;
|
||||||
|
<script src="http://www.openlayers.org/api/OpenLayers.js"></script>
|
||||||
|
<script>
|
||||||
|
// taken from http://stackoverflow.com/questions/901115/get-query-string-values-in-javascript
|
||||||
|
var urlParams = {};
|
||||||
|
(function () {
|
||||||
|
var e,
|
||||||
|
a = /\\+/g, // Regex for replacing addition symbol with a space
|
||||||
|
r = /([^&=]+)=?([^&]*)/g,
|
||||||
|
d = function (s) { return decodeURIComponent(s.replace(a, " ")); },
|
||||||
|
q = window.location.search.substring(1);
|
||||||
|
|
||||||
|
while (e = r.exec(q))
|
||||||
|
urlParams[d(e[1])] = d(e[2]);
|
||||||
|
})();
|
||||||
|
|
||||||
|
function mapsetup(divname, options) {
|
||||||
|
div = document.getElementById(divname);
|
||||||
|
if (options.fullscreen) {
|
||||||
|
permalink = 'permalink';
|
||||||
|
div.style.top = 0;
|
||||||
|
div.style.left = 0;
|
||||||
|
div.style.position = 'absolute';
|
||||||
|
div.style.width = '100%';
|
||||||
|
div.style.height = '100%';
|
||||||
|
} else {
|
||||||
|
div.style.height = options.height;
|
||||||
|
div.style.width = options.width;
|
||||||
|
div.style.float = options.float;
|
||||||
|
permalink = {base: options.href, title: "View larger map"};
|
||||||
|
}
|
||||||
|
map = new OpenLayers.Map(divname, {
|
||||||
|
controls: [
|
||||||
|
new OpenLayers.Control.Navigation(),
|
||||||
|
new OpenLayers.Control.ScaleLine(),
|
||||||
|
new OpenLayers.Control.Permalink(permalink)
|
||||||
|
],
|
||||||
|
displayProjection: new OpenLayers.Projection("EPSG:4326"),
|
||||||
|
numZoomLevels: 18
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
map.addLayer(new OpenLayers.Layer.OSM());
|
||||||
|
if (options.format == 'CSV') {
|
||||||
|
pois = new OpenLayers.Layer.Text( "CSV",
|
||||||
|
{ location:"/" + options.map + "/pois.txt",
|
||||||
|
projection: map.displayProjection
|
||||||
|
});
|
||||||
|
} else if (options.format == 'GeoJSON') {
|
||||||
|
pois = new OpenLayers.Layer.Vector("GeoJSON", {
|
||||||
|
protocol: new OpenLayers.Protocol.HTTP({
|
||||||
|
url: "/" + options.map + "/pois.json",
|
||||||
|
format: new OpenLayers.Format.GeoJSON()
|
||||||
|
}),
|
||||||
|
strategies: [new OpenLayers.Strategy.Fixed()]
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
pois = new OpenLayers.Layer.Vector("KML", {
|
||||||
|
protocol: new OpenLayers.Protocol.HTTP({
|
||||||
|
url: "/" + options.map + "/pois.kml",
|
||||||
|
format: new OpenLayers.Format.KML({
|
||||||
|
extractStyles: true,
|
||||||
|
extractAttributes: true
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
strategies: [new OpenLayers.Strategy.Fixed()]});
|
||||||
|
}
|
||||||
|
map.addLayer(pois);
|
||||||
|
select = new OpenLayers.Control.SelectFeature(pois);
|
||||||
|
map.addControl(select);
|
||||||
|
select.activate();
|
||||||
|
|
||||||
|
pois.events.on({
|
||||||
|
"featureselected": function (event) {
|
||||||
|
var feature = event.feature;
|
||||||
|
var content = '<h2><a href="' + feature.attributes.href + '">' +feature.attributes.name + "</a></h2>" + feature.attributes.description;
|
||||||
|
popup = new OpenLayers.Popup.FramedCloud("chicken",
|
||||||
|
feature.geometry.getBounds().getCenterLonLat(),
|
||||||
|
new OpenLayers.Size(100,100),
|
||||||
|
content,
|
||||||
|
null, true, function () {select.unselectAll()});
|
||||||
|
feature.popup = popup;
|
||||||
|
map.addPopup(popup);
|
||||||
|
},
|
||||||
|
"featureunselected": function (event) {
|
||||||
|
var feature = event.feature;
|
||||||
|
if(feature.popup) {
|
||||||
|
map.removePopup(feature.popup);
|
||||||
|
feature.popup.destroy();
|
||||||
|
delete feature.popup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (options.editable) {
|
||||||
|
vlayer = new OpenLayers.Layer.Vector( "Editable" );
|
||||||
|
map.addControl(new OpenLayers.Control.EditingToolbar(vlayer));
|
||||||
|
map.addLayer(vlayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.fullscreen) {
|
||||||
|
map.addControl(new OpenLayers.Control.PanZoomBar());
|
||||||
|
map.addControl(new OpenLayers.Control.LayerSwitcher({'ascending':false}));
|
||||||
|
map.addControl(new OpenLayers.Control.MousePosition());
|
||||||
|
map.addControl(new OpenLayers.Control.KeyboardDefaults());
|
||||||
|
} else {
|
||||||
|
map.addControl(new OpenLayers.Control.ZoomPanel());
|
||||||
|
}
|
||||||
|
|
||||||
|
//Set start centrepoint and zoom
|
||||||
|
if (!options.lat || !options.lon) {
|
||||||
|
options.lat = urlParams['lat'];
|
||||||
|
options.lon = urlParams['lon'];
|
||||||
|
}
|
||||||
|
if (!options.zoom) {
|
||||||
|
options.zoom = urlParams['zoom'];
|
||||||
|
}
|
||||||
|
if (options.lat && options.lon) {
|
||||||
|
var lat = options.lat;
|
||||||
|
var lon = options.lon;
|
||||||
|
var zoom= options.zoom || 10;
|
||||||
|
center = new OpenLayers.LonLat( lon, lat )
|
||||||
|
.transform(
|
||||||
|
new OpenLayers.Projection("EPSG:4326"), // transform from WGS 1984
|
||||||
|
map.getProjectionObject() // to Spherical Mercator Projection
|
||||||
|
);
|
||||||
|
map.setCenter (center, zoom);
|
||||||
|
} else {
|
||||||
|
pois.events.register("loadend", this, function () { map.zoomToExtent(pois.getDataExtent()); });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
|
@ -6,6 +6,11 @@ ikiwiki (3.20120203) UNRELEASED; urgency=low
|
||||||
to make builds more reproducible. Closes: #661569 (Paul Wise)
|
to make builds more reproducible. Closes: #661569 (Paul Wise)
|
||||||
* shortcut: Support Wikipedia's form of url-encoding for unicode
|
* shortcut: Support Wikipedia's form of url-encoding for unicode
|
||||||
characters, which involves mojibake. Closes: #661198
|
characters, which involves mojibake. Closes: #661198
|
||||||
|
* osm: New plugin to embed an OpenStreetMap into a wiki page.
|
||||||
|
Supports waypoints, tags, and can even draw paths matching
|
||||||
|
wikilinks between pages containing waypoints.
|
||||||
|
Thanks to Blars Blarson and Antoine Beaupré, as well as the worldwide
|
||||||
|
OpenStreetMap community for this utter awesomeness.
|
||||||
|
|
||||||
-- Joey Hess <joeyh@debian.org> Wed, 08 Feb 2012 16:07:00 -0400
|
-- Joey Hess <joeyh@debian.org> Wed, 08 Feb 2012 16:07:00 -0400
|
||||||
|
|
||||||
|
|
|
@ -153,6 +153,10 @@ Files: IkiWiki/Plugin/rsync.pm
|
||||||
Copyright: © 2009 Amitai Schlair
|
Copyright: © 2009 Amitai Schlair
|
||||||
License: BSD-2-clause
|
License: BSD-2-clause
|
||||||
|
|
||||||
|
Files: IkiWiki/Plugin/osm.pm
|
||||||
|
Copyright: © 2011 Blars Blarson, Antoine Beaupré
|
||||||
|
License: GPL-2
|
||||||
|
|
||||||
Files: doc/logo/*
|
Files: doc/logo/*
|
||||||
Copyright: © 2006 Recai Oktaş <roktas@debian.org>
|
Copyright: © 2006 Recai Oktaş <roktas@debian.org>
|
||||||
License: GPL-2+
|
License: GPL-2+
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
The `osm` directive is supplied by the [[!iki plugins/osm desc=osm]] plugin.
|
||||||
|
|
||||||
|
This directive inserts an OpenStreetMap map onto a page.
|
||||||
|
It is typically combined with the [[waypoint]] directive
|
||||||
|
to add points to the map.
|
||||||
|
|
||||||
|
## examples
|
||||||
|
|
||||||
|
[[!osm]]
|
||||||
|
[[!waypoint lat="45°30N" lon="73°40W" name="My city" tag="city"]]
|
||||||
|
|
||||||
|
The osm directive will display the actual map, while the waypoint
|
||||||
|
directive adds waypoints to the map.
|
||||||
|
|
||||||
|
The above can also be shortened as:
|
||||||
|
|
||||||
|
[[!waypoint lat="45°30N" lon="73°40W" name="My city" tag="city" embed]]
|
||||||
|
|
||||||
|
The tag is also taken from the tags elsewhere in the page, so the
|
||||||
|
above is equivalent to:
|
||||||
|
|
||||||
|
[[!waypoint lat="45°30N" lon="73°40W" name="My city" embed]]
|
||||||
|
[[!tag city]]
|
||||||
|
|
||||||
|
The icon is also taken from the tag if attached to the tag page as
|
||||||
|
icon.png (default, modifiable)..
|
||||||
|
|
||||||
|
## map display
|
||||||
|
|
||||||
|
* `map` - map to display, defaults to the current page
|
||||||
|
name in fullscreen mode, "map" otherwise
|
||||||
|
* `zoom` - the level to zoom to on the OSM map
|
||||||
|
* `loc` - lattitude and longitude of the map center
|
||||||
|
* `lat` - lattitude
|
||||||
|
* `lon` - longitude
|
||||||
|
* `fullscreen` - make the map take the whole screen through CSS
|
||||||
|
* `editable` - add edit controls in a separate layer
|
||||||
|
* `right` - float the map right, ignored for fullscreen
|
||||||
|
* `left` - float the map left (default unless fullscreen)
|
||||||
|
* `width` - width of the map, ignored for fullscreen
|
||||||
|
* `height` - height of the map, ignored for fullscreen
|
||||||
|
|
||||||
|
## waypoints
|
||||||
|
|
||||||
|
Waypoints can be added to any page. By default the waypoint takes the
|
||||||
|
name of the page, which allows you to easily tag pages and make them
|
||||||
|
appear on the central map.
|
||||||
|
|
||||||
|
Waypoints, by default, show up as a image (the `icon` parameter) link
|
||||||
|
to the main map (or the `map` parameter provided). That markup can be
|
||||||
|
hidden with the `hidden` parameter.
|
||||||
|
|
||||||
|
* `name` - the name of this point, defaults to the page name (!) must
|
||||||
|
be unique, otherwise later incantation will overwrite previous
|
||||||
|
ones.
|
||||||
|
* `map` - the map to add the point to (defaults to "map")
|
||||||
|
* `desc` - description to embed in the map
|
||||||
|
* `loc` - lattitude and longitude
|
||||||
|
* `lat` - lattitude
|
||||||
|
* `lon` - longitude
|
||||||
|
* `tag` - the type of points, maps to an icon in the osm_types array
|
||||||
|
* `hidden` - do not display the link to the map (will not affect `embed`)
|
||||||
|
* `icon` - URL to the icon to show in the link to the map and within
|
||||||
|
the map
|
||||||
|
* `embed` - embed the map display alongside the point, in which case
|
||||||
|
the regular arguments to the map display can be used
|
||||||
|
|
||||||
|
## Links
|
||||||
|
|
||||||
|
If two pages with waypoints have a link between them, that link will
|
||||||
|
magically show up on the map. Now how awesome is that?
|
|
@ -0,0 +1,6 @@
|
||||||
|
The `waypoint` directive is supplied by the [[!iki plugins/osm desc=osm]] plugin.
|
||||||
|
|
||||||
|
This directive adds a waypoint ot an OpenStreetMap map displayed
|
||||||
|
by the [[osm]] directive. See the [[osm]] directive for examples
|
||||||
|
and options.
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
[[!template id=plugin name=osm author="Blars Blarson, Antoine Beaupré"]]
|
|
||||||
[[!tag type/special-purpose todo/geotagging]]
|
|
||||||
|
|
||||||
Openstreetmap/Openlayers support for ikiwiki
|
|
||||||
--------------------------------------------
|
|
||||||
|
|
||||||
This plugin provides simple Openstreetmap/Openlayers support for ikiwiki. It can embed Openstreetmap viewports within a page or link to a bigger map that will have multiple markers, generated with a KML (or CSV, or GeoJSON) datafile of markers based on the different calling pages. Multiple distinct maps on a single wiki are supported.
|
|
||||||
|
|
||||||
Plugin was originally written by [[the techno-viking|http://techno-viking.com/posts/ikiwiki-maps/]] and fixed up by [[anarcat]]. Code is available at `git://src.anarcat.ath.cx/ikiwiki-osm.git`. See [[this page|http://anarcat.ath.cx/software/ikiwiki-osm/README]] for a more complete description and [[the Mtl-mesh wiki|http://mesh.openisp.ca/nodes/anarcat]] for a sample of what this plugin can do.
|
|
||||||
|
|
||||||
See also [[plugins/contrib/googlemaps]].
|
|
||||||
|
|
||||||
This plugin would be greatly improved by [[todo/internal_definition_list_support]].
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
[[!template id=plugin name=osm author="Blars Blarson, Antoine Beaupré"]]
|
||||||
|
[[!tag type/special-purpose todo/geotagging]]
|
||||||
|
|
||||||
|
## Openstreetmap/Openlayers support for ikiwiki
|
||||||
|
|
||||||
|
This plugin provides simple Openstreetmap/Openlayers support for ikiwiki.
|
||||||
|
It can embed Openstreetmap viewports within a page or link to a bigger map
|
||||||
|
that will have multiple markers, generated with a KML (or CSV, or GeoJSON)
|
||||||
|
datafile of markers based on the different calling pages. Multiple distinct
|
||||||
|
maps on a single wiki are supported.
|
||||||
|
|
||||||
|
You will need the [[!cpan XML::Writer]] perl module to write KML files,
|
||||||
|
which is the default mode of operation. GeoJSON files can also be generated
|
||||||
|
if the [[!cpan JSON]] perl module is installed.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
The plugin was originally written by
|
||||||
|
[[the techno-viking|http://techno-viking.com/posts/ikiwiki-maps/]] and fixed up
|
||||||
|
by [[anarcat]].
|
||||||
|
|
||||||
|
See [[the Mtl-mesh
|
||||||
|
wiki|http://mesh.openisp.ca/nodes/anarcat]] for a sample of what this
|
||||||
|
plugin can do
|
||||||
|
|
||||||
|
See also [[plugins/contrib/googlemaps]].
|
||||||
|
|
||||||
|
This plugin would be greatly improved by
|
||||||
|
[[todo/internal_definition_list_support]].
|
Loading…
Reference in New Issue