Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

fractional zoom and local tile cutter (php)

  • Loading branch information...
commit bcd6d7b45ded044d834fb277d3e7f9db1873ed9c 1 parent 4240299
@dfacts authored
View
49 examples/fractional-zoom.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html manifest="map.manifest">
+ <head>
+ <meta charset="utf-8">
+ <title>Slippy Map on Canvas (HTML5) | fractional zoom</title>
+ <meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=no;"/>
+ <meta name="apple-mobile-web-app-capable" content="yes" />
+ <link rel="apple-touch-icon-precomposed" href="../images/touch-icon.png" />
+ <link href="../css/map.css" rel="stylesheet" type="text/css" media="all" />
+ <link href="../css/ui.css" rel="stylesheet" type="text/css" media="all" />
+ <script src="../js/map.js" type="text/javascript"></script>
+ <script type="text/javascript">
+ app.preInitListeners.push(function(){
+ app.markers =
+ { 'Berlin' :
+ { src : "../images/marker.png",
+ lon : 13.409500,
+ lat : 52.522488,
+ offsetX : -11,
+ offsetY : -25
+ },
+ 'Moskva' :
+ { src : "../images/marker.png",
+ lon : 37.617633,
+ lat : 55.755786,
+ offsetX : -11,
+ offsetY : -25
+ },
+ 'Hong Kong' :
+ { src : "../images/marker.png",
+ lon : 114.10494,
+ lat : 22.381111,
+ offsetX : -11,
+ offsetY : -25
+ }
+ }
+ });
+ </script>
+ </head>
+ <body>
+ <canvas id="map">
+ Your browser doesn't support canvas elements.
+ </canvas>
+ <ul id="buttons">
+ <li><a class="zoomin" href="javascript:;" onclick="app.zoomIn(0.2, false); return false;">+</a></li>
+ <li><a class="zoomout" href="javascript:;" onclick="app.zoomOut(0.2, false); return false;">-</a></li>
+ </ul>
+ </body>
+</html>
View
7 examples/marker-feature-info.html
@@ -3,6 +3,13 @@
<head>
<meta charset="utf-8">
<title>Slippy Map on Canvas (HTML5) | simple path example</title>
+ <!--
+
+
+ does not work with fractional zoom - yet
+
+
+ -->
<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=no;"/>
<meta name="apple-mobile-web-app-capable" content="yes" />
<link rel="apple-touch-icon-precomposed" href="../images/touch-icon.png" />
View
8 examples/marker-path-gpx.html
@@ -45,14 +45,16 @@
}
}
app.preInitListeners.push(function(){
- drawPath = function(z,zp,sz,xMin,xMax,yMin,yMax){
+ drawPath = function(z, zp, sz, xMin, xMax, yMin, yMax, tilesize, diff){
+ var offsetX = Math.round((diff-1)*(xMax-xMin)/zp/2);
+ var offsetY = Math.round((diff-1)*(yMax-yMin)/zp/2);
function lon2x(lon){
- return Math.round((app.pos.lon2pos(lon)-xMin) / zp);
+ return Math.round((app.pos.lon2pos(lon)-xMin) / zp*diff)-offsetX;
}
function lat2y(lat){
- return Math.round((app.pos.lat2pos(lat)-yMin) / zp) ;
+ return Math.round((app.pos.lat2pos(lat)-yMin) / zp*diff)-offsetY;
}
for(t in tracks){
var track = tracks[t];
View
8 examples/marker-path.html
@@ -40,14 +40,16 @@
offsetY : -25
}
}
- drawPath = function(z,zp,sz,xMin,xMax,yMin,yMax){
+ drawPath = function(z,zp,sz,xMin,xMax,yMin,yMax, tilesize, diff){
+ var offsetX = Math.round((diff-1)*(xMax-xMin)/zp/2);
+ var offsetY = Math.round((diff-1)*(yMax-yMin)/zp/2);
function lon2x(lon){
- return Math.round((app.pos.lon2pos(lon)-xMin) / zp);
+ return Math.round((app.pos.lon2pos(lon)-xMin) / zp*diff)-offsetX;
}
function lat2y(lat){
- return Math.round((app.pos.lat2pos(lat)-yMin) / zp) ;
+ return Math.round((app.pos.lat2pos(lat)-yMin) / zp*diff)-offsetY;
}
for(t in tracks){
var track = tracks[t];
View
46 examples/tiles-local.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html manifest="map.manifest">
+ <head>
+ <meta charset="utf-8">
+ <title>Slippy Map on Canvas (HTML5) | tiles from local source</title>
+ <meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=no;"/>
+ <meta name="apple-mobile-web-app-capable" content="yes" />
+ <link rel="apple-touch-icon-precomposed" href="../images/touch-icon.png" />
+ <link href="../css/map.css" rel="stylesheet" type="text/css" media="all" />
+ <link href="../css/ui.css" rel="stylesheet" type="text/css" media="all" />
+ <script type="text/javascript">
+ var now = function(){
+ return (new Date()).getTime();
+ }
+ var srcImagePath = "marker.png";
+ document.addEventListener('DOMContentLoaded', function(){
+ app = window.app || {};
+ app.tiles = app.tiles || {};
+ app.tiles.local = {
+ init : function(){
+ console.log("switching");
+ app.tileprovider = app.tiles.local.tileprovider;
+ },
+ recenter : function(){
+ app.recenter(0,0,0);
+ },
+ tileprovider : function(x,y,z){
+ return "../tile.php?src="+srcImagePath+"&x="+x+"&y="+y+"&z="+z+"&format=png&timestamp="+now();
+ }
+ };
+ app.preInitListeners.push(app.tiles.local.init);
+ app.postInitListeners.push(app.tiles.local.recenter);
+ }, null);
+ </script>
+ <script src="../js/map.js" type="text/javascript"></script>
+ </head>
+ <body>
+ <canvas id="map">
+ Your browser doesn't support canvas elements.
+ </canvas>
+ <ul id="buttons">
+ <li><a class="zoomin" href="javascript:;" onclick="app.zoomIn(); return false;">+</a></li>
+ <li><a class="zoomout" href="javascript:;" onclick="app.zoomOut(); return false;">-</a></li>
+ </ul>
+ </body>
+</html>
View
86 js/map.js
@@ -40,16 +40,30 @@
var url = "http://" + sub[rand(3)] + ".tile.openstreetmap.org/" + z + "/" + x + "/" + y + ".png";
return url;
},
- zoomIn: function () {
+ useFractionalZoom : true,
+ zoomIn: function (step, round) {
+ console.log(round);
if ($.app.pos.z < $.app.renderer.maxZ) {
- ++$.app.pos.z;
+ $.app.pos.z += step || 1;
+ if(round !== false) {
+ $.app.pos.z = $.Math.round($.app.pos.z);
+ }
+ if($.app.pos.z > $.app.renderer.maxZ) {
+ $.app.pos.z = $.app.renderer.maxZ;
+ }
$.app.renderer.refresh();
$.app.zoomed();
}
},
- zoomOut: function () {
+ zoomOut: function (step, round) {
if ($.app.pos.z > 0) {
- --$.app.pos.z;
+ $.app.pos.z -= step || 1;
+ if(round !== false) {
+ $.app.pos.z = $.Math.round($.app.pos.z);
+ }
+ if($.app.pos.z<0) {
+ $.app.pos.z = 0;
+ }
$.app.renderer.refresh();
$.app.zoomed();
}
@@ -57,7 +71,7 @@
recenter: function(lon,lat,zoom){
$.app.pos.x = $.app.pos.lon2pos(lon);
$.app.pos.y = $.app.pos.lat2pos(lat);
- if(zoom>0) $.app.pos.z = zoom;
+ if(zoom>=0) $.app.pos.z = zoom;
$.app.renderer.refresh();
},
/* keep track of zoom + pans */
@@ -137,11 +151,11 @@
delta = -event.detail / 3;
}
if (delta > 0) {
- $.app.zoomIn();
+ $.app.zoomIn(delta/100, false);
$.app.zoomed();
} else if (delta < 0) {
- $.app.zoomOut();
+ $.app.zoomOut(-delta/100, false);
$.app.zoomed();
}
},
@@ -157,7 +171,7 @@
$.app.pos.y += dY * $.Math.pow(2, $.app.renderer.maxZ - $.app.pos.z);
$.app.events.lastMouseX = x;
$.app.events.lastMouseY = y;
- $.app.zoomIn();
+ $.app.zoomIn(1, true);
},
/* maps touch events to mouse events */
touchHandler: function (event) {
@@ -205,11 +219,11 @@
var touches = event.changedTouches;
if (event.scale) {
if (event.scale > 1.5) {
- $.app.zoomIn();
+ $.app.zoomIn(0.1, false);
return true;
}
if (event.scale < 0.5) {
- $.app.zoomOut();
+ $.app.zoomOut(0.1, false);
return true;
}
}
@@ -251,7 +265,12 @@
id: 'tiles',
zindex: 0,
callback :
- function(z,zp,sz,xMin,xMax,yMin,yMax){
+ function(z,zp,sz,xMin,xMax,yMin,yMax, tilesize, zf){
+ $.app.renderer.context.fillStyle = "#dddddd";
+
+ var offsetX = $.Math.floor((zf-1)*(xMax-xMin)/zp/2);
+ var offsetY = $.Math.floor((zf-1)*(yMax-yMin)/zp/2);
+ var maxTileNumber = $.Math.pow(2,z)-1;
var encodeIndex = function (x, y, z) {
return x + "," + y + "," + z;
};
@@ -260,28 +279,41 @@
};
for (var x = $.Math.floor(xMin / sz); x < $.Math.ceil(xMax / sz); ++x) {
for (var y = $.Math.floor(yMin / sz); y < $.Math.ceil(yMax / sz); ++y) {
- var xoff = $.Math.round((x * sz - xMin) / zp);
- var yoff = $.Math.round((y * sz - yMin) / zp);
+ var xoff = $.Math.round((x * sz - xMin) / zp * zf)-offsetX;
+ var yoff = $.Math.round((y * sz - yMin) / zp * zf)-offsetY;
+
var tileKey = encodeIndex(x, y, z);
+ var tileKeyAbove = encodeIndex($.Math.floor(x/2), $.Math.floor(y/2), z-1);
+ if(x>maxTileNumber || y>maxTileNumber || x<0 || y<0){
+ $.app.renderer.context.fillStyle = "#dddddd";
+ $.app.renderer.context.fillRect(xoff, yoff, tilesize, tilesize);
+
+ } else {
if ($.app.renderer.tiles[tileKey] && $.app.renderer.tiles[tileKey].complete) {
try {
- $.app.renderer.context.drawImage($.app.renderer.tiles[tileKey], xoff, yoff);
+ $.app.renderer.context.drawImage($.app.renderer.tiles[tileKey], xoff, yoff, tilesize, tilesize);
} catch (e) {
$.app.renderer.context.fillStyle = "#dddddd";
- $.app.renderer.context.fillRect(xoff, yoff, $.app.renderer.tilesize, $.app.renderer.tilesize);
+ $.app.renderer.context.fillRect(xoff, yoff, tilesize, tilesize);
}
$.app.renderer.tiles[tileKey].lastDrawn = now();
- }
- else {
+ } else {
+ if ($.app.renderer.tiles[tileKeyAbove] && $.app.renderer.tiles[tileKeyAbove].complete){
+ var tileOffsetX = xoff-$.Math.floor((x-$.Math.ceil(x/2)*2)*tilesize*2);
+ var tileOffsetY = yoff-$.Math.floor((y-$.Math.ceil(y/2)*2)*tilesize*2);
+ $.app.renderer.context.drawImage($.app.renderer.tiles[tileKeyAbove], tileOffsetX, tileOffsetY,$.Math.ceil(2*tilesize), $.Math.ceil(2*tilesize));
+ } else {
+ $.app.renderer.context.fillStyle = "#dddddd";
+ $.app.renderer.context.fillRect(xoff, yoff, tilesize, tilesize);
+ }
if (!$.app.renderer.tiles[tileKey]) {
$.app.renderer.tiles[tileKey] = new Image();
- $.app.renderer.tiles[tileKey].src = $.app.tileprovider(x, y, $.app.pos.z, $.app.renderer.tiles[tileKey]);
+ $.app.renderer.tiles[tileKey].src = $.app.tileprovider(x, y, z, $.app.renderer.tiles[tileKey]);
$.app.renderer.tiles[tileKey].onload = function(){
$.app.renderer.refresh();
}
}
- $.app.renderer.context.fillStyle = "#dddddd";
- $.app.renderer.context.fillRect(xoff, yoff, $.app.renderer.tilesize, $.app.renderer.tilesize);
+ }
}
}
}
@@ -291,11 +323,13 @@
id: 'marker',
zindex: 99,
callback :
- function(z,zp,sz,xMin,xMax,yMin,yMax){
+ function(z,zp,sz,xMin,xMax,yMin,yMax, tilesize, zf){
+ var offsetX = $.Math.round((zf-1)*(xMax-xMin)/zp/2);
+ var offsetY = $.Math.round((zf-1)*(yMax-yMin)/zp/2);
for(var marker in $.app.markers){
if($.app.markers[marker].img && $.app.markers[marker].img.complete){
- x = $.Math.round(($.app.pos.lon2pos($.app.markers[marker].lon)-xMin) / zp) + $.app.markers[marker].offsetX;
- y = $.Math.round(($.app.pos.lat2pos($.app.markers[marker].lat)-yMin) / zp) + $.app.markers[marker].offsetY;
+ x = $.Math.round(($.app.pos.lon2pos($.app.markers[marker].lon)-xMin) / zp * zf) + $.app.markers[marker].offsetX - offsetX;
+ y = $.Math.round(($.app.pos.lat2pos($.app.markers[marker].lat)-yMin) / zp * zf) + $.app.markers[marker].offsetY - offsetY;
if(x>-50 && x<$.app.renderer.canvas.width+50 && y>-50 && y<$.app.renderer.canvas.height+50){
try {
$.app.renderer.context.drawImage($.app.markers[marker].img, x, y);
@@ -329,16 +363,19 @@
return (new $.Date()).getTime();
};
var z = $.app.pos.z;
+ var zf = $.app.useFractionalZoom?(1+z-parseInt(z)):1;
+ z = parseInt(z);
var zp = $.Math.pow(2, $.app.renderer.maxZ - z);
var w = $.app.renderer.canvas.width * zp;
var h = $.app.renderer.canvas.height * zp;
var sz = $.app.renderer.tilesize * zp;
+ var tilesize = $.Math.ceil($.app.renderer.tilesize*zf);
var xMin = $.app.pos.x - w / 2;
var yMin = $.app.pos.y - h / 2;
var xMax = $.app.pos.x + w / 2;
var yMax = $.app.pos.y + h / 2;
for (l in $.app.renderer.layers) {
- $.app.renderer.layers[l].callback(z,zp,sz,xMin,xMax,yMin,yMax);
+ $.app.renderer.layers[l].callback(z,zp,sz,xMin,xMax,yMin,yMax,tilesize, zf);
}
for (var i = 0; i < $.app.renderer.refreshListeners.length; i++) {
$.app.renderer.refreshListeners[i]();
@@ -349,6 +386,7 @@
refreshListeners : {},
/* garbage collector */
garbage: function () {
+ return;
if ($.app.renderer.tiles) {
var remove = [];
for (var key in $.app.renderer.tiles) {
View
149 tile.php
@@ -0,0 +1,149 @@
+<?php
+
+/**
+ * tileMaker 0.01
+ *
+ * Copyright 2010 Gerhard Koch
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @author Gerhard Koch <gerhard.koch AT ymail.com>
+ *
+ * WHAT IT DOES:
+ *
+ * cuts tiles from images on demand - uses a lot of resources (!)
+ * uses cache dir if available and writable.
+ * reads images from directory "images"
+ * delivers "images/black.gif" for off boundary x,y parameters
+ *
+ * USAGE:
+ *
+ * tile.php?src=IMAGEPATH&x=X&y=Y&z=Z&format=FORMAT
+ *
+ */
+
+error_reporting(0);
+ini_set('display_errors','off');
+
+/* some constants/ default */
+$cache_dir = "cache"; // must be 0777
+$tileSize = 256;
+$srcImgCreateFunctions = array(
+ IMAGETYPE_GIF => 'imagecreatefromgif',
+ IMAGETYPE_JPEG => 'imagecreatefromjpeg',
+ IMAGETYPE_PNG => 'imagecreatefrompng',
+);
+$tileImgCreateFunctions = array(
+ 'gif' => 'imagegif',
+ 'jpg' => 'imagejpeg',
+ 'jpeg' => 'imagejpeg',
+ 'png' => 'imagepng'
+);
+
+$tileImgMimeTypes = array(
+ 'gif' => 'image/gif',
+ 'jpg' => 'image/jpeg',
+ 'jpeg' => 'image/jpeg',
+ 'png' => 'image/png'
+);
+
+$tileImgExtension = array(
+ 'gif' => 'gif',
+ 'jpg' => 'jpg',
+ 'jpeg' => 'jpg',
+ 'png' => 'png'
+);
+
+
+/* process parameter */
+$srcImgFilename = basename($_REQUEST["src"]);
+$srcImgPath = "images/".$srcImgFilename;
+$cacheName = array_shift(explode(".",$srcImgFilename));
+
+$tileImgFormat = isset($_REQUEST["format"])?$_REQUEST["format"]:'';
+if(!in_array($tileImgFormat, array("gif","jpg","jpeg","png"))){
+ $tileImgFormat = 'jpg';
+}
+$tileX = isset($_REQUEST["x"])?intval($_REQUEST["x"]):0;
+$tileY = isset($_REQUEST["y"])?intval($_REQUEST["y"]):0;
+$tileZ = isset($_REQUEST["z"])?intval($_REQUEST["z"]):0;
+
+
+if($tileZ<0) die("z must be >= 0");
+
+$tileNumber = pow(2,$tileZ);
+
+if($tileX<0 || $tileY<0 || $tileX>$tileNumber || $tileY>$tileNumber){
+ header('Content-type: image/gif');
+ readfile("images/black.gif");
+ exit();
+}
+
+$cacheImgPath = $cache_dir."/".$cacheName."/".$tileZ."/".$tileX."/".$tileY.".".$tileImgExtension[$tileImgFormat];
+
+if(@file_exists($cacheImgPath)){
+ header('Content-type: '.$tileImgMimeTypes[$tileImgFormat]);
+ readfile($cacheImgPath);
+ exit();
+}
+
+
+/* load src */
+if(!@file_exists($srcImgPath)) die('src not found');
+$srcImgInfo = @getimagesize($srcImgPath);
+if(!$srcImgInfo) die('cannot get image info');
+
+
+if(!$srcImgCreateFunctions[$srcImgInfo[2]]) die('cannot get image type');
+if(!function_exists($srcImgCreateFunctions[$srcImgInfo[2]])) die('unknown image type');
+$srcImgResource = $srcImgCreateFunctions[$srcImgInfo[2]]($srcImgPath);
+
+/* create tile */
+$tileImgResource = imagecreatetruecolor($tileSize, $tileSize);
+
+$srcClipping = (($srcImgInfo[0]>$srcImgInfo[1])?$srcImgInfo[0]:$srcImgInfo[1])/$tileNumber;
+
+$srcXmin = round(($tileX)*$srcClipping);
+$srcYmin = round(($tileY)*$srcClipping);
+
+imagecopyresampled( $tileImgResource, $srcImgResource,
+ 0, 0,
+ $srcXmin, $srcYmin,
+ $tileSize, $tileSize,
+ $srcClipping, $srcClipping
+);
+/* please... tidy! */
+if(is_dir($cache_dir)){
+ @mkdir($cache_dir."/".$cacheName);
+ @chmod($cache_dir."/".$cacheName,0777);
+ if(is_dir($cache_dir."/".$cacheName)){
+ @mkdir($cache_dir."/".$cacheName."/".$tileZ);
+ @chmod($cache_dir."/".$cacheName."/".$tileZ, 0777);
+ if(is_dir($cache_dir."/".$cacheName."/".$tileZ)){
+ @mkdir($cache_dir."/".$cacheName."/".$tileZ."/".$tileX);
+ @chmod($cache_dir."/".$cacheName."/".$tileZ."/".$tileX, 0777);
+ if(is_dir($cache_dir."/".$cacheName."/".$tileZ."/".$tileX)){
+ $tileImgCreateFunctions[$tileImgFormat]($tileImgResource,
+ $cache_dir."/".$cacheName."/".$tileZ."/".$tileX."/".$tileY.".".
+ $tileImgExtension[$tileImgFormat]
+ );
+ chmod($cache_dir."/".$cacheName."/".$tileZ."/".$tileX."/".$tileY.".".
+ $tileImgExtension[$tileImgFormat]
+ ,0666);
+ }
+ }
+ }
+}
+
+header('Content-type: '.$tileImgMimeTypes[$tileImgFormat]);
+print $tileImgCreateFunctions[$tileImgFormat]($tileImgResource);
Please sign in to comment.
Something went wrong with that request. Please try again.