diff --git a/.gitignore b/.gitignore index 9f11b75..75b2efc 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .idea/ +vendor diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..7768bfb --- /dev/null +++ b/composer.json @@ -0,0 +1,26 @@ +{ + "name": "calderacc/staticmaplite", + "type": "library", + "license": "Apache", + "authors": [ + { + "name": "Gerhard Koch", + "email": "gerhard.koch@ymail.com" + }, + { + "name": "Malte Hübner", + "email": "maltehuebner@gmx.org" + } + ], + "autoload": { + "psr-4": { + "StaticMapLite\\": "src" + } + }, + "minimum-stability": "stable", + "require": { + "emcconville/google-map-polyline-encoding-tool": "^1.3", + "curl/curl": "^1.6", + "imagine/imagine": "^0.7.1" + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..ab086b4 --- /dev/null +++ b/composer.lock @@ -0,0 +1,176 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "content-hash": "11486d8639a42e3b06c8b99e7ff5061a", + "packages": [ + { + "name": "curl/curl", + "version": "1.6.1", + "source": { + "type": "git", + "url": "https://github.com/php-mod/curl.git", + "reference": "96f5bd47bab8d76f1883c257c6659091987ef662" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-mod/curl/zipball/96f5bd47bab8d76f1883c257c6659091987ef662", + "reference": "96f5bd47bab8d76f1883c257c6659091987ef662", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "3.7.*", + "squizlabs/php_codesniffer": "~2.1" + }, + "type": "library", + "autoload": { + "psr-0": { + "Curl": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Hassan Amouhzi", + "email": "hassan@anezi.net", + "homepage": "http://hassan.amouhzi.com" + }, + { + "name": "php-curl-class", + "homepage": "https://github.com/php-curl-class" + }, + { + "name": "user52", + "homepage": "https://github.com/user52" + } + ], + "description": "cURL class for PHP", + "homepage": "https://github.com/php-mod/curl", + "keywords": [ + "curl", + "dot" + ], + "time": "2017-04-03T15:04:35+00:00" + }, + { + "name": "emcconville/google-map-polyline-encoding-tool", + "version": "v1.3", + "source": { + "type": "git", + "url": "https://github.com/emcconville/google-map-polyline-encoding-tool.git", + "reference": "dbf3816936620b88f0fc4000fddd94b5ce13eadb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/emcconville/google-map-polyline-encoding-tool/zipball/dbf3816936620b88f0fc4000fddd94b5ce13eadb", + "reference": "dbf3816936620b88f0fc4000fddd94b5ce13eadb", + "shasum": "" + }, + "require": { + "php": ">=5.3" + }, + "require-dev": { + "phpunit/phpunit": "4.1.*", + "satooshi/php-coveralls": "dev-master", + "squizlabs/php_codesniffer": "2.0.0a2" + }, + "type": "library", + "autoload": { + "files": [ + "src/Polyline.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GNU" + ], + "authors": [ + { + "name": "Eric McConville", + "email": "emcconville@emcconville.com" + } + ], + "description": "A simple class to handle polyline-encoding for Google Maps", + "keywords": [ + "google", + "maps" + ], + "time": "2016-04-05T01:18:39+00:00" + }, + { + "name": "imagine/imagine", + "version": "v0.7.1", + "source": { + "type": "git", + "url": "https://github.com/avalanche123/Imagine.git", + "reference": "a9a702a946073cbca166718f1b02a1e72d742daa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/avalanche123/Imagine/zipball/a9a702a946073cbca166718f1b02a1e72d742daa", + "reference": "a9a702a946073cbca166718f1b02a1e72d742daa", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "sami/sami": "^3.3", + "symfony/phpunit-bridge": "^3.2" + }, + "suggest": { + "ext-gd": "to use the GD implementation", + "ext-gmagick": "to use the Gmagick implementation", + "ext-imagick": "to use the Imagick implementation" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-develop": "0.7-dev" + } + }, + "autoload": { + "psr-0": { + "Imagine": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bulat Shakirzyanov", + "email": "mallluhuct@gmail.com", + "homepage": "http://avalanche123.com" + } + ], + "description": "Image processing for PHP 5.3", + "homepage": "http://imagine.readthedocs.org/", + "keywords": [ + "drawing", + "graphics", + "image manipulation", + "image processing" + ], + "time": "2017-05-16T10:31:22+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [] +} diff --git a/fonts/fontawesome-webfont.ttf b/fonts/fontawesome-webfont.ttf new file mode 100644 index 0000000..35acda2 Binary files /dev/null and b/fonts/fontawesome-webfont.ttf differ diff --git a/images/extramarkers.png b/images/extramarkers.png new file mode 100644 index 0000000..35ff61b Binary files /dev/null and b/images/extramarkers.png differ diff --git a/src/Canvas/Canvas.php b/src/Canvas/Canvas.php new file mode 100644 index 0000000..0d5217c --- /dev/null +++ b/src/Canvas/Canvas.php @@ -0,0 +1,79 @@ +width = $width; + $this->height = $height; + + $this->zoom = $zoom; + + $this->centerX = $centerX; + $this->centerY = $centerY; + + $imagine = new \Imagine\Gd\Imagine(); + $size = new \Imagine\Image\Box($this->width, $this->height); + $this->image = $imagine->create($size); + } + + public function getImage(): ImageInterface + { + return $this->image; + } + + public function getWidth(): int + { + return $this->width; + } + + public function getHeight(): int + { + return $this->height; + } + + public function getCenterX(): float + { + return $this->centerX; + } + + public function getCenterY(): float + { + return $this->centerY; + } + + public function getZoom(): int + { + return $this->zoom; + } + + public function getTileSize(): int + { + return $this->tileSize; + } +} diff --git a/src/Canvas/CanvasInterface.php b/src/Canvas/CanvasInterface.php new file mode 100644 index 0000000..57c86f3 --- /dev/null +++ b/src/Canvas/CanvasInterface.php @@ -0,0 +1,16 @@ +canvas = $canvas; + + return $this; + } + + public function setTileResolver(TileResolverInterface $tileResolver): CanvasTilePainter + { + $this->tileResolver = $tileResolver; + + return $this; + } + + protected function createTmpCanvasImage(): CanvasTilePainter + { + $tileSize = $this->canvas->getTileSize(); + + $size = new Box($this->canvas->getWidth() + 2 * $tileSize, $this->canvas->getHeight() + 2 * $tileSize); + + $imagine = new Imagine(); + $this->tmpCanvasImage = $imagine->create($size); + + return $this; + } + + protected function cropToCanvas(): CanvasTilePainter + { + $tmpTopLeftPoint = new Point(256, 256); + $this->tmpCanvasImage->crop($tmpTopLeftPoint, $this->canvas->getImage()->getSize()); + + $topLeftPoint = new Point(0, 0); + $this->canvas->getImage()->paste($this->tmpCanvasImage, $topLeftPoint); + + return $this; + } + + public function paint(): CanvasTilePainter + { + $this->createTmpCanvasImage(); + + $startX = floor($this->canvas->getCenterX() - ($this->canvas->getWidth() / $this->canvas->getTileSize()) / 2); + $startY = floor($this->canvas->getCenterY() - ($this->canvas->getHeight() / $this->canvas->getTileSize()) / 2); + $endX = ceil($this->canvas->getCenterX() + ($this->canvas->getWidth() / $this->canvas->getTileSize()) / 2); + $endY = ceil($this->canvas->getCenterY() + ($this->canvas->getHeight() / $this->canvas->getTileSize()) / 2); + + $offsetX = -floor(($this->canvas->getCenterX() - floor($this->canvas->getCenterX())) * $this->canvas->getTileSize()); + $offsetY = -floor(($this->canvas->getCenterY() - floor($this->canvas->getCenterY())) * $this->canvas->getTileSize()); + $offsetX += floor($this->canvas->getWidth() / 2); + $offsetY += floor($this->canvas->getHeight() / 2); + $offsetX += floor($startX - floor($this->canvas->getCenterX())) * $this->canvas->getTileSize(); + $offsetY += floor($startY - floor($this->canvas->getCenterY())) * $this->canvas->getTileSize(); + + $box = new Box(256, 256); + + for ($x = $startX; $x <= $endX; $x++) { + for ($y = $startY; $y <= $endY; $y++) { + $tileImage = $this->tileResolver->fetch($this->canvas->getZoom(), $x, $y); + + $destX = ($x - $startX) * $this->canvas->getTileSize() + $offsetX; + $destY = ($y - $startY) * $this->canvas->getTileSize() + $offsetY; + + $point = new Point($destX + 256, $destY + 256); + + if ($this->tmpCanvasImage->getSize()->contains($box, $point)) { + $this->tmpCanvasImage->paste($tileImage, $point); + } + } + } + + $this->cropToCanvas(); + + return $this; + } +} diff --git a/src/CanvasTilePainter/CanvasTilePainterInterface.php b/src/CanvasTilePainter/CanvasTilePainterInterface.php new file mode 100644 index 0000000..eab923d --- /dev/null +++ b/src/CanvasTilePainter/CanvasTilePainterInterface.php @@ -0,0 +1,13 @@ +canvas = $canvas; + + return $this; + } + + public function printCopyright(): CopyrightPrinterInterface + { + $imagine = new Imagine(); + $copyrightImage = $imagine->open($this->copyrightPath); + + $canvasSize = $this->canvas->getImage()->getSize(); + $copyrightSize = $copyrightImage->getSize(); + + $point = new Point($canvasSize->getWidth() - $copyrightSize->getWidth() - $this->offset,$canvasSize->getHeight() - $copyrightSize->getHeight() - $this->offset); + + $this->canvas->getImage()->paste($copyrightImage, $point); + + return $this; + } +} diff --git a/src/CopyrightPrinter/CopyrightPrinterInterface.php b/src/CopyrightPrinter/CopyrightPrinterInterface.php new file mode 100644 index 0000000..109799c --- /dev/null +++ b/src/CopyrightPrinter/CopyrightPrinterInterface.php @@ -0,0 +1,8 @@ +getShape($shape), $this->getColor($color), $this->getAwesome($icon), $latitude, $longitude); + } + + protected function getAwesome(string $icon): string + { + $icons = [ + 'glass' => 'f000', + 'music' => 'f001', + 'search' => 'f002', + 'envelope-o' => 'f003', + 'heart' => 'f004', + 'star' => 'f005', + 'star-o' => 'f006', + 'user' => 'f007', + 'film' => 'f008', + 'th-large' => 'f009', + 'th' => 'f00a', + 'th-list' => 'f00b', + 'check' => 'f00c', + 'times' => 'f00d', + 'search-plus' => 'f00e', + 'search-minus' => 'f010', + 'power-off' => 'f011', + 'signal' => 'f012', + 'cog' => 'f013', + 'trash-o' => 'f014', + 'home' => 'f015', + 'file-o' => 'f016', + 'clock-o' => 'f017', + 'road' => 'f018', + 'download' => 'f019', + 'arrow-circle-o-down' => 'f01a', + 'arrow-circle-o-up' => 'f01b', + 'inbox' => 'f01c', + 'play-circle-o' => 'f01d', + 'repeat' => 'f01e', + 'refresh' => 'f021', + 'list-alt' => 'f022', + 'lock' => 'f023', + 'flag' => 'f024', + 'headphones' => 'f025', + 'volume-off' => 'f026', + 'volume-down' => 'f027', + 'volume-up' => 'f028', + 'qrcode' => 'f029', + 'barcode' => 'f02a', + 'tag' => 'f02b', + 'tags' => 'f02c', + 'book' => 'f02d', + 'bookmark' => 'f02e', + 'print' => 'f02f', + 'camera' => 'f030', + 'font' => 'f031', + 'bold' => 'f032', + 'italic' => 'f033', + 'text-height' => 'f034', + 'text-width' => 'f035', + 'align-left' => 'f036', + 'align-center' => 'f037', + 'align-right' => 'f038', + 'align-justify' => 'f039', + 'list' => 'f03a', + 'outdent' => 'f03b', + 'indent' => 'f03c', + 'video-camera' => 'f03d', + 'picture-o' => 'f03e', + 'pencil' => 'f040', + 'map-marker' => 'f041', + 'adjust' => 'f042', + 'tint' => 'f043', + 'pencil-square-o' => 'f044', + 'share-square-o' => 'f045', + 'check-square-o' => 'f046', + 'arrows' => 'f047', + 'step-backward' => 'f048', + 'fast-backward' => 'f049', + 'backward' => 'f04a', + 'play' => 'f04b', + 'pause' => 'f04c', + 'stop' => 'f04d', + 'forward' => 'f04e', + 'fast-forward' => 'f050', + 'step-forward' => 'f051', + 'eject' => 'f052', + 'chevron-left' => 'f053', + 'chevron-right' => 'f054', + 'plus-circle' => 'f055', + 'minus-circle' => 'f056', + 'times-circle' => 'f057', + 'check-circle' => 'f058', + 'question-circle' => 'f059', + 'info-circle' => 'f05a', + 'crosshairs' => 'f05b', + 'times-circle-o' => 'f05c', + 'check-circle-o' => 'f05d', + 'ban' => 'f05e', + 'arrow-left' => 'f060', + 'arrow-right' => 'f061', + 'arrow-up' => 'f062', + 'arrow-down' => 'f063', + 'share' => 'f064', + 'expand' => 'f065', + 'compress' => 'f066', + 'plus' => 'f067', + 'minus' => 'f068', + 'asterisk' => 'f069', + 'exclamation-circle' => 'f06a', + 'gift' => 'f06b', + 'leaf' => 'f06c', + 'fire' => 'f06d', + 'eye' => 'f06e', + 'eye-slash' => 'f070', + 'exclamation-triangle' => 'f071', + 'plane' => 'f072', + 'calendar' => 'f073', + 'random' => 'f074', + 'comment' => 'f075', + 'magnet' => 'f076', + 'chevron-up' => 'f077', + 'chevron-down' => 'f078', + 'retweet' => 'f079', + 'shopping-cart' => 'f07a', + 'folder' => 'f07b', + 'folder-open' => 'f07c', + 'arrows-v' => 'f07d', + 'arrows-h' => 'f07e', + 'bar-chart' => 'f080', + 'twitter-square' => 'f081', + 'facebook-square' => 'f082', + 'camera-retro' => 'f083', + 'key' => 'f084', + 'cogs' => 'f085', + 'comments' => 'f086', + 'thumbs-o-up' => 'f087', + 'thumbs-o-down' => 'f088', + 'star-half' => 'f089', + 'heart-o' => 'f08a', + 'sign-out' => 'f08b', + 'linkedin-square' => 'f08c', + 'thumb-tack' => 'f08d', + 'external-link' => 'f08e', + 'sign-in' => 'f090', + 'trophy' => 'f091', + 'github-square' => 'f092', + 'upload' => 'f093', + 'lemon-o' => 'f094', + 'phone' => 'f095', + 'square-o' => 'f096', + 'bookmark-o' => 'f097', + 'phone-square' => 'f098', + 'twitter' => 'f099', + 'facebook' => 'f09a', + 'github' => 'f09b', + 'unlock' => 'f09c', + 'credit-card' => 'f09d', + 'rss' => 'f09e', + 'hdd-o' => 'f0a0', + 'bullhorn' => 'f0a1', + 'bell' => 'f0f3', + 'certificate' => 'f0a3', + 'hand-o-right' => 'f0a4', + 'hand-o-left' => 'f0a5', + 'hand-o-up' => 'f0a6', + 'hand-o-down' => 'f0a7', + 'arrow-circle-left' => 'f0a8', + 'arrow-circle-right' => 'f0a9', + 'arrow-circle-up' => 'f0aa', + 'arrow-circle-down' => 'f0ab', + 'globe' => 'f0ac', + 'wrench' => 'f0ad', + 'tasks' => 'f0ae', + 'filter' => 'f0b0', + 'briefcase' => 'f0b1', + 'arrows-alt' => 'f0b2', + 'users' => 'f0c0', + 'link' => 'f0c1', + 'cloud' => 'f0c2', + 'flask' => 'f0c3', + 'scissors' => 'f0c4', + 'files-o' => 'f0c5', + 'paperclip' => 'f0c6', + 'floppy-o' => 'f0c7', + 'square' => 'f0c8', + 'bars' => 'f0c9', + 'list-ul' => 'f0ca', + 'list-ol' => 'f0cb', + 'strikethrough' => 'f0cc', + 'underline' => 'f0cd', + 'table' => 'f0ce', + 'magic' => 'f0d0', + 'truck' => 'f0d1', + 'pinterest' => 'f0d2', + 'pinterest-square' => 'f0d3', + 'google-plus-square' => 'f0d4', + 'google-plus' => 'f0d5', + 'money' => 'f0d6', + 'caret-down' => 'f0d7', + 'caret-up' => 'f0d8', + 'caret-left' => 'f0d9', + 'caret-right' => 'f0da', + 'columns' => 'f0db', + 'sort' => 'f0dc', + 'sort-desc' => 'f0dd', + 'sort-asc' => 'f0de', + 'envelope' => 'f0e0', + 'linkedin' => 'f0e1', + 'undo' => 'f0e2', + 'gavel' => 'f0e3', + 'tachometer' => 'f0e4', + 'comment-o' => 'f0e5', + 'comments-o' => 'f0e6', + 'bolt' => 'f0e7', + 'sitemap' => 'f0e8', + 'umbrella' => 'f0e9', + 'clipboard' => 'f0ea', + 'lightbulb-o' => 'f0eb', + 'exchange' => 'f0ec', + 'cloud-download' => 'f0ed', + 'cloud-upload' => 'f0ee', + 'user-md' => 'f0f0', + 'stethoscope' => 'f0f1', + 'suitcase' => 'f0f2', + 'bell-o' => 'f0a2', + 'coffee' => 'f0f4', + 'cutlery' => 'f0f5', + 'file-text-o' => 'f0f6', + 'building-o' => 'f0f7', + 'hospital-o' => 'f0f8', + 'ambulance' => 'f0f9', + 'medkit' => 'f0fa', + 'fighter-jet' => 'f0fb', + 'beer' => 'f0fc', + 'h-square' => 'f0fd', + 'plus-square' => 'f0fe', + 'angle-double-left' => 'f100', + 'angle-double-right' => 'f101', + 'angle-double-up' => 'f102', + 'angle-double-down' => 'f103', + 'angle-left' => 'f104', + 'angle-right' => 'f105', + 'angle-up' => 'f106', + 'angle-down' => 'f107', + 'desktop' => 'f108', + 'laptop' => 'f109', + 'tablet' => 'f10a', + 'mobile' => 'f10b', + 'circle-o' => 'f10c', + 'quote-left' => 'f10d', + 'quote-right' => 'f10e', + 'spinner' => 'f110', + 'circle' => 'f111', + 'reply' => 'f112', + 'github-alt' => 'f113', + 'folder-o' => 'f114', + 'folder-open-o' => 'f115', + 'smile-o' => 'f118', + 'frown-o' => 'f119', + 'meh-o' => 'f11a', + 'gamepad' => 'f11b', + 'keyboard-o' => 'f11c', + 'flag-o' => 'f11d', + 'flag-checkered' => 'f11e', + 'terminal' => 'f120', + 'code' => 'f121', + 'reply-all' => 'f122', + 'star-half-o' => 'f123', + 'location-arrow' => 'f124', + 'crop' => 'f125', + 'code-fork' => 'f126', + 'chain-broken' => 'f127', + 'question' => 'f128', + 'info' => 'f129', + 'exclamation' => 'f12a', + 'superscript' => 'f12b', + 'subscript' => 'f12c', + 'eraser' => 'f12d', + 'puzzle-piece' => 'f12e', + 'microphone' => 'f130', + 'microphone-slash' => 'f131', + 'shield' => 'f132', + 'calendar-o' => 'f133', + 'fire-extinguisher' => 'f134', + 'rocket' => 'f135', + 'maxcdn' => 'f136', + 'chevron-circle-left' => 'f137', + 'chevron-circle-right' => 'f138', + 'chevron-circle-up' => 'f139', + 'chevron-circle-down' => 'f13a', + 'html5' => 'f13b', + 'css3' => 'f13c', + 'anchor' => 'f13d', + 'unlock-alt' => 'f13e', + 'bullseye' => 'f140', + 'ellipsis-h' => 'f141', + 'ellipsis-v' => 'f142', + 'rss-square' => 'f143', + 'play-circle' => 'f144', + 'ticket' => 'f145', + 'minus-square' => 'f146', + 'minus-square-o' => 'f147', + 'level-up' => 'f148', + 'level-down' => 'f149', + 'check-square' => 'f14a', + 'pencil-square' => 'f14b', + 'external-link-square' => 'f14c', + 'share-square' => 'f14d', + 'compass' => 'f14e', + 'caret-square-o-down' => 'f150', + 'caret-square-o-up' => 'f151', + 'caret-square-o-right' => 'f152', + 'eur' => 'f153', + 'gbp' => 'f154', + 'usd' => 'f155', + 'inr' => 'f156', + 'jpy' => 'f157', + 'rub' => 'f158', + 'krw' => 'f159', + 'btc' => 'f15a', + 'file' => 'f15b', + 'file-text' => 'f15c', + 'sort-alpha-asc' => 'f15d', + 'sort-alpha-desc' => 'f15e', + 'sort-amount-asc' => 'f160', + 'sort-amount-desc' => 'f161', + 'sort-numeric-asc' => 'f162', + 'sort-numeric-desc' => 'f163', + 'thumbs-up' => 'f164', + 'thumbs-down' => 'f165', + 'youtube-square' => 'f166', + 'youtube' => 'f167', + 'xing' => 'f168', + 'xing-square' => 'f169', + 'youtube-play' => 'f16a', + 'dropbox' => 'f16b', + 'stack-overflow' => 'f16c', + 'instagram' => 'f16d', + 'flickr' => 'f16e', + 'adn' => 'f170', + 'bitbucket' => 'f171', + 'bitbucket-square' => 'f172', + 'tumblr' => 'f173', + 'tumblr-square' => 'f174', + 'long-arrow-down' => 'f175', + 'long-arrow-up' => 'f176', + 'long-arrow-left' => 'f177', + 'long-arrow-right' => 'f178', + 'apple' => 'f179', + 'windows' => 'f17a', + 'android' => 'f17b', + 'linux' => 'f17c', + 'dribbble' => 'f17d', + 'skype' => 'f17e', + 'foursquare' => 'f180', + 'trello' => 'f181', + 'female' => 'f182', + 'male' => 'f183', + 'gratipay' => 'f184', + 'sun-o' => 'f185', + 'moon-o' => 'f186', + 'archive' => 'f187', + 'bug' => 'f188', + 'vk' => 'f189', + 'weibo' => 'f18a', + 'renren' => 'f18b', + 'pagelines' => 'f18c', + 'stack-exchange' => 'f18d', + 'arrow-circle-o-right' => 'f18e', + 'arrow-circle-o-left' => 'f190', + 'caret-square-o-left' => 'f191', + 'dot-circle-o' => 'f192', + 'wheelchair' => 'f193', + 'vimeo-square' => 'f194', + 'try' => 'f195', + 'plus-square-o' => 'f196', + 'space-shuttle' => 'f197', + 'slack' => 'f198', + 'envelope-square' => 'f199', + 'wordpress' => 'f19a', + 'openid' => 'f19b', + 'university' => 'f19c', + 'graduation-cap' => 'f19d', + 'yahoo' => 'f19e', + 'google' => 'f1a0', + 'reddit' => 'f1a1', + 'reddit-square' => 'f1a2', + 'stumbleupon-circle' => 'f1a3', + 'stumbleupon' => 'f1a4', + 'delicious' => 'f1a5', + 'digg' => 'f1a6', + 'pied-piper-pp' => 'f1a7', + 'pied-piper-alt' => 'f1a8', + 'drupal' => 'f1a9', + 'joomla' => 'f1aa', + 'language' => 'f1ab', + 'fax' => 'f1ac', + 'building' => 'f1ad', + 'child' => 'f1ae', + 'paw' => 'f1b0', + 'spoon' => 'f1b1', + 'cube' => 'f1b2', + 'cubes' => 'f1b3', + 'behance' => 'f1b4', + 'behance-square' => 'f1b5', + 'steam' => 'f1b6', + 'steam-square' => 'f1b7', + 'recycle' => 'f1b8', + 'car' => 'f1b9', + 'taxi' => 'f1ba', + 'tree' => 'f1bb', + 'spotify' => 'f1bc', + 'deviantart' => 'f1bd', + 'soundcloud' => 'f1be', + 'database' => 'f1c0', + 'file-pdf-o' => 'f1c1', + 'file-word-o' => 'f1c2', + 'file-excel-o' => 'f1c3', + 'file-powerpoint-o' => 'f1c4', + 'file-image-o' => 'f1c5', + 'file-archive-o' => 'f1c6', + 'file-audio-o' => 'f1c7', + 'file-video-o' => 'f1c8', + 'file-code-o' => 'f1c9', + 'vine' => 'f1ca', + 'codepen' => 'f1cb', + 'jsfiddle' => 'f1cc', + 'life-ring' => 'f1cd', + 'circle-o-notch' => 'f1ce', + 'rebel' => 'f1d0', + 'empire' => 'f1d1', + 'git-square' => 'f1d2', + 'git' => 'f1d3', + 'hacker-news' => 'f1d4', + 'tencent-weibo' => 'f1d5', + 'qq' => 'f1d6', + 'weixin' => 'f1d7', + 'paper-plane' => 'f1d8', + 'paper-plane-o' => 'f1d9', + 'history' => 'f1da', + 'circle-thin' => 'f1db', + 'header' => 'f1dc', + 'paragraph' => 'f1dd', + 'sliders' => 'f1de', + 'share-alt' => 'f1e0', + 'share-alt-square' => 'f1e1', + 'bomb' => 'f1e2', + 'futbol-o' => 'f1e3', + 'tty' => 'f1e4', + 'binoculars' => 'f1e5', + 'plug' => 'f1e6', + 'slideshare' => 'f1e7', + 'twitch' => 'f1e8', + 'yelp' => 'f1e9', + 'newspaper-o' => 'f1ea', + 'wifi' => 'f1eb', + 'calculator' => 'f1ec', + 'paypal' => 'f1ed', + 'google-wallet' => 'f1ee', + 'cc-visa' => 'f1f0', + 'cc-mastercard' => 'f1f1', + 'cc-discover' => 'f1f2', + 'cc-amex' => 'f1f3', + 'cc-paypal' => 'f1f4', + 'cc-stripe' => 'f1f5', + 'bell-slash' => 'f1f6', + 'bell-slash-o' => 'f1f7', + 'trash' => 'f1f8', + 'copyright' => 'f1f9', + 'at' => 'f1fa', + 'eyedropper' => 'f1fb', + 'paint-brush' => 'f1fc', + 'birthday-cake' => 'f1fd', + 'area-chart' => 'f1fe', + 'pie-chart' => 'f200', + 'line-chart' => 'f201', + 'lastfm' => 'f202', + 'lastfm-square' => 'f203', + 'toggle-off' => 'f204', + 'toggle-on' => 'f205', + 'bicycle' => 'f206', + 'bus' => 'f207', + 'ioxhost' => 'f208', + 'angellist' => 'f209', + 'cc' => 'f20a', + 'ils' => 'f20b', + 'meanpath' => 'f20c', + 'buysellads' => 'f20d', + 'connectdevelop' => 'f20e', + 'dashcube' => 'f210', + 'forumbee' => 'f211', + 'leanpub' => 'f212', + 'sellsy' => 'f213', + 'shirtsinbulk' => 'f214', + 'simplybuilt' => 'f215', + 'skyatlas' => 'f216', + 'cart-plus' => 'f217', + 'cart-arrow-down' => 'f218', + 'diamond' => 'f219', + 'ship' => 'f21a', + 'user-secret' => 'f21b', + 'motorcycle' => 'f21c', + 'street-view' => 'f21d', + 'heartbeat' => 'f21e', + 'venus' => 'f221', + 'mars' => 'f222', + 'mercury' => 'f223', + 'transgender' => 'f224', + 'transgender-alt' => 'f225', + 'venus-double' => 'f226', + 'mars-double' => 'f227', + 'venus-mars' => 'f228', + 'mars-stroke' => 'f229', + 'mars-stroke-v' => 'f22a', + 'mars-stroke-h' => 'f22b', + 'neuter' => 'f22c', + 'genderless' => 'f22d', + 'facebook-official' => 'f230', + 'pinterest-p' => 'f231', + 'whatsapp' => 'f232', + 'server' => 'f233', + 'user-plus' => 'f234', + 'user-times' => 'f235', + 'bed' => 'f236', + 'viacoin' => 'f237', + 'train' => 'f238', + 'subway' => 'f239', + 'medium' => 'f23a', + 'y-combinator' => 'f23b', + 'optin-monster' => 'f23c', + 'opencart' => 'f23d', + 'expeditedssl' => 'f23e', + 'battery-full' => 'f240', + 'battery-three-quarters' => 'f241', + 'battery-half' => 'f242', + 'battery-quarter' => 'f243', + 'battery-empty' => 'f244', + 'mouse-pointer' => 'f245', + 'i-cursor' => 'f246', + 'object-group' => 'f247', + 'object-ungroup' => 'f248', + 'sticky-note' => 'f249', + 'sticky-note-o' => 'f24a', + 'cc-jcb' => 'f24b', + 'cc-diners-club' => 'f24c', + 'clone' => 'f24d', + 'balance-scale' => 'f24e', + 'hourglass-o' => 'f250', + 'hourglass-start' => 'f251', + 'hourglass-half' => 'f252', + 'hourglass-end' => 'f253', + 'hourglass' => 'f254', + 'hand-rock-o' => 'f255', + 'hand-paper-o' => 'f256', + 'hand-scissors-o' => 'f257', + 'hand-lizard-o' => 'f258', + 'hand-spock-o' => 'f259', + 'hand-pointer-o' => 'f25a', + 'hand-peace-o' => 'f25b', + 'trademark' => 'f25c', + 'registered' => 'f25d', + 'creative-commons' => 'f25e', + 'gg' => 'f260', + 'gg-circle' => 'f261', + 'tripadvisor' => 'f262', + 'odnoklassniki' => 'f263', + 'odnoklassniki-square' => 'f264', + 'get-pocket' => 'f265', + 'wikipedia-w' => 'f266', + 'safari' => 'f267', + 'chrome' => 'f268', + 'firefox' => 'f269', + 'opera' => 'f26a', + 'internet-explorer' => 'f26b', + 'television' => 'f26c', + 'contao' => 'f26d', + '500px' => 'f26e', + 'amazon' => 'f270', + 'calendar-plus-o' => 'f271', + 'calendar-minus-o' => 'f272', + 'calendar-times-o' => 'f273', + 'calendar-check-o' => 'f274', + 'industry' => 'f275', + 'map-pin' => 'f276', + 'map-signs' => 'f277', + 'map-o' => 'f278', + 'map' => 'f279', + 'commenting' => 'f27a', + 'commenting-o' => 'f27b', + 'houzz' => 'f27c', + 'vimeo' => 'f27d', + 'black-tie' => 'f27e', + 'fonticons' => 'f280', + 'reddit-alien' => 'f281', + 'edge' => 'f282', + 'credit-card-alt' => 'f283', + 'codiepie' => 'f284', + 'modx' => 'f285', + 'fort-awesome' => 'f286', + 'usb' => 'f287', + 'product-hunt' => 'f288', + 'mixcloud' => 'f289', + 'scribd' => 'f28a', + 'pause-circle' => 'f28b', + 'pause-circle-o' => 'f28c', + 'stop-circle' => 'f28d', + 'stop-circle-o' => 'f28e', + 'shopping-bag' => 'f290', + 'shopping-basket' => 'f291', + 'hashtag' => 'f292', + 'bluetooth' => 'f293', + 'bluetooth-b' => 'f294', + 'percent' => 'f295', + 'gitlab' => 'f296', + 'wpbeginner' => 'f297', + 'wpforms' => 'f298', + 'envira' => 'f299', + 'universal-access' => 'f29a', + 'wheelchair-alt' => 'f29b', + 'question-circle-o' => 'f29c', + 'blind' => 'f29d', + 'audio-description' => 'f29e', + 'volume-control-phone' => 'f2a0', + 'braille' => 'f2a1', + 'assistive-listening-systems' => 'f2a2', + 'american-sign-language-interpreting' => 'f2a3', + 'deaf' => 'f2a4', + 'glide' => 'f2a5', + 'glide-g' => 'f2a6', + 'sign-language' => 'f2a7', + 'low-vision' => 'f2a8', + 'viadeo' => 'f2a9', + 'viadeo-square' => 'f2aa', + 'snapchat' => 'f2ab', + 'snapchat-ghost' => 'f2ac', + 'snapchat-square' => 'f2ad', + 'pied-piper' => 'f2ae', + 'first-order' => 'f2b0', + 'yoast' => 'f2b1', + 'themeisle' => 'f2b2', + 'google-plus-official' => 'f2b3', + 'font-awesome' => 'f2b4' + ]; + + if (!array_key_exists($icon, $icons)) { + throw new InvalidIconException(sprintf('The icon "%s" is not available', $icon)); + } + + return $icons[$icon]; + } + + protected function getShape(string $shape): int + { + $shapes = ['circle', 'square', 'star', 'penta']; + + $key = array_search($shape, $shapes); + + if (false === $key) { + throw new InvalidShapeException(sprintf('The shape "%s" is not available', $shape)); + } + + return $key; + } + + protected function getColor(string $color): int + { + $colors = ['red', 'orangedark', 'orange', 'yellow', 'bluedark', 'blue', 'cyan', 'purple', 'violet', 'pink', 'greendark', 'green', 'greenlight', 'black', 'white']; + + $key = array_search($color, $colors); + + if (false === $key) { + new InvalidColorException(sprintf('The color "%s" is not available', $color)); + } + + return $key; + } +} diff --git a/src/Element/Marker/AbstractMarker.php b/src/Element/Marker/AbstractMarker.php new file mode 100644 index 0000000..0252895 --- /dev/null +++ b/src/Element/Marker/AbstractMarker.php @@ -0,0 +1,26 @@ +latitude; + } + + public function getLongitude(): float + { + return $this->longitude; + } +} diff --git a/src/Element/Marker/ExtraMarker.php b/src/Element/Marker/ExtraMarker.php new file mode 100644 index 0000000..33dc59a --- /dev/null +++ b/src/Element/Marker/ExtraMarker.php @@ -0,0 +1,56 @@ +shape = $shape; + $this->color = $color; + $this->awesome = $awesome; + + $this->latitude = $latitude; + $this->longitude = $longitude; + } + + public function getShape(): int + { + return $this->shape; + } + + public function getColor(): int + { + return $this->color; + } + + public function getAwesome(): string + { + return $this->awesome; + } +} diff --git a/src/Element/Marker/Marker.php b/src/Element/Marker/Marker.php new file mode 100644 index 0000000..6b518bd --- /dev/null +++ b/src/Element/Marker/Marker.php @@ -0,0 +1,23 @@ +markerType = $markerType; + $this->latitude = $latitude; + $this->longitude = $longitude; + } + + public function getMarkerType(): string + { + return $this->markerType; + } + + +} diff --git a/src/Element/Polyline/Polyline.php b/src/Element/Polyline/Polyline.php new file mode 100644 index 0000000..0ec5b1a --- /dev/null +++ b/src/Element/Polyline/Polyline.php @@ -0,0 +1,47 @@ +polyline = $polyline; + + $this->colorRed = $colorRed; + $this->colorGreen = $colorGreen; + $this->colorBlue = $colorBlue; + } + + public function getPolyline(): string + { + return $this->polyline; + } + + public function getColorRed(): int + { + return $this->colorRed; + } + + public function getColorGreen(): int + { + return $this->colorGreen; + } + + public function getColorBlue(): int + { + return $this->colorBlue; + } +} diff --git a/src/ElementPrinter/Marker/ExtraMarkerPrinter.php b/src/ElementPrinter/Marker/ExtraMarkerPrinter.php new file mode 100644 index 0000000..c0fb27d --- /dev/null +++ b/src/ElementPrinter/Marker/ExtraMarkerPrinter.php @@ -0,0 +1,173 @@ +imagine = new \Imagine\Gd\Imagine(); + } + + public function setMarkerSize(float $markerSize): ExtraMarkerPrinter + { + $this->markerSize = $markerSize; + + return $this; + } + + public function setMarker(AbstractMarker $marker): ExtraMarkerPrinter + { + $this->marker = $marker; + + return $this; + } + + public function paint(Canvas $canvas): ExtraMarkerPrinter + { + $this->paintShadow($canvas); + $this->paintMarker($canvas); + + return $this; + } + + protected function paintMarker(Canvas $canvas): ExtraMarkerPrinter + { + $markerImage = $this->createMarker(); + + $destX = floor(($canvas->getWidth() / 2) - $canvas->getTileSize() * ($canvas->getCenterX() - Util::lonToTile($this->marker->getLongitude(), $canvas->getZoom()))); + $destY = floor(($canvas->getHeight() / 2) - $canvas->getTileSize() * ($canvas->getCenterY() - Util::latToTile($this->marker->getLatitude(), $canvas->getZoom()))); + + $destX -= $markerImage->getSize()->getWidth() * $this->markerSize / 2; + $destY -= $markerImage->getSize()->getHeight() * $this->markerSize; + + $point = new Point($destX, $destY); + + if ($canvas->getImage()->getSize()->contains($markerImage->getSize(), $point)) { + $canvas->getImage()->paste($markerImage, $point); + } + + return $this; + } + + protected function createMarker(): ImageInterface + { + $extramarkers = $this + ->imagine + ->open(__DIR__.'/../../../images/extramarkers.png') + ; + + $sourceX = $this->baseMarkerWidth * $this->marker->getColor(); + $sourceY = $this->baseMarkerHeight * $this->marker->getShape(); + + $point = new Point($sourceX, $sourceY); + $box = new Box($this->baseMarkerWidth, $this->baseMarkerHeight); + + $markerImage = $extramarkers->crop($point, $box); + + $this->writeMarker($markerImage); + + return $markerImage; + } + + protected function writeMarker(ImageInterface $markerImage): ExtraMarkerPrinter + { + $text = json_decode(sprintf('"&#x%s;"', $this->marker->getAwesome())); + $font = $this->getFont($markerImage); + + $textBox = $font->box($text); + $textCenterPosition = new Center($textBox); + $imageCenterPosition = new Center($markerImage->getSize()); + $centeredTextPosition = new Point( + $imageCenterPosition->getX() - $textCenterPosition->getX() + $this->iconOffsetX, + $imageCenterPosition->getY() - $textCenterPosition->getY() + $this->iconOffsetY + ); + + $markerImage->draw()->text($text, $font, $centeredTextPosition); + + return $this; + } + + protected function getFont(ImageInterface $markerImage): AbstractFont + { + $fontColor = $markerImage->palette()->color('fff'); + $fontSize = 20; + $fontFilename = __DIR__.'/../../../fonts/fontawesome-webfont.ttf'; + + $font = new Font($fontFilename, $fontSize, $fontColor); + + return $font; + } + + protected function paintShadow(Canvas $canvas): ExtraMarkerPrinter + { + $shadowImage = $this->createShadow(); + + $destX = floor(($canvas->getWidth() / 2) - $canvas->getTileSize() * ($canvas->getCenterX() - Util::lonToTile($this->marker->getLongitude(), $canvas->getZoom()))); + $destY = floor(($canvas->getHeight() / 2) - $canvas->getTileSize() * ($canvas->getCenterY() - Util::latToTile($this->marker->getLatitude(), $canvas->getZoom()))); + + $destX -= $this->baseShadowWidth * $this->markerSize; + $destY -= $this->baseShadowHeight; + + $point = new Point($destX + $this->shadowOffsetX, $destY + $this->shadowOffsetY); + + $canvas->getImage()->paste($shadowImage, $point); + + return $this; + } + + protected function createShadow(): ImageInterface + { + $shadowImage = $this + ->imagine + ->open(__DIR__.'/../../../images/marker_shadow.png') + ; + + return $shadowImage; + } +} diff --git a/src/ElementPrinter/Marker/MarkerPrinter.php b/src/ElementPrinter/Marker/MarkerPrinter.php new file mode 100644 index 0000000..65ebe8e --- /dev/null +++ b/src/ElementPrinter/Marker/MarkerPrinter.php @@ -0,0 +1,123 @@ + array('regex' => '/^lightblue([0-9]+)$/', + 'extension' => '.png', + 'shadow' => false, + 'offsetImage' => '0,-19', + 'offsetShadow' => false, + ), + // openlayers std markers + 'ol-marker' => array('regex' => '/^ol-marker(|-blue|-gold|-green)+$/', + 'extension' => '.png', + 'shadow' => '../marker_shadow.png', + 'offsetImage' => '-10,-25', + 'offsetShadow' => '-1,-13', + ), + // taken from http://www.visual-case.it/cgi-bin/vc/GMapsIcons.pl + 'ylw' => array('regex' => '/^(pink|purple|red|ltblu|ylw)-pushpin$/', + 'extension' => '.png', + 'shadow' => '../marker_shadow.png', + 'offsetImage' => '-10,-32', + 'offsetShadow' => '-1,-13', + ), + // http://svn.openstreetmap.org/sites/other/StaticMap/symbols/0.png + 'ojw' => array('regex' => '/^bullseye$/', + 'extension' => '.png', + 'shadow' => false, + 'offsetImage' => '-20,-20', + 'offsetShadow' => false, + ), + ); + + public function __construct() + { + + } + + public function setMarker(AbstractMarker $marker): MarkerPrinter + { + $this->marker = $marker; + + return $this; + } + + public function paint(Canvas $canvas): MarkerPrinter + { + $markerFilename = ''; + $markerShadow = ''; + $matches = false; + $markerIndex = 0; + + // check for marker type, get settings from markerPrototypes + if ($this->marker->getMarkerType()) { + foreach ($this->markerPrototypes as $markerPrototype) { + if (preg_match($markerPrototype['regex'], $this->marker->getMarkerType(), $matches)) { + $markerFilename = $matches[0] . $markerPrototype['extension']; + if ($markerPrototype['offsetImage']) { + list($markerImageOffsetX, $markerImageOffsetY) = explode(",", $markerPrototype['offsetImage']); + } + $markerShadow = $markerPrototype['shadow']; + if ($markerShadow) { + list($markerShadowOffsetX, $markerShadowOffsetY) = explode(",", $markerPrototype['offsetShadow']); + } + } + + } + } + + // check required files or set default + if ($markerFilename == '' || !file_exists($this->markerBaseDir . '/' . $markerFilename)) { + $markerIndex++; + $markerFilename = 'lightblue' . $markerIndex . '.png'; + $markerImageOffsetX = 0; + $markerImageOffsetY = -19; + } + + // create img resource + if (file_exists($this->markerBaseDir . '/' . $markerFilename)) { + $markerImg = imagecreatefrompng($this->markerBaseDir . '/' . $markerFilename); + } else { + $markerImg = imagecreatefrompng($this->markerBaseDir . '/lightblue1.png'); + } + + // check for shadow + create shadow recource + if ($markerShadow && file_exists($this->markerBaseDir . '/' . $markerShadow)) { + $markerShadowImg = imagecreatefrompng($this->markerBaseDir . '/' . $markerShadow); + } + + // calc position + $destX = floor(($canvas->getWidth() / 2) - $canvas->getTileSize() * ($canvas->getCenterX() - Util::lonToTile($this->marker->getLongitude(), $canvas->getZoom()))); + $destY = floor(($canvas->getHeight() / 2) - $canvas->getTileSize() * ($canvas->getCenterY() - Util::latToTile($this->marker->getLatitude(), $canvas->getZoom()))); + + // copy shadow on basemap + if ($markerShadow && $markerShadowImg) { + imagecopy($canvas->getImage(), $markerShadowImg, $destX + intval($markerShadowOffsetX), $destY + intval($markerShadowOffsetY), + 0, 0, imagesx($markerShadowImg), imagesy($markerShadowImg)); + } + + // copy marker on basemap above shadow + imagecopy($canvas->getImage(), $markerImg, $destX + intval($markerImageOffsetX), $destY + intval($markerImageOffsetY), + 0, 0, imagesx($markerImg), imagesy($markerImg)); + + + return $this; + } + +} diff --git a/src/ElementPrinter/Polyline/PolylinePrinter.php b/src/ElementPrinter/Polyline/PolylinePrinter.php new file mode 100644 index 0000000..da0ba04 --- /dev/null +++ b/src/ElementPrinter/Polyline/PolylinePrinter.php @@ -0,0 +1,83 @@ +polyline = $polyline; + + return $this; + } + + public function paint(Canvas $canvas): PolylinePrinter + { + $pointList = $this->convertPolylineToPointList($canvas); + $color = $this->getPolylineColor($canvas); + + $startPoint = null; + $endPoint = null; + + while (!empty($pointList)) { + if (!$startPoint) { + $startPoint = array_pop($pointList); + } + + $endPoint = array_pop($pointList); + + $canvas->getImage()->draw()->line($startPoint, $endPoint, $color, $this->thickness); + + $startPoint = $endPoint; + } + + return $this; + } + + protected function getPolylineColor(Canvas $canvas): ColorInterface + { + return $canvas->getImage()->palette()->color([ + $this->polyline->getColorRed(), + $this->polyline->getColorGreen(), + $this->polyline->getColorBlue(), + ]); + } + + protected function convertPolylineToPointList(Canvas $canvas): array + { + $polylineList = \Polyline::decode($this->polyline->getPolyline()); + + $pointList = []; + + while (!empty($polylineList)) { + $latitude = array_shift($polylineList); + $longitude = array_shift($polylineList); + + $sourceX = floor(($canvas->getWidth() / 2) - $canvas->getTileSize() * ($canvas->getCenterX() - Util::lonToTile($longitude, $canvas->getZoom()))); + $sourceY = floor(($canvas->getHeight() / 2) - $canvas->getTileSize() * ($canvas->getCenterY() - Util::latToTile($latitude, $canvas->getZoom()))); + + $point = new Point($sourceX, $sourceY); + + $pointList[] = $point; + } + + return $pointList; + } +} diff --git a/src/Exception/ExtraMarker/InvalidColorException.php b/src/Exception/ExtraMarker/InvalidColorException.php new file mode 100644 index 0000000..04a966e --- /dev/null +++ b/src/Exception/ExtraMarker/InvalidColorException.php @@ -0,0 +1,10 @@ +printer = $printer; + } + + public function checkMapCache(): bool + { + return false; + $this->mapCacheID = md5($this->serializeParams()); + + $filename = $this->getFilename(); + + return file_exists($filename); + } + + public function serializeParams(): string + { + return join('&', [ + $this->printer->getZoom(), + $this->printer->getLatitude(), + $this->printer->getLongitude(), + $this->printer->getWidth(), + $this->printer->getHeight(), + serialize($this->printer->getMarkers()), + serialize($this->printer->getPolylines()), + $this->printer->getMapType() + ]); + } + + public function mapCacheIDToFilename() + { + if (!$this->mapCacheFile) { + $this->mapCacheFile = sprintf( + '%s/%s/%s/cache_%/%s/%s', + $this->mapCacheBaseDir, + $this->printer->getMaptype(), + $this->printer->getZoom(), + substr($this->mapCacheID, 0, 2), + substr($this->mapCacheID, 2, 2), + substr($this->mapCacheID, 4) + ); + } + + $filename = sprintf('%s.%s', $this->mapCacheFile, $this->mapCacheExtension); + + return $filename; + } + + public function cache(CanvasInterface $canvas): void + { + $this->mkdir_recursive(dirname($this->mapCacheIDToFilename()), 0777); + + $canvas->getImage()->save($this->mapCacheIDToFilename()); + + $output = new CacheOutput(); + $output->setFilename($this->mapCacheIDToFilename()) + ->sendHeader() + ->sendImage() + ; + } + + public function mkdir_recursive($pathname, $mode): bool + { + is_dir(dirname($pathname)) || $this->mkdir_recursive(dirname($pathname), $mode); + + return is_dir($pathname) || @mkdir($pathname, $mode); + } + + public function getFilename(): string + { + return $this->mapCacheIDToFilename(); + } +} diff --git a/src/MapCache/MapCacheInterface.php b/src/MapCache/MapCacheInterface.php new file mode 100644 index 0000000..dd9f9b1 --- /dev/null +++ b/src/MapCache/MapCacheInterface.php @@ -0,0 +1,15 @@ +filename = $filename; + + return $this; + } + + public function sendImage(): void + { + echo file_get_contents($this->filename); + } +} diff --git a/src/Output/ImageOutput.php b/src/Output/ImageOutput.php new file mode 100644 index 0000000..38243bd --- /dev/null +++ b/src/Output/ImageOutput.php @@ -0,0 +1,20 @@ +image = $image; + + return $this; + } + + public function sendImage(): bool + { + return imagepng($this->image); + } +} diff --git a/src/Output/OutputInterface.php b/src/Output/OutputInterface.php new file mode 100644 index 0000000..4b3e16e --- /dev/null +++ b/src/Output/OutputInterface.php @@ -0,0 +1,9 @@ + 'http://tile.openstreetmap.org/{z}/{x}/{y}.png', + 'osmarenderer' => 'http://otile1.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.png', + 'cycle' => 'http://a.tile.opencyclemap.org/cycle/{z}/{x}/{y}.png', + 'wikimedia-intl' => 'https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png', + ]; + + /** @var string $tileDefaultSrc */ + protected $tileDefaultSrc = 'mapnik'; + + /** @var bool $useTileCache */ + protected $useTileCache = true; + + /** @var int $zoom */ + protected $zoom; + + /** @var float $latitude */ + protected $latitude; + + /** @var float $longitude */ + protected $longitude; + + /** @var int $width */ + protected $width; + + /** @var int $height */ + protected $height; + + protected $image; + + protected $maptype; + + protected $centerX; + + protected $centerY; + + protected $offsetX; + + protected $offsetY; + + /** @var array $markers */ + protected $markers = []; + + /** @var array $polylines */ + protected $polylines = []; + + public function getMaxWidth(): int + { + return $this->maxWidth; + } + + public function setMaxWidth(int $maxWidth): PrinterInterface + { + $this->maxWidth = $maxWidth; + + return $this; + } + + public function getMaxHeight(): int + { + return $this->maxHeight; + } + + public function setMaxHeight(int $maxHeight): PrinterInterface + { + $this->maxHeight = $maxHeight; + + return $this; + } + + public function getTileResolver(): TileResolverInterface + { + return $this->tileResolver; + } + + public function setTileResolver(TileResolverInterface $tileResolver): PrinterInterface + { + $this->tileResolver = $tileResolver; + + return $this; + } + + public function getCanvas(): CanvasInterface + { + return $this->canvas; + } + + public function setCanvas(CanvasInterface $canvas): PrinterInterface + { + $this->canvas = $canvas; + + return $this; + } + + public function getTileSize(): int + { + return $this->tileSize; + } + + public function setTileSize(int $tileSize): PrinterInterface + { + $this->tileSize = $tileSize; + + return $this; + } + + public function getTileSrcUrl(): array + { + return $this->tileSrcUrl; + } + + public function setTileSrcUrl(array $tileSrcUrl): PrinterInterface + { + $this->tileSrcUrl = $tileSrcUrl; + + return $this; + } + + public function getTileDefaultSrc(): string + { + return $this->tileDefaultSrc; + } + + public function setTileDefaultSrc(string $tileDefaultSrc): PrinterInterface + { + $this->tileDefaultSrc = $tileDefaultSrc; + + return $this; + } + + public function getOsmLogo(): string + { + return $this->osmLogo; + } + + public function setOsmLogo(string $osmLogo): PrinterInterface + { + $this->osmLogo = $osmLogo; + + return $this; + } + + public function isUseTileCache(): bool + { + return $this->useTileCache; + } + + public function setUseTileCache(bool $useTileCache): PrinterInterface + { + $this->useTileCache = $useTileCache; + + return $this; + } + + public function getZoom(): int + { + return $this->zoom; + } + + public function setZoom(int $zoom): PrinterInterface + { + $this->zoom = $zoom; + + return $this; + } + + public function getLatitude(): float + { + return $this->latitude; + } + + public function setLatitude(float $latitude): PrinterInterface + { + $this->latitude = $latitude; + + return $this; + } + + public function getLongitude(): float + { + return $this->longitude; + } + + public function setLongitude(float $longitude): PrinterInterface + { + $this->longitude = $longitude; + + return $this; + } + + public function getWidth(): int + { + return $this->width; + } + + public function setWidth($width): PrinterInterface + { + $this->width = $width; + + return $this; + } + + public function getHeight(): int + { + return $this->height; + } + + public function setHeight($height): PrinterInterface + { + $this->height = $height; + + return $this; + } + + public function getImage() + { + return $this->image; + } + + public function setImage($image): PrinterInterface + { + $this->image = $image; + + return $this; + } + + public function getMaptype(): string + { + return $this->maptype; + } + + public function setMaptype(string $maptype): PrinterInterface + { + $this->maptype = $maptype; + + return $this; + } + + public function getCenterX(): int + { + return $this->centerX; + } + + public function setCenterX($centerX): PrinterInterface + { + $this->centerX = $centerX; + + return $this; + } + + public function getCenterY(): int + { + return $this->centerY; + } + + public function setCenterY(int $centerY): PrinterInterface + { + $this->centerY = $centerY; + + return $this; + } + + public function getOffsetX(): int + { + return $this->offsetX; + } + + public function setOffsetX(int $offsetX): PrinterInterface + { + $this->offsetX = $offsetX; + + return $this; + } + + public function getOffsetY(): int + { + return $this->offsetY; + } + + public function setOffsetY(int $offsetY): PrinterInterface + { + $this->offsetY = $offsetY; + + return $this; + } + + public function getMarkers(): array + { + return $this->markers; + } + + public function setMarkers(array $markers): PrinterInterface + { + $this->markers = $markers; + + return $this; + } + + public function getPolylines(): array + { + return $this->polylines; + } + + public function setPolylines(array $polylines): PrinterInterface + { + $this->polylines = $polylines; + + return $this; + } +} diff --git a/src/Printer/Printer.php b/src/Printer/Printer.php new file mode 100644 index 0000000..de8a191 --- /dev/null +++ b/src/Printer/Printer.php @@ -0,0 +1,208 @@ +zoom = 0; + $this->latitude = 0; + $this->longitude = 0; + $this->width = 500; + $this->height = 350; + $this->maptype = $this->tileDefaultSrc; + + $this->mapCache = new MapCache($this); + $this->tileResolver = new CachedTileResolver(); + $this->tileResolver->setTileLayerUrl($this->tileSrcUrl[$this->maptype]); + } + + public function addMarker(AbstractMarker $marker): Printer + { + $this->markers[] = $marker; + + return $this; + } + + public function addPolyline(Polyline $polyline): Printer + { + $this->polylines[] = $polyline; + + return $this; + } + + public function setCenter(float $latitude, float $longitude): Printer + { + $this->latitude = $latitude; + $this->longitude = $longitude; + + return $this; + } + + public function setSize(int $width, int $height): Printer + { + $this->width = $width; + $this->height = $height; + + if ($this->width > $this->maxWidth) { + $this->width = $this->maxWidth; + } + + if ($this->height > $this->maxHeight) { + $this->height = $this->maxHeight; + } + + return $this; + } + + public function setZoom(int $zoom): PrinterInterface + { + $this->zoom = $zoom; + + if ($this->zoom > 18) { + $this->zoom = 18; + } + + return $this; + } + + public function setMapType(string $mapType): PrinterInterface + { + $this->maptype = $mapType; + + $this->tileResolver->setTileLayerUrl($this->tileSrcUrl[$this->maptype]); + + return $this; + } + + public function initCoords(): Printer + { + $this->centerX = Util::lonToTile($this->longitude, $this->zoom); + $this->centerY = Util::latToTile($this->latitude, $this->zoom); + + $this->offsetX = floor((floor($this->centerX) - $this->centerX) * $this->tileSize); + $this->offsetY = floor((floor($this->centerY) - $this->centerY) * $this->tileSize); + + return $this; + } + + public function createBaseMap(): Printer + { + $this->canvas = new Canvas( + $this->width, + $this->height, + $this->zoom, + $this->centerX, + $this->centerY + ); + + $ctp = new CanvasTilePainter(); + $ctp + ->setCanvas($this->canvas) + ->setTileResolver($this->tileResolver) + ->paint() + ; + + return $this; + } + + public function placeMarkers(): Printer + { + $printer = new ExtraMarkerPrinter(); + + foreach ($this->markers as $marker) { + $printer + ->setMarker($marker) + ->paint($this->canvas) + ; + } + + return $this; + } + + public function placePolylines(): Printer + { + $printer = new PolylinePrinter(); + + /** @var Polyline $polyline */ + foreach ($this->polylines as $polyline) { + $printer + ->setPolyline($polyline) + ->paint($this->canvas) + ; + } + + return $this; + } + + public function makeMap(): Printer + { + $this->initCoords(); + + $this->createBaseMap(); + + if (count($this->polylines)) { + $this->placePolylines(); + } + + if (count($this->markers)) { + $this->placeMarkers(); + } + + $this->printCopyright(); + + return $this; + } + + protected function printCopyright(): Printer + { + $cp = new CopyrightPrinter(); + $cp + ->setCanvas($this->canvas) + ->printCopyright() + ; + + return $this; + } + + public function showMap() + { + if ($this->mapCache) { + if (!$this->mapCache->checkMapCache()) { + $this->makeMap(); + + $this->mapCache->cache($this->canvas); + } else { + $output = new CacheOutput(); + $output + ->setFilename($this->mapCache->getFilename()) + ->sendHeader() + ->sendImage() + ; + } + } else { + $this->makeMap(); + + $output = new ImageOutput(); + $output + ->setImage($this->image) + ->sendHeader() + ->sendImage() + ; + } + } +} diff --git a/src/Printer/PrinterInterface.php b/src/Printer/PrinterInterface.php new file mode 100644 index 0000000..3863458 --- /dev/null +++ b/src/Printer/PrinterInterface.php @@ -0,0 +1,75 @@ +curl = new Curl(); + $this->imagine = new Imagine(); + } + + public function setTileLayerUrl(string $tileLayerUrl): TileResolverInterface + { + $this->tileLayerUrl = $tileLayerUrl; + + return $this; + } +} diff --git a/src/TileResolver/CachedTileResolver.php b/src/TileResolver/CachedTileResolver.php new file mode 100644 index 0000000..b2a1226 --- /dev/null +++ b/src/TileResolver/CachedTileResolver.php @@ -0,0 +1,66 @@ +resolve($zoom, $x, $y); + + $cachedTile = $this->checkTileCache($url); + + if ($cachedTile) { + return $cachedTile; + } + + $tile = parent::fetch($zoom, $x, $y); + + if ($tile) { + $this->writeTileToCache($url, $tile); + } + + return $tile; + } + + protected function tileUrlToFilename(string $url): string + { + return $this->tileCacheBaseDir . '/' . str_replace(['http://', 'https://'], '', $url); + } + + protected function checkTileCache(string $url): ?ImageInterface + { + $filename = $this->tileUrlToFilename($url); + + if (file_exists($filename)) { + $tileImagine = $this->imagine->open($filename); + + return $tileImagine; + } + + return null; + } + + protected function writeTileToCache($url, ImageInterface $tileImage): CachedTileResolver + { + $filename = $this->tileUrlToFilename($url); + + $this->mkdir_recursive(dirname($filename), 0777); + + $tileImage->save($filename); + + return $this; + } + + protected function mkdir_recursive($pathname, $mode): bool + { + is_dir(dirname($pathname)) || $this->mkdir_recursive(dirname($pathname), $mode); + + return is_dir($pathname) || @mkdir($pathname, $mode); + } +} diff --git a/src/TileResolver/TileResolver.php b/src/TileResolver/TileResolver.php new file mode 100644 index 0000000..27da539 --- /dev/null +++ b/src/TileResolver/TileResolver.php @@ -0,0 +1,27 @@ +tileLayerUrl); + } + + public function fetch(int $zoom, int $x, int $y): ImageInterface + { + $url = $this->resolve($zoom, $x, $y); + + $this->curl->get($url); + + $image = $this + ->imagine + ->load($this->curl->response) + ; + + return $image; + } +} diff --git a/src/TileResolver/TileResolverInterface.php b/src/TileResolver/TileResolverInterface.php new file mode 100644 index 0000000..22eb00f --- /dev/null +++ b/src/TileResolver/TileResolverInterface.php @@ -0,0 +1,12 @@ + - * - * USAGE: - * - * staticmap.php?center=40.714728,-73.998672&zoom=14&size=512x512&maptype=mapnik&markers=40.702147,-74.015794,blues|40.711614,-74.012318,greeng|40.718217,-73.998284,redc - * - */ - -error_reporting(0); -ini_set('display_errors', 'off'); - -Class staticMapLite -{ - - protected $maxWidth = 1024; - protected $maxHeight = 1024; - - protected $tileSize = 256; - protected $tileSrcUrl = array('mapnik' => 'http://tile.openstreetmap.org/{Z}/{X}/{Y}.png', - 'osmarenderer' => 'http://otile1.mqcdn.com/tiles/1.0.0/osm/{Z}/{X}/{Y}.png', - 'cycle' => 'http://a.tile.opencyclemap.org/cycle/{Z}/{X}/{Y}.png', - ); - - protected $tileDefaultSrc = 'mapnik'; - protected $markerBaseDir = 'images/markers'; - protected $osmLogo = 'images/osm_logo.png'; - - protected $markerPrototypes = array( - // found at http://www.mapito.net/map-marker-icons.html - 'lighblue' => array('regex' => '/^lightblue([0-9]+)$/', - 'extension' => '.png', - 'shadow' => false, - 'offsetImage' => '0,-19', - 'offsetShadow' => false - ), - // openlayers std markers - 'ol-marker' => array('regex' => '/^ol-marker(|-blue|-gold|-green)+$/', - 'extension' => '.png', - 'shadow' => '../marker_shadow.png', - 'offsetImage' => '-10,-25', - 'offsetShadow' => '-1,-13' - ), - // taken from http://www.visual-case.it/cgi-bin/vc/GMapsIcons.pl - 'ylw' => array('regex' => '/^(pink|purple|red|ltblu|ylw)-pushpin$/', - 'extension' => '.png', - 'shadow' => '../marker_shadow.png', - 'offsetImage' => '-10,-32', - 'offsetShadow' => '-1,-13' - ), - // http://svn.openstreetmap.org/sites/other/StaticMap/symbols/0.png - 'ojw' => array('regex' => '/^bullseye$/', - 'extension' => '.png', - 'shadow' => false, - 'offsetImage' => '-20,-20', - 'offsetShadow' => false - ) - ); - - - protected $useTileCache = true; - protected $tileCacheBaseDir = '../cache/tiles'; - - protected $useMapCache = true; - protected $mapCacheBaseDir = '../cache/maps'; - protected $mapCacheID = ''; - protected $mapCacheFile = ''; - protected $mapCacheExtension = 'png'; - - protected $zoom, $lat, $lon, $width, $height, $markers, $image, $maptype; - protected $centerX, $centerY, $offsetX, $offsetY; - - public function __construct() - { - $this->zoom = 0; - $this->lat = 0; - $this->lon = 0; - $this->width = 500; - $this->height = 350; - $this->markers = array(); - $this->maptype = $this->tileDefaultSrc; - } - - public function parseParams() - { - global $_GET; - - if (!empty($_GET['show'])) { - $this->parseOjwParams(); - } - else { - $this->parseLiteParams(); - } - } - - public function parseLiteParams() - { - // get zoom from GET paramter - $this->zoom = $_GET['zoom'] ? intval($_GET['zoom']) : 0; - if ($this->zoom > 18) $this->zoom = 18; - - // get lat and lon from GET paramter - list($this->lat, $this->lon) = explode(',', $_GET['center']); - $this->lat = floatval($this->lat); - $this->lon = floatval($this->lon); - - // get size from GET paramter - if ($_GET['size']) { - list($this->width, $this->height) = explode('x', $_GET['size']); - $this->width = intval($this->width); - if ($this->width > $this->maxWidth) $this->width = $this->maxWidth; - $this->height = intval($this->height); - if ($this->height > $this->maxHeight) $this->height = $this->maxHeight; - } - if (!empty($_GET['markers'])) { - $markers = explode('|', $_GET['markers']); - foreach ($markers as $marker) { - list($markerLat, $markerLon, $markerType) = explode(',', $marker); - $markerLat = floatval($markerLat); - $markerLon = floatval($markerLon); - $markerType = basename($markerType); - $this->markers[] = array('lat' => $markerLat, 'lon' => $markerLon, 'type' => $markerType); - } - - } - if ($_GET['maptype']) { - if (array_key_exists($_GET['maptype'], $this->tileSrcUrl)) $this->maptype = $_GET['maptype']; - } - } - - public function parseOjwParams() - { - $this->lat = floatval($_GET['lat']); - $this->lon = floatval($_GET['lon']); - $this->zoom = intval($_GET['z']); - - $this->width = intval($_GET['w']); - if ($this->width > $this->maxWidth) $this->width = $this->maxWidth; - $this->height = intval($_GET['h']); - if ($this->height > $this->maxHeight) $this->height = $this->maxHeight; - - - if (!empty($_GET['mlat0'])) { - $markerLat = floatval($_GET['mlat0']); - if (!empty($_GET['mlon0'])) { - $markerLon = floatval($_GET['mlon0']); - $this->markers[] = array('lat' => $markerLat, 'lon' => $markerLon, 'type' => "bullseye"); - } - } - } - - public function lonToTile($long, $zoom) - { - return (($long + 180) / 360) * pow(2, $zoom); - } - - public function latToTile($lat, $zoom) - { - return (1 - log(tan($lat * pi() / 180) + 1 / cos($lat * pi() / 180)) / pi()) / 2 * pow(2, $zoom); - } - - public function initCoords() - { - $this->centerX = $this->lonToTile($this->lon, $this->zoom); - $this->centerY = $this->latToTile($this->lat, $this->zoom); - $this->offsetX = floor((floor($this->centerX) - $this->centerX) * $this->tileSize); - $this->offsetY = floor((floor($this->centerY) - $this->centerY) * $this->tileSize); - } - - public function createBaseMap() - { - $this->image = imagecreatetruecolor($this->width, $this->height); - $startX = floor($this->centerX - ($this->width / $this->tileSize) / 2); - $startY = floor($this->centerY - ($this->height / $this->tileSize) / 2); - $endX = ceil($this->centerX + ($this->width / $this->tileSize) / 2); - $endY = ceil($this->centerY + ($this->height / $this->tileSize) / 2); - $this->offsetX = -floor(($this->centerX - floor($this->centerX)) * $this->tileSize); - $this->offsetY = -floor(($this->centerY - floor($this->centerY)) * $this->tileSize); - $this->offsetX += floor($this->width / 2); - $this->offsetY += floor($this->height / 2); - $this->offsetX += floor($startX - floor($this->centerX)) * $this->tileSize; - $this->offsetY += floor($startY - floor($this->centerY)) * $this->tileSize; - - for ($x = $startX; $x <= $endX; $x++) { - for ($y = $startY; $y <= $endY; $y++) { - $url = str_replace(array('{Z}', '{X}', '{Y}'), array($this->zoom, $x, $y), $this->tileSrcUrl[$this->maptype]); - $tileData = $this->fetchTile($url); - if ($tileData) { - $tileImage = imagecreatefromstring($tileData); - } else { - $tileImage = imagecreate($this->tileSize, $this->tileSize); - $color = imagecolorallocate($tileImage, 255, 255, 255); - @imagestring($tileImage, 1, 127, 127, 'err', $color); - } - $destX = ($x - $startX) * $this->tileSize + $this->offsetX; - $destY = ($y - $startY) * $this->tileSize + $this->offsetY; - imagecopy($this->image, $tileImage, $destX, $destY, 0, 0, $this->tileSize, $this->tileSize); - } - } - } - - - public function placeMarkers() - { - // loop thru marker array - foreach ($this->markers as $marker) { - // set some local variables - $markerLat = $marker['lat']; - $markerLon = $marker['lon']; - $markerType = $marker['type']; - // clear variables from previous loops - $markerFilename = ''; - $markerShadow = ''; - $matches = false; - // check for marker type, get settings from markerPrototypes - if ($markerType) { - foreach ($this->markerPrototypes as $markerPrototype) { - if (preg_match($markerPrototype['regex'], $markerType, $matches)) { - $markerFilename = $matches[0] . $markerPrototype['extension']; - if ($markerPrototype['offsetImage']) { - list($markerImageOffsetX, $markerImageOffsetY) = explode(",", $markerPrototype['offsetImage']); - } - $markerShadow = $markerPrototype['shadow']; - if ($markerShadow) { - list($markerShadowOffsetX, $markerShadowOffsetY) = explode(",", $markerPrototype['offsetShadow']); - } - } - - } - } - - // check required files or set default - if ($markerFilename == '' || !file_exists($this->markerBaseDir . '/' . $markerFilename)) { - $markerIndex++; - $markerFilename = 'lightblue' . $markerIndex . '.png'; - $markerImageOffsetX = 0; - $markerImageOffsetY = -19; - } - - // create img resource - if (file_exists($this->markerBaseDir . '/' . $markerFilename)) { - $markerImg = imagecreatefrompng($this->markerBaseDir . '/' . $markerFilename); - } else { - $markerImg = imagecreatefrompng($this->markerBaseDir . '/lightblue1.png'); - } - - // check for shadow + create shadow recource - if ($markerShadow && file_exists($this->markerBaseDir . '/' . $markerShadow)) { - $markerShadowImg = imagecreatefrompng($this->markerBaseDir . '/' . $markerShadow); - } - - // calc position - $destX = floor(($this->width / 2) - $this->tileSize * ($this->centerX - $this->lonToTile($markerLon, $this->zoom))); - $destY = floor(($this->height / 2) - $this->tileSize * ($this->centerY - $this->latToTile($markerLat, $this->zoom))); - - // copy shadow on basemap - if ($markerShadow && $markerShadowImg) { - imagecopy($this->image, $markerShadowImg, $destX + intval($markerShadowOffsetX), $destY + intval($markerShadowOffsetY), - 0, 0, imagesx($markerShadowImg), imagesy($markerShadowImg)); - } - - // copy marker on basemap above shadow - imagecopy($this->image, $markerImg, $destX + intval($markerImageOffsetX), $destY + intval($markerImageOffsetY), - 0, 0, imagesx($markerImg), imagesy($markerImg)); - - }; - } - - - public function tileUrlToFilename($url) - { - return $this->tileCacheBaseDir . "/" . str_replace(array('http://'), '', $url); - } - - public function checkTileCache($url) - { - $filename = $this->tileUrlToFilename($url); - if (file_exists($filename)) { - return file_get_contents($filename); - } - } - - public function checkMapCache() - { - $this->mapCacheID = md5($this->serializeParams()); - $filename = $this->mapCacheIDToFilename(); - if (file_exists($filename)) return true; - } - - public function serializeParams() - { - return join("&", array($this->zoom, $this->lat, $this->lon, $this->width, $this->height, serialize($this->markers), $this->maptype)); - } - - public function mapCacheIDToFilename() - { - if (!$this->mapCacheFile) { - $this->mapCacheFile = $this->mapCacheBaseDir . "/" . $this->maptype . "/" . $this->zoom . "/cache_" . substr($this->mapCacheID, 0, 2) . "/" . substr($this->mapCacheID, 2, 2) . "/" . substr($this->mapCacheID, 4); - } - return $this->mapCacheFile . "." . $this->mapCacheExtension; - } - - - public function mkdir_recursive($pathname, $mode) - { - is_dir(dirname($pathname)) || $this->mkdir_recursive(dirname($pathname), $mode); - return is_dir($pathname) || @mkdir($pathname, $mode); - } - - public function writeTileToCache($url, $data) - { - $filename = $this->tileUrlToFilename($url); - $this->mkdir_recursive(dirname($filename), 0777); - file_put_contents($filename, $data); - } - - public function fetchTile($url) - { - if ($this->useTileCache && ($cached = $this->checkTileCache($url))) return $cached; - $ch = curl_init(); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0"); - curl_setopt($ch, CURLOPT_URL, $url); - $tile = curl_exec($ch); - curl_close($ch); - if ($tile && $this->useTileCache) { - $this->writeTileToCache($url, $tile); - } - return $tile; - - } - - public function copyrightNotice() - { - $logoImg = imagecreatefrompng($this->osmLogo); - imagecopy($this->image, $logoImg, imagesx($this->image) - imagesx($logoImg), imagesy($this->image) - imagesy($logoImg), 0, 0, imagesx($logoImg), imagesy($logoImg)); - - } - - public function sendHeader() - { - header('Content-Type: image/png'); - $expires = 60 * 60 * 24 * 14; - header("Pragma: public"); - header("Cache-Control: maxage=" . $expires); - header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $expires) . ' GMT'); - } - - public function makeMap() - { - $this->initCoords(); - $this->createBaseMap(); - if (count($this->markers)) $this->placeMarkers(); - if ($this->osmLogo) $this->copyrightNotice(); - } - - public function showMap() - { - $this->parseParams(); - if ($this->useMapCache) { - // use map cache, so check cache for map - if (!$this->checkMapCache()) { - // map is not in cache, needs to be build - $this->makeMap(); - $this->mkdir_recursive(dirname($this->mapCacheIDToFilename()), 0777); - imagepng($this->image, $this->mapCacheIDToFilename(), 9); - $this->sendHeader(); - if (file_exists($this->mapCacheIDToFilename())) { - return file_get_contents($this->mapCacheIDToFilename()); - } else { - return imagepng($this->image); - } - } else { - // map is in cache - $this->sendHeader(); - return file_get_contents($this->mapCacheIDToFilename()); - } - - } else { - // no cache, make map, send headers and deliver png - $this->makeMap(); - $this->sendHeader(); - return imagepng($this->image); - - } - } - -} - -$map = new staticMapLite(); -print $map->showMap(); diff --git a/index.html b/web/index.html similarity index 97% rename from index.html rename to web/index.html index c61052b..4fb2c0c 100644 --- a/index.html +++ b/web/index.html @@ -70,7 +70,7 @@ a.external:after { content: "\2197";} staticMapLite - simple map for your website

-

+

This image was created using the following simple <img> tag:

<img src="staticmap.php?center=40.714728,-73.998672&zoom=14&size=865x512&maptype=mapnik" />
@@ -119,4 +119,4 @@ a.external:after { content: "\2197";} - \ No newline at end of file + diff --git a/web/info.php b/web/info.php new file mode 100644 index 0000000..c42d5a3 --- /dev/null +++ b/web/info.php @@ -0,0 +1,7 @@ + + * + * USAGE: + * + * staticmap.php?center=40.714728,-73.998672&zoom=14&size=512x512&maptype=mapnik&markers=40.702147,-74.015794,blues|40.711614,-74.012318,greeng|40.718217,-73.998284,redc + * + */ + +require_once '../vendor/autoload.php'; + +use StaticMapLite\Element\Factory\Marker\ExtraMarkerFactory; +use StaticMapLite\Element\Polyline\Polyline; +use StaticMapLite\Printer\Printer; + +$printer = new Printer(); + +list($centerLatitude, $centerLongitude) = explode(',', $_GET['center']); +list($width, $height) = explode('x', $_GET['size']); + +$printer + ->setCenter($centerLatitude, $centerLongitude) + ->setZoom($_GET['zoom']) + ->setSize($width, $height) + ->setMapType($_GET['maptype']) +; + +$markers = isset($_GET['markers']) ? $_GET['markers'] : null; + +if ($markers) { + $markerList = explode('|', $markers); + $markerFactory = new ExtraMarkerFactory(); + + foreach ($markerList as $markerData) { + list($markerLatitude, $markerLongitude, $markerShape, $markerColor, $markerIcon) = explode(',', $markerData); + + $marker = $markerFactory->create(floatval($markerLatitude), floatval($markerLongitude), $markerShape, $markerColor, $markerIcon); + + $printer->addMarker($marker); + } +} + +$polylines = isset($_GET['polylines']) ? $_GET['polylines'] : null; + +if ($polylines) { + $polylineList = explode('|', $polylines); + + foreach ($polylineList as $polylineData) { + list($polyline64String, $colorRed, $colorGreen, $colorBlue) = explode(',', $polylineData); + + $polylineString = base64_decode($polyline64String); + + $polyline = new Polyline($polylineString, $colorRed, $colorGreen, $colorBlue); + + $printer->addPolyline($polyline); + } +} + +$printer->showMap(); + + + +