more basic framework

This commit is contained in:
Steve Coast 2006-07-28 21:53:30 +00:00
parent 15f23469d9
commit b4c0bfd8fa
20 changed files with 1084 additions and 448 deletions

181
README
View file

@ -1,180 +1,13 @@
== Welcome to Rails
Rails is a web-application and persistence framework that includes everything
needed to create database-backed web-applications according to the
Model-View-Control pattern of separation. This pattern splits the view (also
called the presentation) into "dumb" templates that are primarily responsible
for inserting pre-built data in between HTML tags. The model contains the
"smart" domain objects (such as Account, Product, Person, Post) that holds all
the business logic and knows how to persist themselves to a database. The
controller handles the incoming requests (such as Save New Account, Update
Product, Show Post) by manipulating the model and directing data to the view.
Task one
========
In Rails, the model is handled by what's called an object-relational mapping
layer entitled Active Record. This layer allows you to present the data from
database rows as objects and embellish these data objects with business logic
methods. You can read more about Active Record in
link:files/vendor/rails/activerecord/README.html.
Get OSM on rails with a 0.4 API, without changing the db schema
The controller and view are handled by the Action Pack, which handles both
layers by its two parts: Action View and Action Controller. These two layers
are bundled in a single package due to their heavy interdependence. This is
unlike the relationship between the Active Record and Action Pack that is much
more separate. Each of these packages can be used independently outside of
Rails. You can read more about Action Pack in
link:files/vendor/rails/actionpack/README.html.
see db/README for how to create the db
Two
===
== Getting started
change the schema
1. Start the web server: <tt>ruby script/server</tt> (run with --help for options)
2. Go to http://localhost:3000/ and get "Welcome aboard: Youre riding the Rails!"
3. Follow the guidelines to start developing your application
== Web servers
Rails uses the built-in web server in Ruby called WEBrick by default, so you don't
have to install or configure anything to play around.
If you have lighttpd installed, though, it'll be used instead when running script/server.
It's considerably faster than WEBrick and suited for production use, but requires additional
installation and currently only works well on OS X/Unix (Windows users are encouraged
to start with WEBrick). We recommend version 1.4.11 and higher. You can download it from
http://www.lighttpd.net.
If you want something that's halfway between WEBrick and lighttpd, we heartily recommend
Mongrel. It's a Ruby-based web server with a C-component (so it requires compilation) that
also works very well with Windows. See more at http://mongrel.rubyforge.org/.
But of course its also possible to run Rails with the premiere open source web server Apache.
To get decent performance, though, you'll need to install FastCGI. For Apache 1.3, you want
to use mod_fastcgi. For Apache 2.0+, you want to use mod_fcgid.
See http://wiki.rubyonrails.com/rails/pages/FastCGI for more information on FastCGI.
== Example for Apache conf
<VirtualHost *:80>
ServerName rails
DocumentRoot /path/application/public/
ErrorLog /path/application/log/server.log
<Directory /path/application/public/>
Options ExecCGI FollowSymLinks
AllowOverride all
Allow from all
Order allow,deny
</Directory>
</VirtualHost>
NOTE: Be sure that CGIs can be executed in that directory as well. So ExecCGI
should be on and ".cgi" should respond. All requests from 127.0.0.1 go
through CGI, so no Apache restart is necessary for changes. All other requests
go through FCGI (or mod_ruby), which requires a restart to show changes.
== Debugging Rails
Have "tail -f" commands running on both the server.log, production.log, and
test.log files. Rails will automatically display debugging and runtime
information to these files. Debugging info will also be shown in the browser
on requests from 127.0.0.1.
== Breakpoints
Breakpoint support is available through the script/breakpointer client. This
means that you can break out of execution at any point in the code, investigate
and change the model, AND then resume execution! Example:
class WeblogController < ActionController::Base
def index
@posts = Post.find_all
breakpoint "Breaking out from the list"
end
end
So the controller will accept the action, run the first line, then present you
with a IRB prompt in the breakpointer window. Here you can do things like:
Executing breakpoint "Breaking out from the list" at .../webrick_server.rb:16 in 'breakpoint'
>> @posts.inspect
=> "[#<Post:0x14a6be8 @attributes={\"title\"=>nil, \"body\"=>nil, \"id\"=>\"1\"}>,
#<Post:0x14a6620 @attributes={\"title\"=>\"Rails you know!\", \"body\"=>\"Only ten..\", \"id\"=>\"2\"}>]"
>> @posts.first.title = "hello from a breakpoint"
=> "hello from a breakpoint"
...and even better is that you can examine how your runtime objects actually work:
>> f = @posts.first
=> #<Post:0x13630c4 @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}>
>> f.
Display all 152 possibilities? (y or n)
Finally, when you're ready to resume execution, you press CTRL-D
== Console
You can interact with the domain model by starting the console through script/console.
Here you'll have all parts of the application configured, just like it is when the
application is running. You can inspect domain models, change values, and save to the
database. Starting the script without arguments will launch it in the development environment.
Passing an argument will specify a different environment, like <tt>script/console production</tt>.
== Description of contents
app
Holds all the code that's specific to this particular application.
app/controllers
Holds controllers that should be named like weblog_controller.rb for
automated URL mapping. All controllers should descend from
ActionController::Base.
app/models
Holds models that should be named like post.rb.
Most models will descend from ActiveRecord::Base.
app/views
Holds the template files for the view that should be named like
weblog/index.rhtml for the WeblogController#index action. All views use eRuby
syntax. This directory can also be used to keep stylesheets, images, and so on
that can be symlinked to public.
app/helpers
Holds view helpers that should be named like weblog_helper.rb.
app/apis
Holds API classes for web services.
config
Configuration files for the Rails environment, the routing map, the database, and other dependencies.
components
Self-contained mini-applications that can bundle together controllers, models, and views.
db
Contains the database schema in schema.rb. db/migrate contains all
the sequence of Migrations for your schema.
lib
Application specific libraries. Basically, any kind of custom code that doesn't
belong under controllers, models, or helpers. This directory is in the load path.
public
The directory available for the web server. Contains subdirectories for images, stylesheets,
and javascripts. Also contains the dispatchers and the default HTML files.
script
Helper scripts for automation and generation.
test
Unit and functional tests along with fixtures.
vendor
External libraries that the application depends on. Also includes the plugins subdirectory.
This directory is in the load path.

View file

@ -0,0 +1,4 @@
# Filters added to this controller will be run for all controllers in the application.
# Likewise, all the methods added will be available for all controllers.
class ApplicationController < ActionController::Base
end

View file

@ -0,0 +1,2 @@
class TraceController < ApplicationController
end

View file

@ -0,0 +1,2 @@
class TracePointsController < ApplicationController
end

View file

@ -0,0 +1,6 @@
class UserController < ApplicationController
def new
end
end

View file

@ -0,0 +1,3 @@
# Methods added to this helper will be available to all templates in the application.
module ApplicationHelper
end

View file

@ -0,0 +1,2 @@
module TraceHelper
end

View file

@ -0,0 +1,2 @@
module TracePointsHelper
end

View file

@ -0,0 +1,2 @@
module UserHelper
end

4
app/models/trace.rb Normal file
View file

@ -0,0 +1,4 @@
class Trace < ActiveRecord::Base
set_table_name 'gpx_files'
has_many :trace_points, :foreign_key => 'gpx_id'
end

View file

@ -0,0 +1,4 @@
class TracePoints < ActiveRecord::Base
set_table_name 'gps_points'
belongs_to :trace, :foreign_key => 'gpx_id'
end

3
app/models/user.rb Normal file
View file

@ -0,0 +1,3 @@
class User < ActiveRecord::Base
has_many :traces
end

View file

@ -0,0 +1,22 @@
<html>
<head>
<%= javascript_include_tag 'main.js' %>
<!--[if IE]><%= javascript_include_tag 'pngfix.js' %><![endif]--> <!-- thanks, microsoft! -->
<%= javascript_include_tag 'tile.js' %>
<%= javascript_include_tag 'site.js' %>
<script type="text/javascript">
lon = <% if cgi['lon'].length > 0 then print cgi['lon'].to_f else print '0' end %>;
lat = <% if cgi['lat'].length > 0 then print cgi['lat'].to_f else print '0' end %>;
zoom = <% if cgi['zoom'].length > 0 then print cgi['zoom'].to_f else print '0' end %>;
<% if cgi['scale'].length > 0 then %>
zoom = Math.log(360.0/(( <% print cgi['scale'].to_f() %> ) * 512.0)) / Math.log(2.0);
<% end %>
</script>
<link rel="stylesheet" type="text/css" href="/css/style.css" />
<title>OpenStreetMap</title>
</head>
<body>
<%= @content_for_layout %>
</body>
</html>

4
app/views/user/new.rhtml Normal file
View file

@ -0,0 +1,4 @@
create a user

View file

@ -1,277 +1,5 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<title>Ruby on Rails: Welcome aboard</title>
<style type="text/css" media="screen">
body {
margin: 0;
margin-bottom: 25px;
padding: 0;
background-color: #f0f0f0;
font-family: "Lucida Grande", "Bitstream Vera Sans", "Verdana";
font-size: 13px;
color: #333;
}
h1 {
font-size: 28px;
color: #000;
}
a {color: #03c}
a:hover {
background-color: #03c;
color: white;
text-decoration: none;
}
#page {
background-color: #f0f0f0;
width: 750px;
margin: 0;
margin-left: auto;
margin-right: auto;
}
#content {
float: left;
background-color: white;
border: 3px solid #aaa;
border-top: none;
padding: 25px;
width: 500px;
}
#sidebar {
float: right;
width: 175px;
}
#footer {
clear: both;
}
#header, #about, #getting-started {
padding-left: 75px;
padding-right: 30px;
}
nuffin here
#header {
background-image: url("images/rails.png");
background-repeat: no-repeat;
background-position: top left;
height: 64px;
}
#header h1, #header h2 {margin: 0}
#header h2 {
color: #888;
font-weight: normal;
font-size: 16px;
}
#about h3 {
margin: 0;
margin-bottom: 10px;
font-size: 14px;
}
#about-content {
background-color: #ffd;
border: 1px solid #fc0;
margin-left: -11px;
}
#about-content table {
margin-top: 10px;
margin-bottom: 10px;
font-size: 11px;
border-collapse: collapse;
}
#about-content td {
padding: 10px;
padding-top: 3px;
padding-bottom: 3px;
}
#about-content td.name {color: #555}
#about-content td.value {color: #000}
#about-content.failure {
background-color: #fcc;
border: 1px solid #f00;
}
#about-content.failure p {
margin: 0;
padding: 10px;
}
#getting-started {
border-top: 1px solid #ccc;
margin-top: 25px;
padding-top: 15px;
}
#getting-started h1 {
margin: 0;
font-size: 20px;
}
#getting-started h2 {
margin: 0;
font-size: 14px;
font-weight: normal;
color: #333;
margin-bottom: 25px;
}
#getting-started ol {
margin-left: 0;
padding-left: 0;
}
#getting-started li {
font-size: 18px;
color: #888;
margin-bottom: 25px;
}
#getting-started li h2 {
margin: 0;
font-weight: normal;
font-size: 18px;
color: #333;
}
#getting-started li p {
color: #555;
font-size: 13px;
}
#search {
margin: 0;
padding-top: 10px;
padding-bottom: 10px;
font-size: 11px;
}
#search input {
font-size: 11px;
margin: 2px;
}
#search-text {width: 170px}
#sidebar ul {
margin-left: 0;
padding-left: 0;
}
#sidebar ul h3 {
margin-top: 25px;
font-size: 16px;
padding-bottom: 10px;
border-bottom: 1px solid #ccc;
}
#sidebar li {
list-style-type: none;
}
#sidebar ul.links li {
margin-bottom: 5px;
}
</style>
<script type="text/javascript" src="javascripts/prototype.js"></script>
<script type="text/javascript" src="javascripts/effects.js"></script>
<script type="text/javascript">
function about() {
if (Element.empty('about-content')) {
new Ajax.Updater('about-content', 'rails/info/properties', {
method: 'get',
onFailure: function() {Element.classNames('about-content').add('failure')},
onComplete: function() {new Effect.BlindDown('about-content', {duration: 0.25})}
});
} else {
new Effect[Element.visible('about-content') ?
'BlindUp' : 'BlindDown']('about-content', {duration: 0.25});
}
}
window.onload = function() {
$('search-text').value = '';
$('search').onsubmit = function() {
$('search-text').value = 'site:rubyonrails.org ' + $F('search-text');
}
}
</script>
</head>
<body>
<div id="page">
<div id="sidebar">
<ul id="sidebar-items">
<li>
<form id="search" action="http://www.google.com/search" method="get">
<input type="hidden" name="hl" value="en" />
<input type="text" id="search-text" name="q" value="site:rubyonrails.org " />
<input type="submit" value="Search" /> the Rails site
</form>
</li>
<li>
<h3>Join the community</h3>
<ul class="links">
<li><a href="http://www.rubyonrails.org/">Ruby on Rails</a></li>
<li><a href="http://weblog.rubyonrails.org/">Official weblog</a></li>
<li><a href="http://lists.rubyonrails.org/">Mailing lists</a></li>
<li><a href="http://wiki.rubyonrails.org/rails/pages/IRC">IRC channel</a></li>
<li><a href="http://wiki.rubyonrails.org/">Wiki</a></li>
<li><a href="http://dev.rubyonrails.org/">Bug tracker</a></li>
</ul>
</li>
<li>
<h3>Browse the documentation</h3>
<ul class="links">
<li><a href="http://api.rubyonrails.org/">Rails API</a></li>
<li><a href="http://stdlib.rubyonrails.org/">Ruby standard library</a></li>
<li><a href="http://corelib.rubyonrails.org/">Ruby core</a></li>
</ul>
</li>
</ul>
</div>
<div id="content">
<div id="header">
<h1>Welcome aboard</h1>
<h2>You&rsquo;re riding the Rails!</h2>
</div>
<div id="about">
<h3><a href="rails/info/properties" onclick="about(); return false">About your application&rsquo;s environment</a></h3>
<div id="about-content" style="display: none"></div>
</div>
<div id="getting-started">
<h1>Getting started</h1>
<h2>Here&rsquo;s how to get rolling:</h2>
<ol>
<li>
<h2>Create your databases and edit <tt>config/database.yml</tt></h2>
<p>Rails needs to know your login and password.</p>
</li>
<li>
<h2>Use <tt>script/generate</tt> to create your models and controllers</h2>
<p>To see all available options, run it without parameters.</p>
</li>
<li>
<h2>Set up a default route and remove or rename this file</h2>
<p>Routes are setup in config/routes.rb.</p>
</li>
</ol>
</div>
</div>
<div id="footer">&nbsp;</div>
</div>
</body>
</html>

View file

@ -0,0 +1,72 @@
/*
Copyright (C) 2004-05 Nick Whitelegg, Hogweed Software, nick@hogweed.org
This program is free software; you can redistribute it and/or modify
it under the terms of the Lesser 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
Lesser GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
*/
// These are functions which manipulate the slippy map in various ways
// The idea has been to try and clean up the slippy map API and take code
// which does not manipulate it directly outside.
var view=0, tileURL, tile_engine;
function init()
{
tileURL = 'http://tile.openstreetmap.org/ruby/wmsmod.rbx';
tile_engine = new tile_engine_new('drag','FULL','',tileURL,lon,lat,zoom,700,500);
tile_engine.setURLAttribute("landsat",1);
document.getElementById('zoomout').onclick = zoomOut;
document.getElementById('zoomin').onclick = zoomIn;
/*
document.getElementById('landsat').onclick = landsatToggle;
*/
//document.getElementById('posGo').onclick = setPosition;
}
function zoomIn()
{
tile_engine.tile_engine_zoomin();
}
function zoomOut()
{
tile_engine.tile_engine_zoomout();
}
function enableTileEngine()
{
tile_engine.event_catch();
}
function landsatToggle()
{
var lsat = tile_engine.getURLAttribute("landsat");
tile_engine.setURLAttribute("landsat", (lsat) ? 0: 1);
tile_engine.forceRefresh();
}
function setPosition()
{
/*
var txtLat = document.getElementById("txtLat"),
txtLon = document.getElementById("txtLon");
tile_engine.setLatLon(txtLat, txtLon);
*/
}

View file

@ -0,0 +1,25 @@
function correctPNG() // correctly handle PNG transparency in Win IE 5.5 or higher.
{
for(var i=0; i<document.images.length; i++)
{
var img = document.images[i]
var imgName = img.src.toUpperCase()
if (imgName.indexOf('.PNG') > 0)
{
var imgID = (img.id) ? "id='" + img.id + "' " : ""
var imgClass = (img.className) ? "class='" + img.className + "' " : ""
var imgTitle = (img.title) ? "title='" + img.title + "' " : "title='" + img.alt + "' "
var imgStyle = "display:inline-block;" + img.style.cssText
if (img.align == "left") imgStyle = "float:left;" + imgStyle
if (img.align == "right") imgStyle = "float:right;" + imgStyle
if (img.parentElement.href) imgStyle = "cursor:hand;" + imgStyle
var strNewHTML = "<span " + imgID + imgClass + imgTitle
+ " style=\"" + "width:" + img.width + "px; height:" + img.height + "px;" + imgStyle + ";"
+ "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader"
+ "(src=\'" + img.src + "\', sizingMethod='scale');\"></span>"
img.outerHTML = strNewHTML
i = i-1
}
}
}
window.attachEvent("onload", correctPNG);

View file

@ -0,0 +1,28 @@
function updatelinks(lon,lat,zoom) {
var links = new Array();
links['viewanchor'] = '/index.html';
//links['editanchor'] = 'edit.html';
links['uploadanchor'] = '/traces';
links['loginanchor'] = '/login.html';
links['logoutanchor'] = '/logout.html';
links['registeranchor'] = '/create-account.html';
var node;
var anchor;
for (anchor in links) {
node = document.getElementById(anchor);
if (! node) { continue; }
node.href = links[anchor] + "?lat=" + lat + "&lon=" + lon + "&zoom=" + zoom;
}
node = document.getElementById("editanchor");
if (node) {
if ( zoom >= 14) {
node.href = '/edit.html?lat=' + lat + '&lon=' + lon + "&zoom=" + zoom;
node.style.fontStyle = 'normal';
} else {
node.href = 'javascript:alert("zoom in to edit map");';
node.style.fontStyle = 'italic';
}
}
}

889
public/javascripts/tile.js Normal file
View file

@ -0,0 +1,889 @@
// June 20th 2005 http://civicactions.net anselm@hook.org public domain version 0.5
//
// miscellaneous
//
var netscape = ( document.getElementById && !document.all ) || document.layers;
var defaultEngine = null; // xxx for firefox keyboard events.
var PI = 3.14159265358979323846;
var lat_range = PI, lon_range = PI;
//
// Utility - get div position - may not be accurate
//
function getCSSPositionX(parent)
{
var offset = parent.x ? parseInt(parent.x) : 0;
offset += parent.style.left ? parseInt(parent.style.left) : 0;
for(var node = parent; node ; node = node.offsetParent )
{
offset += node.offsetLeft;
}
return offset;
}
function getCSSPositionY(parent)
{
var offset = parent.y ? parseInt(parent.y) : 0;
offset += parent.style.top ? parseInt(parent.style.top) : 0;
for(var node = parent; node ; node = node.offsetParent )
{
offset += node.offsetTop;
}
return offset;
}
///
/// initialize a new tile engine object
/// usage: var engine = new tile_engine_new(parentdiv,stylehints,wmssource,lon,lat,zoom,optional width, optional height)
///
function tile_engine_new(parentname,hints,feedurl,url,lon,lat,zoom,w,h)
{
// NW geocoder removed for now
this.timestamp = new Date().getTime();
this.urlAttr = new Array();
// NW Removed navigation buttons entirely for flexibility
this.lonPerPixel = function()
{ return (this.lon_quant/this.scale)/this.tilewidth; }
this.latPerPixel = function()
{ return (this.lat_quant/this.scale)/this.tileheight; }
this.xToLon = function(x)
{ return this.lon + (x-this.thewidth/2)*this.lonPerPixel(); }
this.yToLat = function(y)
{ return normallat(this.lat - (y-this.theheight/2)
*this.latPerPixel()); }
this.lonToX = function (lon)
{ return ((lon-this.lon)/this.lonPerPixel()) + this.thewidth/2;}
this.latToY = function(lat)
{ return ((this.lat-mercatorlat(lat))/this.latPerPixel()) +
this.theheight/2; }
//
// it is possible that this collection is already in use - clean it
//
this.clean = function()
{
/*
while( this.parent.hasChildNodes() )
this.parent.removeChild( this.parent.firstChild );
*/
for(var ct=0; ct<this.parent.childNodes.length; ct++)
{
if(this.parent.childNodes[ct].id != "controls")
this.parent.removeChild(this.parent.childNodes[ct]);
}
//
// build inner tile container for theoretical speed improvement?
// center in parent for simplicity of math
// size of inner container is irrelevant since overflow is enabled
//
if( this.dragcontainer )
{
this.tiles = document.createElement('div');
this.tiles.style.position = 'absolute';
this.tiles.style.left = this.displaywidth/2 + 'px';
this.tiles.style.top = this.displayheight/2 + 'px';
this.tiles.style.width = '16px';
this.tiles.style.height = '16px';
if( this.debug )
{
this.tiles.style.border = 'dashed green 1px';
}
this.tiles.tile_engine = this;
this.parent.appendChild(this.tiles);
}
else
{
this.tiles = this.parent;
}
}
/// focus over specified lon/lat and zoom
/// user should call this.drag(0,0) after this to force an initial refresh
///
this.performzoom = function(lon,lat,z)
{
// setup for zoom
// this engine operates at * scale to try avoid tile errors thrashing
// server cache
this.scale = 1000000;
this.lon_min_clamp = -180 * this.scale;
this.lon_max_clamp = 180 * this.scale;
this.lat_min_clamp = -180 * this.scale; //t
this.lat_max_clamp = 180 * this.scale; //t
this.lon_start_tile = 180 * this.scale;
this.lat_start_tile = 90 * this.scale; //t
this.zoom_power = 2;
this.lon_quant = this.lon_start_tile;
this.lat_quant = this.lat_start_tile;
this.lon = lon;
this.lat = lat;
// operational lat - = lat due to quirks in our engine and quirks in o
// lon/lat design
lat = -lat;
// divide tile size until reach requested zoom
// trying to guarantee consistency so as to not thrash the server side tile cache
while(z > 0)
{
this.lon_quant = this.lon_quant / this.zoom_power;
this.lat_quant = this.lat_quant / this.zoom_power;
z--;
}
this.lon_quant = Math.round( this.lon_quant );
this.lat_quant = Math.round( this.lat_quant );
// get user requested exact lon/lat
this.lon_scaled = Math.round( lon * this.scale );
this.lat_scaled = Math.round( lat * this.scale );
// convert requested exact lon/lat to quantized lon lat (rounding down
// or up as best suits)
this.lon_round = Math.round( this.lon_scaled / this.lon_quant ) *
this.lon_quant;
this.lat_round = Math.round( this.lat_scaled / this.lat_quant ) *
this.lat_quant;
//alert('lon_round=' + this.lon_round+ ' lat_round='+this.lat_round);
// calculate world extents [ this is the span of all tiles in lon/lat ]
this.lon_min = this.lon_round - this.lon_quant;
this.lon_max = this.lon_round + this.lon_quant;
this.lat_min = this.lat_round - this.lat_quant;
this.lat_max = this.lat_round + this.lat_quant;
// set tiled region details [ this is the span of all tiles in pixels ]
this.centerx = 0;
this.centery = 0;
this.tilewidth = 256;
this.tileheight = 128;
this.left = -this.tilewidth;
this.right = this.tilewidth;
this.top = -this.tileheight;
this.bot = this.tileheight;
// adjust the current center position slightly to reflect exact lat/lon
// not rounded
this.centerx -= (this.lon_scaled-this.lon_round)/
(this.lon_max-this.lon_min)*(this.right-this.left);
this.centery -= (this.lat_scaled-this.lat_round)/
(this.lat_max-this.lat_min)*(this.bot-this.top);
}
this.update_perma_link = function() {
// because we're using mercator
updatelinks(this.lon,normallat(this.lat),this.zoom);
}
///
/// draw the spanning lon/lat range
/// drag is simply the mouse delta in pixels
///
this.drag = function(dragx,dragy)
{
var fred=true;
// move the drag offset
this.centerx += dragx;
this.centery += dragy;
// update where we think the user is actually focused
this.lon = ( this.lon_round - ( this.lon_max - this.lon_min ) /
( this.right - this.left ) * this.centerx ) / this.scale;
this.lat = - ( this.lat_round - ( this.lat_max - this.lat_min ) /
( this.bot - this.top ) * this.centery ) / this.scale;
this.update_perma_link();
// show it
var helper = this.navhelp;
// extend exposed sections
var dirty = false;
while( this.left + this.centerx > -this.displaywidth/2 &&
this.lon_min > this.lon_min_clamp )
{
this.left -= this.tilewidth;
this.lon_min -= this.lon_quant;
dirty = true;
}
while( this.right + this.centerx < this.displaywidth/2 &&
this.lon_max < this.lon_max_clamp )
{
this.right += this.tilewidth;
this.lon_max += this.lon_quant;
dirty = true;
}
while( this.top + this.centery > -this.displayheight/2 &&
this.lat_min > this.lat_min_clamp )
{
this.top -= this.tileheight;
this.lat_min -= this.lat_quant;
dirty = true;
}
while( this.bot + this.centery < this.displayheight/2 &&
this.lat_max < this.lat_max_clamp )
{
this.bot += this.tileheight;
this.lat_max += this.lat_quant;
dirty = true;
}
// prepare to walk the container and assure that all nodes are correct
var containerx;
var containery;
// in drag container mode we do not have to move the children all the
// time
if( this.dragcontainer )
{
this.tiles.style.left = this.displaywidth / 2 + this.centerx + 'px';
this.tiles.style.top = this.displayheight / 2 + this.centery + 'px';
if( !dirty && this.tiles.hasChildNodes() )
{
return;
}
containerx = this.left;
containery = this.top;
}
else
{
containerx = this.left + this.centerx;
containery = this.top + this.centery;
}
// walk all tiles and repair as needed
// xxx one bug is that it walks the _entire_ width and height...
// not just visible.
// xxx this makes cleanup harder and perhaps a bitmap is better
var removehidden = 1;
var removecolumn = 0;
var removerow = 0;
var containeryreset = containery;
for( var x = this.lon_min; x < this.lon_max ; x+= this.lon_quant )
{
// will this row be visible in the next round?
if( removehidden )
{
var rx = containerx + this.centerx;
if( rx > this.displaywidth / 2 )
{
removerow = 1;
// ideally i would truncate max width here
}
else if( rx + this.tilewidth < - this.displaywidth / 2 )
{
removerow = 1;
}
else
{
removerow = 0;
}
}
for( var y = this.lat_min; y < this.lat_max ; y+= this.lat_quant )
{
// is this column visible?
if( removehidden )
{
var ry = containery + this.centery;
if( ry > this.displayheight / 2 )
{
removecolumn = 1;
}
else if( ry + this.tileheight < - this.displayheight/2)
{
removecolumn = 1;
}
else
{
removecolumn = 0;
}
}
// convert to WMS compliant coordinate system
var lt = x / this.scale;
var rt = lt + this.lon_quant / this.scale;
var tp = y / this.scale;
var bt = tp + this.lat_quant / this.scale;
var temp = bt;
var bt = -tp;
var tp = -temp;
// modify for mercator-projected tiles:
tp = 180/PI * (2 * Math.atan(Math.exp(tp * PI / 180)) - PI / 2);
bt = 180/PI * (2 * Math.atan(Math.exp(bt * PI / 180)) - PI / 2);
// make a key
var key = this.url + "?WIDTH="+(this.tilewidth)+"&HEIGHT="+
(this.tileheight)+"&BBOX="+lt+","+tp+","+rt+","+bt;
// see if our tile is already present
var node = document.getElementById(key);
// create if not present
if(!node)
{
if( this.debug > 0)
{
node = document.createElement('div');
}
else
{
node = document.createElement('img');
}
node.id = key;
node.className = 'tile';
node.style.position = 'absolute';
node.style.width = this.tilewidth + 'px';
node.style.height = this.tileheight + 'px';
node.style.left = containerx + 'px';
node.style.top = containery + 'px';
node.style.zIndex = 10; // to appear under the rss elements
node.tile_engine = this;
if( this.debug > 0)
{
node.style.border = "1px solid yellow";
node.innerHTML = key;
if( this.debug > 1 )
{
var img = document.createElement('img');
img.src = key;
node.appendChild(img);
}
}
var goURL = key + "&zoom=" + this.zoom;
for(var k in this.urlAttr)
{
goURL += "&"+k+"="+this.urlAttr[k];
}
node.src = goURL;
node.alt = "loading tile..";
node.style.color = "#ffffff";
this.tiles.appendChild(node);
}
// adjust if using active style
else if( !this.dragcontainer ) {
node.style.left = containerx + 'px';
node.style.top = containery + 'px';
}
containery += this.tileheight;
}
containery = containeryreset;
containerx += this.tilewidth;
}
}
this.zoomTo = function(zoom)
{
this.zoom = zoom;
if (this.zoom < this.minzoom) { this.zoom = this.minzoom; }
if (this.zoom > this.maxzoom) { this.zoom = this.maxzoom; }
///
/// immediately draw and or fit to feed
///
this.performzoom(this.lon,this.lat,zoom);
this.drag(0,0);
///
} // CLOSE ZOOM FUNCTION
this.setLatLon = function(lat,lon)
{
this.lon=lon;
this.lat=mercatorlat(lat);
this.clean();
this.performzoom(lon,mercatorlat(lat),this.zoom);
this.drag(0,0);
}
this.forceRefresh = function()
{
this.clean();
this.performzoom(this.lon,this.lat,this.zoom);
this.drag(0,0);
}
///
/// zoom a tile group
///
this.tile_engine_zoomout = function()
{
this.clean();
this.zoomTo(this.zoom-1);
return false; // or safari falls over
}
///
/// zoom a tile group
///
this.tile_engine_zoomin = function()
{
this.clean();
this.zoomTo(this.zoom+1);
return false; // or safari falls over
}
this.setURL=function(url) { this.url=url; }
///
/// intercept context events to minimize out-of-browser interruptions
///
this.event_context = function(e)
{
return false;
}
///
/// keys
///
this.event_key = function(e)
{
var key = 0;
var hostengine = defaultEngine;
if( window && window.event && window.event.srcElement ) {
hostengine = window.event.srcElement.tile_engine;
} else if( e.target ) {
hostengine = e.target.tile_engine;
} else if( e.srcElement ) {
hostengine = e.srcElement.tile_engine;
}
if( hostengine == null ) {
hostengine = defaultEngine;
if( hostengine == null ) {
return;
}
}
if( e == null && document.all ) {
e = window.event;
}
if( e ) {
if( e.keyCode ) {
key = e.keyCode;
}
else if( e.which ) {
key = e.which;
}
switch(key) {
case 97: // a = left
hostengine.drag(16,0);
break;
case 100: // d = right
hostengine.drag(-16,0);
break;
case 119: // w = up
hostengine.drag(0,16);
break;
case 120: // x = dn
hostengine.drag(0,-16);
break;
case 115: // s = center
new tile_engine_new(hostengine.parentname,
"FULL",
hostengine.feedurl, // xxx hrm, cache this?
hostengine.url,
hostengine.lon,
hostengine.lat,
hostengine.zoom,
0,0
);
break;
case 122: // z = zoom
new tile_engine_new(hostengine.parentname,
"FULL",
hostengine.feedurl, // xxx hrm, cache this?
hostengine.url,
hostengine.lon,
hostengine.lat,
hostengine.zoom + 1,
0,0
);
break;
case 99: // c = unzoom
new tile_engine_new(hostengine.parentname,
"FULL",
hostengine.feedurl, // xxx hrm, cache this?
hostengine.url,
hostengine.lon,
hostengine.lat,
hostengine.zoom - 1,
0,0
);
break;
}
}
}
///
/// catch mouse move events
/// this routine _must_ return false or else the operating system outside-of-browser-scope drag and drop handler will interfere
///
this.event_mouse_move = function(e) {
var hostengine = null;
if( window && window.event && window.event.srcElement ) {
hostengine = window.event.srcElement.tile_engine;
} else if( e.target ) {
hostengine = e.target.tile_engine;
} else if( e.srcElement ) {
hostengine = e.srcElement.tile_engine;
}
if( hostengine && hostengine.drag ) {
if( hostengine.mousedown ) {
if( netscape ) {
hostengine.mousex = parseInt(e.pageX) + 0.0;
hostengine.mousey = parseInt(e.pageY) + 0.0;
} else {
hostengine.mousex = parseInt(window.event.clientX) + 0.0;
hostengine.mousey = parseInt(window.event.clientY) + 0.0;
}
hostengine.drag(hostengine.mousex-hostengine.lastmousex,hostengine.mousey-hostengine.lastmousey);
}
hostengine.lastmousex = hostengine.mousex;
hostengine.lastmousey = hostengine.mousey;
}
// must return false to prevent operating system drag and drop from handling events
return false;
}
///
/// catch mouse down
///
this.event_mouse_down = function(e) {
var hostengine = null;
if( window && window.event && window.event.srcElement ) {
hostengine = window.event.srcElement.tile_engine;
} else if( e.target ) {
hostengine = e.target.tile_engine;
} else if( e.srcElement ) {
hostengine = e.srcElement.tile_engine;
}
if( hostengine ) {
if( netscape ) {
hostengine.mousex = parseInt(e.pageX) + 0.0;
hostengine.mousey = parseInt(e.pageY) + 0.0;
} else {
hostengine.mousex = parseInt(window.event.clientX) + 0.0;
hostengine.mousey = parseInt(window.event.clientY) + 0.0;
}
hostengine.lastmousex = hostengine.mousex;
hostengine.lastmousey = hostengine.mousey;
hostengine.mousedown = 1;
}
// must return false to prevent operating system drag and drop from handling events
return false;
}
///
/// catch double click (use to center map)
///
this.event_double_click = function(e) {
var hostengine = null;
if( window && window.event && window.event.srcElement ) {
hostengine = window.event.srcElement.tile_engine;
} else if( e.target ) {
hostengine = e.target.tile_engine;
} else if( e.srcElement ) {
hostengine = e.srcElement.tile_engine;
}
if( hostengine ) {
if( netscape ) {
hostengine.mousex = parseInt(e.pageX) + 0.0;
hostengine.mousey = parseInt(e.pageY) + 0.0;
} else {
hostengine.mousex = parseInt(window.event.clientX) + 0.0;
hostengine.mousey = parseInt(window.event.clientY) + 0.0;
}
var dx = hostengine.mousex-(hostengine.displaywidth/2)-hostengine.parent_x;
var dy = hostengine.mousey-(hostengine.displayheight/2)-hostengine.parent_y;
hostengine.drag(-dx,-dy); // TODO smooth
}
// must return false to prevent operating system drag and drop from handling events
return false;
}
///
/// catch mouse up
///
this.event_mouse_up = function(e) {
var hostengine = null;
if( window && window.event && window.event.srcElement ) {
hostengine = window.event.srcElement.tile_engine;
} else if( e.target ) {
hostengine = e.target.tile_engine;
} else if( e.srcElement ) {
hostengine = e.srcElement.tile_engine;
}
if( hostengine ) {
if( netscape ) {
hostengine.mousex = parseInt(e.pageX) + 0.0;
hostengine.mousey = parseInt(e.pageY) + 0.0;
} else {
hostengine.mousex = parseInt(window.event.clientX) + 0.0;
hostengine.mousey = parseInt(window.event.clientY) + 0.0;
}
hostengine.mousedown = 0;
}
// must return false to prevent operating system drag and drop from handling events
return false;
}
///
/// catch mouse out
///
this.event_mouse_out = function(e) {
var hostengine = null;
if( window && window.event && window.event.srcElement ) {
hostengine = window.event.srcElement.tile_engine;
} else if( e.target ) {
hostengine = e.target.tile_engine;
} else if( e.srcElement ) {
hostengine = e.srcElement.tile_engine;
}
if( hostengine ) {
if( netscape ) {
hostengine.mousex = parseInt(e.pageX) + 0.0;
hostengine.mousey = parseInt(e.pageY) + 0.0;
} else {
hostengine.mousex = parseInt(window.event.clientX) + 0.0;
hostengine.mousey = parseInt(window.event.clientY) + 0.0;
}
hostengine.mousedown = 0;
}
// must return false to prevent operating system drag and drop from handling events
return false;
}
///
/// register new handlers to catch desired events
///
// NW removed parameter - always use parent
this.event_catch = function() {
this.parent.style.cursor = 'move';
if( netscape ) {
window.captureEvents(Event.MOUSEMOVE);
window.captureEvents(Event.KEYPRESS);
}
this.parent.onmousemove = this.event_mouse_move;
this.parent.onmousedown = this.event_mouse_down;
this.parent.onmouseup = this.event_mouse_up;
this.parent.onkeypress = this.event_key;
window.ondblclick = this.event_double_click;
if( window ) {
window.onmousemove = this.event_mouse_move;
window.onmouseup = this.event_mouse_up;
window.ondblclick = this.event_double_click;
}
}
this.setURLAttribute = function(k,v)
{
this.urlAttr[k] = v;
}
this.getURLAttribute = function(k)
{
return this.urlAttr[k];
}
this.getDownloadedTileBounds = function()
{
var bounds = new Array();
bounds.w=this.lon_min;
bounds.s=normallat(this.lat_min);
bounds.e=this.lon_max;
bounds.n=normallat(this.lat_max);
return bounds;
}
this.getVisibleBounds = function()
{
var bounds = new Array();
bounds.w = this.xToLon(0);
bounds.s = this.yToLat(this.theheight);
bounds.e = this.xToLon(this.thewidth);
bounds.n = this.yToLat(0);
return bounds;
}
// navout and navin stuff - START
// draw navigation buttons into the parent div
// ENTRY CODE BEGINS HERE....
// get parent div or fail
this.parent = document.getElementById(parentname);
if( this.parent == null ) {
alert('The tile map engine cannot find a parent container named ['
+parentname+']');
return;
}
//
// store for later
//
this.parentname = parentname;
this.hints = hints;
this.feedurl = feedurl;
this.url = url;
this.lon = lon;
this.lat = mercatorlat(lat);
this.thewidth = w;
this.theheight = h;
this.dragcontainer = 1;
this.debug = 0;
// for firefox keyboard
defaultEngine = this;
document.engine = this;
//
// decide on display width and height
//
if( !w || !h )
{
w = parseInt(this.parent.style.width);
h = parseInt(this.parent.style.height);
if(!w || !h)
{
w = 512;
h = 256;
this.parent.style.width = w + 'px';
this.parent.style.height = h + 'px';
}
}
else
{
this.parent.style.width = parseInt(w) + 'px';
this.parent.style.height = parseInt(h) + 'px';
}
this.displaywidth = w;
this.displayheight = h;
this.minzoom = 0;
this.maxzoom = 20;
//
// enforce parent div style?
// position absolute is really only required for firefox
// http://www.quirksmode.org/js/findpos.html
//
this.parent_x = getCSSPositionX(this.parent);
this.parent_y = getCSSPositionY(this.parent);
this.parent.style.position = 'relative';
this.parent.style.overflow = 'hidden';
this.parent.style.backgroundColor = '#000036';
// attach event capture parent div
this.event_catch();
this.clean();
//this.makeZoom();
this.zoomTo(zoom);
}
function normallat(mercatorlat)
{
var tp = 180/PI*(2 * Math.atan(Math.exp(mercatorlat * PI / 180)) - PI / 2);
return tp;
}
function mercatorlat(normallat)
{
var lpi = 3.14159265358979323846;
return Math.log( Math.tan( (lpi / 4.0) + (normallat / 180.0 * lpi / 2.0))) *
180.0 / lpi ;
}

View file

@ -1 +1,2 @@
# See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file
User-agent: *
Disallow: /api/