From b4c0bfd8fa324a4c9d8b24e8753d134524ea61c7 Mon Sep 17 00:00:00 2001 From: Steve Coast Date: Fri, 28 Jul 2006 21:53:30 +0000 Subject: [PATCH 1/1] more basic framework --- README | 181 +---- app/controllers/application.rb | 4 + app/controllers/trace_controller.rb | 2 + app/controllers/trace_points_controller.rb | 2 + app/controllers/user_controller.rb | 6 + app/helpers/application_helper.rb | 3 + app/helpers/trace_helper.rb | 2 + app/helpers/trace_points_helper.rb | 2 + app/helpers/user_helper.rb | 2 + app/models/trace.rb | 4 + app/models/trace_points.rb | 4 + app/models/user.rb | 3 + app/views/layouts/user.rhtml | 22 + app/views/user/new.rhtml | 4 + public/index.html | 274 +------ public/javascripts/main.js | 72 ++ public/javascripts/pngfix.js | 25 + public/javascripts/site.js | 28 + public/javascripts/tile.js | 889 +++++++++++++++++++++ public/robots.txt | 3 +- 20 files changed, 1084 insertions(+), 448 deletions(-) create mode 100644 app/controllers/application.rb create mode 100644 app/controllers/trace_controller.rb create mode 100644 app/controllers/trace_points_controller.rb create mode 100644 app/controllers/user_controller.rb create mode 100644 app/helpers/application_helper.rb create mode 100644 app/helpers/trace_helper.rb create mode 100644 app/helpers/trace_points_helper.rb create mode 100644 app/helpers/user_helper.rb create mode 100644 app/models/trace.rb create mode 100644 app/models/trace_points.rb create mode 100644 app/models/user.rb create mode 100644 app/views/layouts/user.rhtml create mode 100644 app/views/user/new.rhtml create mode 100644 public/javascripts/main.js create mode 100644 public/javascripts/pngfix.js create mode 100644 public/javascripts/site.js create mode 100644 public/javascripts/tile.js diff --git a/README b/README index b8e356925..74c8ed145 100644 --- a/README +++ b/README @@ -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: ruby script/server (run with --help for options) -2. Go to http://localhost:3000/ and get "Welcome aboard: You’re 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 - - - ServerName rails - DocumentRoot /path/application/public/ - ErrorLog /path/application/log/server.log - - - Options ExecCGI FollowSymLinks - AllowOverride all - Allow from all - Order allow,deny - - - -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 - => "[#nil, \"body\"=>nil, \"id\"=>\"1\"}>, - #\"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 - => #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 script/console production. - - -== 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. diff --git a/app/controllers/application.rb b/app/controllers/application.rb new file mode 100644 index 000000000..537de40d7 --- /dev/null +++ b/app/controllers/application.rb @@ -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 \ No newline at end of file diff --git a/app/controllers/trace_controller.rb b/app/controllers/trace_controller.rb new file mode 100644 index 000000000..7420ea52d --- /dev/null +++ b/app/controllers/trace_controller.rb @@ -0,0 +1,2 @@ +class TraceController < ApplicationController +end diff --git a/app/controllers/trace_points_controller.rb b/app/controllers/trace_points_controller.rb new file mode 100644 index 000000000..be34cd282 --- /dev/null +++ b/app/controllers/trace_points_controller.rb @@ -0,0 +1,2 @@ +class TracePointsController < ApplicationController +end diff --git a/app/controllers/user_controller.rb b/app/controllers/user_controller.rb new file mode 100644 index 000000000..da27a95dc --- /dev/null +++ b/app/controllers/user_controller.rb @@ -0,0 +1,6 @@ +class UserController < ApplicationController + + def new + + end +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb new file mode 100644 index 000000000..22a7940eb --- /dev/null +++ b/app/helpers/application_helper.rb @@ -0,0 +1,3 @@ +# Methods added to this helper will be available to all templates in the application. +module ApplicationHelper +end diff --git a/app/helpers/trace_helper.rb b/app/helpers/trace_helper.rb new file mode 100644 index 000000000..278c6c4b2 --- /dev/null +++ b/app/helpers/trace_helper.rb @@ -0,0 +1,2 @@ +module TraceHelper +end diff --git a/app/helpers/trace_points_helper.rb b/app/helpers/trace_points_helper.rb new file mode 100644 index 000000000..0252b91fe --- /dev/null +++ b/app/helpers/trace_points_helper.rb @@ -0,0 +1,2 @@ +module TracePointsHelper +end diff --git a/app/helpers/user_helper.rb b/app/helpers/user_helper.rb new file mode 100644 index 000000000..0147c3fe6 --- /dev/null +++ b/app/helpers/user_helper.rb @@ -0,0 +1,2 @@ +module UserHelper +end diff --git a/app/models/trace.rb b/app/models/trace.rb new file mode 100644 index 000000000..a7e19bef8 --- /dev/null +++ b/app/models/trace.rb @@ -0,0 +1,4 @@ +class Trace < ActiveRecord::Base + set_table_name 'gpx_files' + has_many :trace_points, :foreign_key => 'gpx_id' +end diff --git a/app/models/trace_points.rb b/app/models/trace_points.rb new file mode 100644 index 000000000..56703a29e --- /dev/null +++ b/app/models/trace_points.rb @@ -0,0 +1,4 @@ +class TracePoints < ActiveRecord::Base + set_table_name 'gps_points' + belongs_to :trace, :foreign_key => 'gpx_id' +end diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 000000000..cfcbfd351 --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,3 @@ +class User < ActiveRecord::Base + has_many :traces +end diff --git a/app/views/layouts/user.rhtml b/app/views/layouts/user.rhtml new file mode 100644 index 000000000..1bd916a02 --- /dev/null +++ b/app/views/layouts/user.rhtml @@ -0,0 +1,22 @@ + + + <%= javascript_include_tag 'main.js' %> + + <%= javascript_include_tag 'tile.js' %> + <%= javascript_include_tag 'site.js' %> + + + + OpenStreetMap + + + <%= @content_for_layout %> + + diff --git a/app/views/user/new.rhtml b/app/views/user/new.rhtml new file mode 100644 index 000000000..4e1ca5f72 --- /dev/null +++ b/app/views/user/new.rhtml @@ -0,0 +1,4 @@ + +create a user + + diff --git a/public/index.html b/public/index.html index a2daab72b..b48454685 100644 --- a/public/index.html +++ b/public/index.html @@ -1,277 +1,5 @@ - - - - - Ruby on Rails: Welcome aboard - - - - - - -
- - -
- - - - -
-

Getting started

-

Here’s how to get rolling:

- -
    -
  1. -

    Create your databases and edit config/database.yml

    -

    Rails needs to know your login and password.

    -
  2. - -
  3. -

    Use script/generate to create your models and controllers

    -

    To see all available options, run it without parameters.

    -
  4. - -
  5. -

    Set up a default route and remove or rename this file

    -

    Routes are setup in config/routes.rb.

    -
  6. -
-
-
- - -
- - \ No newline at end of file diff --git a/public/javascripts/main.js b/public/javascripts/main.js new file mode 100644 index 000000000..fc888d4dd --- /dev/null +++ b/public/javascripts/main.js @@ -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); + */ +} diff --git a/public/javascripts/pngfix.js b/public/javascripts/pngfix.js new file mode 100644 index 000000000..0fdefc6b2 --- /dev/null +++ b/public/javascripts/pngfix.js @@ -0,0 +1,25 @@ +function correctPNG() // correctly handle PNG transparency in Win IE 5.5 or higher. +{ + for(var i=0; i 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 = "" + img.outerHTML = strNewHTML + i = i-1 + } + } +} +window.attachEvent("onload", correctPNG); diff --git a/public/javascripts/site.js b/public/javascripts/site.js new file mode 100644 index 000000000..75c3eb539 --- /dev/null +++ b/public/javascripts/site.js @@ -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'; + } + } +} diff --git a/public/javascripts/tile.js b/public/javascripts/tile.js new file mode 100644 index 000000000..069767dc9 --- /dev/null +++ b/public/javascripts/tile.js @@ -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 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 ; +} diff --git a/public/robots.txt b/public/robots.txt index 4ab9e89fe..d34624918 100644 --- a/public/robots.txt +++ b/public/robots.txt @@ -1 +1,2 @@ -# See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file \ No newline at end of file +User-agent: * +Disallow: /api/ -- 2.43.2