prinsfrank / php-geo-svg
生成Geo SVG
Requires
- php: ^8.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.2
- phpunit/phpunit: ^9.5
- prinsfrank/natural-earth-vector-geojson-only: ^4.1.0
Suggests
- prinsfrank/natural-earth-vector-geojson-only: Provides open source GeoJSON data sets
README
PHP Geo SVG
无需外部服务或牺牲隐私即可生成和显示地图。
为什么使用这个包?
在寻找高质量SVG文件用于我的博客时,我发现所有SVG文件要么质量太低,要么被生成工具中的不必要元素污染严重,或者投影方式不正确。这个包提供了手动生成地图或从geojson文件生成地图的灵活性,这些文件更易于获取。
特性
- 支持从GeoJSON(直接从文件、作为JSON字符串或从数组)创建SVG以及手动GeometryCollection。
- 根据请求直接输出svg到您的用户或输出到文件。
- 使用边界框绘制整个世界地图或其一部分。
- 易于支持的投影。目前支持:等矩形、墨卡托、米勒和几个等面积投影(Lambert、Behrmann、Smyth、Trystan、Hobo-Dyer、Gall-Peters、Balthasart和Tobler的方形世界地图)。请提交PR添加更多。
- 在创建或编辑GeometryCollection时,提供了一个Fluent接口,允许进行方法链式调用。
目录
设置
请确保您正在运行PHP 8.0或更高版本以使用此包
要立即开始,请在您的composer项目中运行以下命令;
composer require prinsfrank/php-geo-svg
或者仅用于开发;
composer require prinsfrank/php-geo-svg --dev
基础知识;创建SVG
假设我们想创建以下简单的洲际地图
我们可以使用多种方法在svg中使用此包创建此地图;
从GeoJSON文件
要从GeoJSON文件创建SVG,通过在GeometryCollectionFactory上调用createFromGeoJSONFilePath方法创建一个新的'GeometryCollection',如下所示;
显示代码
使用变量
$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'
);
从GeoJSON字符串
要从GeoJSON字符串创建SVG,通过在GeometryCollectionFactory上调用createFromGeoJsonString方法创建一个新的'GeometryCollection',如下所示;
显示代码
使用变量
$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
$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'
);
从GeoJSON数组
要从GeoJSON数组创建SVG,通过在GeometryCollectionFactory上调用createFromGeoJSONArray方法创建一个新的'GeometryCollection',如下所示;
显示代码
使用变量
$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'
);
从构建自己的GeometryCollection
要从GeometryCollection手动构建SVG,创建对象并添加任何您想要的几何形状
显示代码
使用变量
$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'
);
不同的地球到平面的变换;投影
如果您想使用除默认等矩形以外的其他投影,可以!目前支持以下投影,但请随意添加并提交PR;
- 等矩形
- 墨卡托
- 米勒
要指定要使用的投影,您可以使用构造函数;
$geoSVG = new GeoSVG(new MercatorProjection);
或使用'setProjection'方法;
$geoSVG = new GeoSVG();
$geoSVG->setProjection(new MercatorProjection);
仅显示世界的一部分;使用边界框
如果您想使用边界框,您必须知道要显示的最南西和最东北坐标,并为两者创建'BoundingBoxPositions'。将这些传递给边界框对象,您就有了一个边界框;
$northEastern = new BoundingBoxPosition(7.2, 53.5);
$southWestern = new BoundingBoxPosition(3.5, 50.8);
$boundingBox = new BoundingBox($southWestern, $northEastern);
实际上使用它,可以将边界框传递给构造函数,位于投影之后;
$geoSVG = new GeoSVG($projection, $boundingBox);
或使用'setBoundingBox'方法设置边界框;
$geoSVG = new GeoSVG();
$geoSVG->setBoundingBox($boundingBox);