Generate and display maps without external services or compromising on privacy.

Last update: Jun 24, 2022

Banner

PHP Geo SVG

GitHub Build Status Scrutinizer Code Quality Code Coverage

Generate and display maps without external services or compromising on privacy.

Why this package?

When searching for high quality SVG's for my blog, I ran into the issue that all SVG's where either too low quality, heavily polluted with unnecessary elements by the tool they were generated with, or in the wrong projection. This package provides the flexibility to generate maps manually or from geojson files, which are more readily available.

Features

  • Supports creation of SVGs from GeoJSON (directly from file, as a JSON string or from an array) and manual GeometryCollection.
  • Output the svg directly to your user on request or output to a file.
  • Render an entire world map or only part of it by using a bounding box.
  • Easy support for projections. Currently supported: EquiRectangular, Mercator and Miller. Please open a PR to add any extra ones.
  • When you create or edit a GeometryCollection, a Fluent Interface is provided to allow for method chaining.
Showcase
Countries - Equirectangular projection
Netherlands - Mercator projection

Table of Contents

Setup

To start right away, run the following command in your composer project;

composer require prinsfrank/php-geo-svg

Or for development only;

composer require prinsfrank/php-geo-svg --dev

The basics; creating an SVG

Let's say we want to create the following simple continent map:

Simplified continents map

There are multiple ways we can go about creating this map in svg using this package;

From a GeoJSON file

To create an SVG from a GeoJson file, create a new 'GeometryCollection' by calling the 'createFromGeoJSONFilePath' method on the 'GeometryCollectionFactory' as follows;

Show code

With variables:

$geoSVG = new GeoSVG();
$geometryCollection = GeometryCollectionFactory::createFromGeoJSONFilePath('/path/to/file.geojson');
$geoSVG->toFile($geometryCollection, 'output/file.svg');

Fluent:

(new GeoSVG())
    ->toFile(
        GeometryCollectionFactory::createFromGeoJSONFilePath(__DIR__ . '/path/to/file.geojson'),
        'output/file.svg'
    );

From a GeoJSON string

To create an SVG from a GeoJson string, create a new 'GeometryCollection' by calling the 'createFromGeoJsonString' method on the 'GeometryCollectionFactory' as follows;

Show code

With variables:

toFile($geometryCollection, 'output/file.svg'); ">
$geoJsonString = '{"type":"FeatureCollection","features":[{"type":"Feature","properties":{"featurecla":"Continent"},"geometry":{"type":"MultiLineString","coordinates":[[[-177,74],[-80,9],[-25,82]]]}},{"type":"Feature","properties":{"featurecla":"Continent"},"geometry":{"type":"MultiLineString","coordinates":[[[-80,9],[-37,-7],[-70,-55]]]}},{"type":"Feature","properties":{"featurecla":"Continent"},"geometry":{"type":"MultiLineString","coordinates":[[[-12,36],[30,37],[27,70],[-24,66]]]}},{"type":"Feature","properties":{"featurecla":"Continent"},"geometry":{"type":"MultiLineString","coordinates":[[[-12,36],[30,37],[51,11],[22,-35],[-17,17]]]}},{"type":"Feature","properties":{"featurecla":"Continent"},"geometry":{"type":"MultiLineString","coordinates":[[[27,70],[30,37],[51,11],[131,-2],[171,67]]]}},{"type":"Feature","properties":{"featurecla":"Continent"},"geometry":{"type":"MultiLineString","coordinates":[[[115,-15],[153,-15],[148,-43],[114,-35]]]}}]}';


$geoSVG = new GeoSVG();
$geometryCollection = GeometryCollectionFactory::createFromGeoJsonString($geoJsonString);
$geoSVG->toFile($geometryCollection, 'output/file.svg');

Fluent:

toFile( GeometryCollectionFactory::createFromGeoJsonString($geoJsonString), 'output/file.svg' ); ">
$geoJsonString = '{"type":"FeatureCollection","features":[{"type":"Feature","properties":{"featurecla":"Continent"},"geometry":{"type":"MultiLineString","coordinates":[[[-177,74],[-80,9],[-25,82]]]}},{"type":"Feature","properties":{"featurecla":"Continent"},"geometry":{"type":"MultiLineString","coordinates":[[[-80,9],[-37,-7],[-70,-55]]]}},{"type":"Feature","properties":{"featurecla":"Continent"},"geometry":{"type":"MultiLineString","coordinates":[[[-12,36],[30,37],[27,70],[-24,66]]]}},{"type":"Feature","properties":{"featurecla":"Continent"},"geometry":{"type":"MultiLineString","coordinates":[[[-12,36],[30,37],[51,11],[22,-35],[-17,17]]]}},{"type":"Feature","properties":{"featurecla":"Continent"},"geometry":{"type":"MultiLineString","coordinates":[[[27,70],[30,37],[51,11],[131,-2],[171,67]]]}},{"type":"Feature","properties":{"featurecla":"Continent"},"geometry":{"type":"MultiLineString","coordinates":[[[115,-15],[153,-15],[148,-43],[114,-35]]]}}]}';

(new GeoSVG())
    ->toFile(
        GeometryCollectionFactory::createFromGeoJsonString($geoJsonString),
        'output/file.svg'
    );

From a GeoJSON array

To create an SVG from a GeoJson array, create a new 'GeometryCollection' by calling the 'createFromGeoJSONArray' method on the 'GeometryCollectionFactory' as follows;

Show code

With variables:

$geoJsonArray = ['type'=>'FeatureCollection','features'=>[['type'=>'Feature','properties'=>['featurecla'=>'Continent'],'geometry'=>['type'=>'MultiLineString','coordinates'=>[[[-177,74],[-80,9],[-25,82]]]]],['type'=>'Feature','properties'=>['featurecla'=>'Continent'],'geometry'=>['type'=>'MultiLineString','coordinates'=>[[[-80,9],[-37,-7],[-70,-55]]]]],['type'=>'Feature','properties'=>['featurecla'=>'Continent'],'geometry'=>['type'=>'MultiLineString','coordinates'=>[[[-12,36],[30,37],[27,70],[-24,66]]]]],['type'=>'Feature','properties'=>['featurecla'=>'Continent'],'geometry'=>['type'=>'MultiLineString','coordinates'=>[[[-12,36],[30,37],[51,11],[22,-35],[-17,17]]]]],['type'=>'Feature','properties'=>['featurecla'=>'Continent'],'geometry'=>['type'=>'MultiLineString','coordinates'=>[[[27,70],[30,37],[51,11],[131,-2],[171,67]]]]],['type'=>'Feature','properties'=>['featurecla'=>'Continent'],'geometry'=>['type'=>'MultiLineString','coordinates'=>[[[115,-15],[153,-15],[148,-43],[114,-35]]]]]]];


$geoSVG = new GeoSVG();
$geometryCollection = GeometryCollectionFactory::createFromGeoJsonArray($geoJsonArray);
$geoSVG->toFile($geometryCollection, 'output/file.svg');

Fluent:

$geoJsonArray = ['type'=>'FeatureCollection','features'=>[['type'=>'Feature','properties'=>['featurecla'=>'Continent'],'geometry'=>['type'=>'MultiLineString','coordinates'=>[[[-177,74],[-80,9],[-25,82]]]]],['type'=>'Feature','properties'=>['featurecla'=>'Continent'],'geometry'=>['type'=>'MultiLineString','coordinates'=>[[[-80,9],[-37,-7],[-70,-55]]]]],['type'=>'Feature','properties'=>['featurecla'=>'Continent'],'geometry'=>['type'=>'MultiLineString','coordinates'=>[[[-12,36],[30,37],[27,70],[-24,66]]]]],['type'=>'Feature','properties'=>['featurecla'=>'Continent'],'geometry'=>['type'=>'MultiLineString','coordinates'=>[[[-12,36],[30,37],[51,11],[22,-35],[-17,17]]]]],['type'=>'Feature','properties'=>['featurecla'=>'Continent'],'geometry'=>['type'=>'MultiLineString','coordinates'=>[[[27,70],[30,37],[51,11],[131,-2],[171,67]]]]],['type'=>'Feature','properties'=>['featurecla'=>'Continent'],'geometry'=>['type'=>'MultiLineString','coordinates'=>[[[115,-15],[153,-15],[148,-43],[114,-35]]]]]]];

(new GeoSVG())
    ->toFile(
        GeometryCollectionFactory::createFromGeoJsonArray($geoJsonArray),
        'output/file.svg'
    );

From building your own GeometryCollection

To build an SVG manually from a GeometryCollection, create the object and add any geometry you want:

Show code

With variables:

$geoSVG = new GeoSVG();
$geometryCollection = new GeometryCollection();

$continents = new MultiPolygon();
$geometryCollection->addGeometryObject($continents);

$outerBorderNorthAmerica = new LineString();
$outerBorderNorthAmerica->addPosition(new Position(-177, 74));
$outerBorderNorthAmerica->addPosition(new Position(-80, 9));
$outerBorderNorthAmerica->addPosition(new Position(-25, 82));
$outerBorderNorthAmerica->setFeatureClass('Continent');
$outerBorderNorthAmerica->setTitle('North America');
$polygonNorthAmerica = new Polygon($outerBorderNorthAmerica);
$continents->addPolygon($polygonNorthAmerica);


$outerBorderSouthAmerica = new LineString();
$outerBorderSouthAmerica->addPosition(new Position(-80, 9));
$outerBorderSouthAmerica->addPosition(new Position(-37, -7));
$outerBorderSouthAmerica->addPosition(new Position(-70, -55));
$outerBorderSouthAmerica->setFeatureClass('Continent');
$outerBorderSouthAmerica->setTitle('South America');
$polygonSouthAmerica = new Polygon($outerBorderSouthAmerica);
$continents->addPolygon($polygonSouthAmerica);

$outerBorderEurope = new LineString();
$outerBorderEurope->addPosition(new Position(-12, 36));
$outerBorderEurope->addPosition(new Position(30, 37));
$outerBorderEurope->addPosition(new Position(27, 70));
$outerBorderEurope->addPosition(new Position(-24, 66));
$outerBorderEurope->setFeatureClass('Continent');
$outerBorderEurope->setTitle('Europe');
$polygonEurope = new Polygon($outerBorderEurope);
$continents->addPolygon($polygonEurope);

$outerBorderAfrica = new LineString();
$outerBorderAfrica->addPosition(new Position(-12, 36));
$outerBorderAfrica->addPosition(new Position(30, 37));
$outerBorderAfrica->addPosition(new Position(51, 11));
$outerBorderAfrica->addPosition(new Position(22, -35));
$outerBorderAfrica->addPosition(new Position(-17, 17));
$outerBorderAfrica->setFeatureClass('Continent');
$outerBorderAfrica->setTitle('Africa');
$polygonAfrica = new Polygon($outerBorderAfrica);
$continents->addPolygon($polygonAfrica);

$outerBorderAsia = new LineString();
$outerBorderAsia->addPosition(new Position(27, 70));
$outerBorderAsia->addPosition(new Position(30, 37));
$outerBorderAsia->addPosition(new Position(51, 11));
$outerBorderAsia->addPosition(new Position(131, -2));
$outerBorderAsia->addPosition(new Position(171, 67));
$outerBorderAsia->setFeatureClass('Continent');
$outerBorderAsia->setTitle('Asia');
$polygonAsia = new Polygon($outerBorderAsia);
$continents->addPolygon($polygonAsia);

$outerBorderAustralia = new LineString();
$outerBorderAustralia->addPosition(new Position(115, -15));
$outerBorderAustralia->addPosition(new Position(153, -15));
$outerBorderAustralia->addPosition(new Position(148, -43));
$outerBorderAustralia->addPosition(new Position(114, -35));
$outerBorderAustralia->setFeatureClass('Continent');
$outerBorderAustralia->setTitle('Australia');
$polygonAustralia = new Polygon($outerBorderAustralia);
$continents->addPolygon($polygonAustralia);

$geoSVG->toFile($geometryCollection, 'output/file.svg');

Fluent:

(new GeoSVG())
    ->toFile(
        (new GeometryCollection())
            ->addGeometryObject(
                (new MultiPolygon())
                    ->addPolygon(
                        new Polygon(
                            (new LineString())
                                ->addPosition(new Position(-177, 74))
                                ->addPosition(new Position(-80, 9))
                                ->addPosition(new Position(-25, 82))
                                ->setFeatureClass('Continent')
                                ->setTitle('North America')
                        )
                    )
                    ->addPolygon(
                        new Polygon(
                            (new LineString())
                                ->addPosition(new Position(-80, 9))
                                ->addPosition(new Position(-37, -7))
                                ->addPosition(new Position(-70, -55))
                                ->setFeatureClass('Continent')
                                ->setTitle('South America')
                        )
                    )
                    ->addPolygon(
                        new Polygon(
                            (new LineString())
                                ->addPosition(new Position(-12, 36))
                                ->addPosition(new Position(30, 37))
                                ->addPosition(new Position(27, 70))
                                ->addPosition(new Position(-24, 66))
                                ->setFeatureClass('Continent')
                                ->setTitle('Europe')
                        )
                    )
                    ->addPolygon(
                        new Polygon(
                            (new LineString())
                                ->addPosition(new Position(-12, 36))
                                ->addPosition(new Position(30, 37))
                                ->addPosition(new Position(51, 11))
                                ->addPosition(new Position(22, -35))
                                ->addPosition(new Position(-17, 17))
                                ->setFeatureClass('Continent')
                                ->setTitle('Africa')
                        )
                    )
                    ->addPolygon(
                        new Polygon(
                            (new LineString())
                                ->addPosition(new Position(27, 70))
                                ->addPosition(new Position(30, 37))
                                ->addPosition(new Position(51, 11))
                                ->addPosition(new Position(131, -2))
                                ->addPosition(new Position(171, 67))
                                ->setFeatureClass('Continent')
                                ->setTitle('Asia')
                        )
                    )
                    ->addPolygon(
                        new Polygon(
                            (new LineString())
                                ->addPosition(new Position(115, -15))
                                ->addPosition(new Position(153, -15))
                                ->addPosition(new Position(148, -43))
                                ->addPosition(new Position(114, -35))
                                ->setFeatureClass('Continent')
                                ->setTitle('Australia')
                        )
                    )
            ),
        'output/file.svg'
    );

Different globe-to-plane transformations; Projections

If you prefer a different projection other than the default EquiRectangular, you can! Currently, the following projections are supported, but please feel free to add any and open a PR;

  • Equirectangular
  • Mercator
  • Miller

To specify the projection you want to use, you can do so either using the constructor;

$geoSVG = new GeoSVG(new MercatorProjection);

Or using the 'setProjection' method;

$geoSVG = new GeoSVG();
$geoSVG->setProjection(new MercatorProjection);

Displaying only parts of the world; Using bounding boxes

If you want to use a bounding box, you have to know both the most southWestern and northEastern coordinates you want to show, and create 'BoundingBoxPositions' for both of them. Pass those along to a bounding box object and you have yourself a bounding box;

$northEastern = new BoundingBoxPosition(7.2, 53.5);
$southWestern = new BoundingBoxPosition(3.5, 50.8);

$boundingBox  = new BoundingBox($southWestern, $northEastern);

To actually use it, either pass the bounding box in the constructor after the projection;

$geoSVG = new GeoSVG($projection, $boundingBox);

Or set the bounding box using the 'setBoundingBox' method;

$geoSVG = new GeoSVG();
$geoSVG->setBoundingBox($boundingBox);

GitHub

https://github.com/PrinsFrank/php-geo-svg
You might also like...

Pretty Good Privacy (PGP) is an encryption program that provides cryptographic privacy and authentication for data communication.

Pretty Good Privacy (PGP) is an encryption program that provides cryptographic privacy and authentication for data communication. PGP is used for signing, encrypting, and decrypting texts, e-mails, files, directories, and whole disk partitions and to increase the security of e-mail communications. Phil Zimmermann developed PGP in 1991.

Dec 31, 2021

A modern PHP library that allows you to make resilient calls to external services

A modern PHP library that allows you to make resilient calls to external services

Resiliency, an implementation for resilient and modern PHP applications Main principles This library is compatible with PHP 7.4+. Installation compose

Mar 15, 2022

Simple analyse the traffic of your OctoberCMS-based website without relying on an external service.

Simple Analytics for OctoberCMS Simple analyse the traffic of your website without relying on an external service. The simple version of this plugin (

Sep 12, 2021

Curated list that contain code, snippets or examples without libraries or external packages for developers.

Awesome WordPress Developer Tips Curated list that contain very awesome and ready code, snippets or examples without libraries or external packages ma

Aug 16, 2022

Collection of Google Maps API Web Services for Laravel

Collection of Google Maps API Web Services for Laravel Provides convenient way of setting up and making requests to Maps API from Laravel application.

Aug 2, 2022

Newsprint is a simple web application that will fetch the front page of a newspaper and display it on an eink display

Newsprint is a simple web application that will fetch the front page of a newspaper and display it on an eink display

Newsprint is a simple web application that will fetch the front page of a newspaper and display it on an eink display. The specific resolutions and sizes have been setup to work with a 32" eInk place & play display from Visionect but can be modified for other screen resolutions.

Aug 6, 2022

Utilities to scan PHP code and generate class maps.

composer/class-map-generator Utilities to generate class maps and scan PHP code. Installation Install the latest version with: $ composer require comp

Aug 1, 2022

A privacy respecting free as in freedom meta search engine for Google and popular torrent sites

A privacy respecting free as in freedom meta search engine for Google and popular torrent sites

A privacy respecting free as in freedom meta search engine for Google and popular torrent sites

Aug 13, 2022

A simple helper to generate and display pagination navigation links

Intro to CHocoCode Paginator Friendly PHP paginator to paginate everything This package introduces a different way of pagination handling. You can rea

Aug 24, 2021

Open Source Smart Meter with focus on privacy - you remain the master of your data.

Open Source Smart Meter with focus on privacy - you remain the master of your data.

volkszaehler.org volkszaehler.org is a free smart meter implementation with focus on data privacy. Demo demo.volkszaehler.org Quickstart The easiest w

Aug 2, 2022

The modern, privacy-aware URL Shortener built in PHP.

The modern, privacy-aware URL Shortener built in PHP.

About UrlHum UrlHum is a modern, privacy-aware and fast URL Shortener built with PHP and the Laravel Framework. At the moment UrlHum is heavily under

Aug 9, 2022

html-sanitizer is a library aiming at handling, cleaning and sanitizing HTML sent by external users

html-sanitizer html-sanitizer is a library aiming at handling, cleaning and sanitizing HTML sent by external users (who you cannot trust), allowing yo

Jul 31, 2022

AES 128 bit Encryption and Decryption algorithm excuted purely on PHP with no external libraries.

AES 128 bit Encryption and Decryption algorithm excuted purely on PHP with no external libraries.

AES128 Executed with PHP Advanced Encryption Standard (AES) is a specification for the encryption of electronic data established by the U.S National I

Aug 8, 2022

MediaWiki extension that allows embedding external content

MediaWiki extension that allows embedding external content, specified by URL, into your wiki pages.

May 4, 2022

This application gives you the ability to send a newsletter to multiple subscribers with use of SMTP or an external driver like Mailgun

This application gives you the ability to send a newsletter to multiple subscribers with use of SMTP or an external driver like Mailgun

Laravel Newsletter Laravel Newsletter is an open source project that can be used for sending newsletters to multiple subscribers, mailing lists, ... a

Jul 1, 2022

Register for multiple Livestorm sessions from an external form. Practical use of Livestorm API with PHP/Javascript.

Livestorm Multi Session Registration Register for multiple Livestorm sessions from an external form. Practical use of Livestorm API with PHP/Javascrip

Dec 24, 2021

Silverstripe-fulltextsearch - Adds external full text search engine support to SilverStripe

FullTextSearch module Adds support for fulltext search engines like Sphinx and Solr to SilverStripe CMS. Compatible with PHP 7.2 Important notes when

Jun 20, 2022
Comments
  • 1. Error when running the example

    I tried to run this example.

    https://github.com/PrinsFrank/php-geo-svg#from-a-geojson-array

    Problem:

    Parse error: syntax error, unexpected '?', expecting function (T_FUNCTION) or const (T_CONST) in C:......vendor\prinsfrank\php-geo-svg\src\GeoSVG.php on line 24

    Reviewed by JUREXT at 2021-12-11 09:10
New WordPress plugin to render a map with multiple markers using the open source maps provider OpenStreetMap

markers-on-openstreetmap New WordPress plugin to render a map with multiple markers using the open source maps provider OpenStreetMap A friend of mine

Oct 25, 2021
A weather data tile generator for digital maps using the Web Mercator projection
A weather data tile generator for digital maps using the Web Mercator projection

Weather data tile generator for Web Mercator maps This is a weather data tile generator for digital maps, which is compatible with Leaflet and in gene

Oct 31, 2021
GeoSpatial integration on Laravel 5.2+ that supports MySQL and PostgreSQL.

Features GeoSpatial integration on Laravel 5.2+: Create geospatial columns using Schema and migrations Save and retrieve geospatial attributes using d

May 22, 2022
Free database of geographic place names and corresponding geospatial data

FreeGeoDB Free database of geographic place names and corresponding geospatial data Entities airports cities countries (admin-0) lakes ports railroads

Jul 27, 2022
Geo-related tools PHP 5.4+ library built atop Geocoder and React libraries

Geotools Geotools is a PHP geo-related library, built atop Geocoder and React libraries. Features Batch geocode & reverse geocoding request(s) in seri

Aug 7, 2022
PHP library to easily get static image from French Cadastral Government map with markers and lines.
PHP library to easily get static image from French Cadastral Government map with markers and lines.

PHP French Cadastral Map Static API PHP library to easily get static image from French Cadastral Government map with markers and lines. Map source : c

May 24, 2022
PHP library to easily get static image from OpenStreetMap (OSM) with markers and lines.
PHP library to easily get static image from OpenStreetMap (OSM) with markers and lines.

PHP OpenStreetMap Static API PHP library to easily get static image from OpenStreetMap with markers and lines. ✨ Supporting ⭐ Star this repository to

Jul 28, 2022
Use: [i] to share item and name in hand, [coor] to share you current coordinates

General Now you can share your Coordinates and Item with Prefix Example if you type [i] in message, later it will be automatically replaced into the n

Oct 15, 2021
Official PHP library for IPinfo (IP geolocation and other types of IP data)

This is the official PHP client library for the IPinfo.io IP address API, allowing you to lookup your own IP address,

Aug 14, 2022