Home > Back-end >  Convert geoJSON to SVG on device without using external service
Convert geoJSON to SVG on device without using external service

Time:10-13

CONTEXT: Need to display user's travelled path as SVG in list UI.(Should work offline)

INPUT: geoJSON with user travelled coordinates list as 'LineString' geometry.

const geoJsonData = {
      type: 'FeatureCollection',
      features: [
        {
          geometry: {
            type: 'LineString',
            coordinates: [
              [77.601923, 13.054111],
              [77.602046, 13.054097],
              [77.601984, 13.054261],
              [77.601954, 13.055172],
              [77.601861, 13.055171],
              [77.601613, 13.055162],
              [77.601534, 13.055159],
              [77.601223, 13.055148],
              [77.600907, 13.055136],
              [77.60085, 13.055134],
              [77.600585, 13.055125],
              [77.600492, 13.055122],
              [77.600256, 13.055113],
              [77.600144, 13.055116],
              [77.599887, 13.055124],
              [77.599678, 13.05515],
              [77.599419, 13.055186],
              [77.599237, 13.055262],
              [77.599059, 13.055332],
              [77.598979, 13.055365],
              [77.598696, 13.055528],
              [77.598316, 13.055735],
              [77.597942, 13.055909],
              [77.597914, 13.055993],
              [77.597911, 13.056119],
              [77.597979, 13.056299],
              [77.598195, 13.056721],
              [77.59833, 13.057012],
            ],
          },
          type: 'Feature',
          properties: {
            description: 'Southern Ave',
            lines: ['Green'],
          },
        },
      ],
    };

PROBLEM: Generated SVG path doesn't draw expected line.

EXPECTED RESULT: I tried using Aspose online convertor service this service gives me correct result. link : https://products.aspose.app/gis/viewer/geojson-to-svg

      \\Result :```<path d="m771.5 575.78l23.5 2.68-11.85-31.33-5.73-174.05-17.76.19-47.39 1.72-15.09.57-59.42 2.1-60.37 2.3-10.89.38-50.63 1.72-17.76.57-45.09 1.72-21.4-.57-49.1-1.53-39.93-4.97-49.48-6.88-34.78-14.52-34-13.37-15.29-6.31-54.06-31.14-72.6-39.54-71.46-33.25-5.35-16.05-.57-24.07 12.99-34.39 41.27-80.62 25.79-55.6"></path>```

enter image description here

Solutions Tried:

  1. geojson2svg (https://github.com/gagan-bansal/geojson2svg)

       var converter = geojson2svg({
        viewportSize: {width: 200, height: 300},
        output: 'svg',
       });
       const svgStr = converter.convert(geoJsonData);
    
    
    \\Result: <path d="M100.00038728329726,99.99993485162537 100.00038728391112,99.99993485169524 100.0003872836017,99.99993485087678 100.00038728345197,99.9999348463303 100.00038728298784,99.9999348463353 100.00038728175016,99.9999348463802 100.00038728135591,99.99993484639519 100.00038727980382,99.99993484645007 100.00038727822678,99.99993484650997 100.00038727794231,99.99993484651996 100.00038727661978,99.99993484656486 100.00038727615566,99.99993484657985 100.00038727497787,99.99993484662475 100.00038727441891,99.99993484660978 100.00038727313631,99.99993484656986 100.00038727209326,99.99993484644011 100.0003872708007,99.99993484626044 100.0003872698924,99.99993484588116 100.00038726900408,99.9999348455318 100.00038726860481,99.99993484536711 100.00038726719247,99.99993484455364 100.00038726529601,99.99993484352058 100.00038726342952,99.99993484265221 100.00038726328978,99.999934842233 100.00038726327482,99.99993484160417 100.00038726361419,99.99993484070585 100.00038726469216,99.99993483859981 100.00038726536589,99.99993483714753"/>```
    
    

This is almost like a circle

  1. D3
    const width = 200,
          height = 200;
    const gfg = d3
    .geoMercator()
    .scale(100)
    .rotate([0, 0])
    .center([0, 0])
    .translate([width / 2, height / 2]);
    
    
const pathGenerator = d3.geoPath().projection(gfg);
console.log(pathGenerator(geoJsonData));
\\Result: M235.44090622291156,77.01656453166521L235.44112089840957,77.01658961448477L235.44101268799594,77.01629578708086L235.4409603281184,77.01466360813455L235.44079801249794,77.01466539977226L235.44036517084345,77.01468152451129L235.44022728983254,77.0146868994242L235.43968449243516,77.01470660743753L235.43913296839153,77.01472810708745L235.43903348462416,77.01473169036237L235.43857097237236,77.01474781509897L235.43840865675196,77.01475319001105L235.43799675904847,77.0147693147469L235.43780128217227,77.014763939835L235.43735273255447,77.01474960673634L235.43698795874081,77.01470302416246L235.43653591846456,77.01463852520587L235.4362182685407,77.01450236071116L235.43590759993384,77.0143769460079L235.4357679735937,77.0143178219212L235.43527404541538,77.01402578464979L235.4346108202996,77.01365491495383L235.43395806715935,77.01334316917195L235.43390919794032,77.0131926711297L235.43390396195255,77.01296692397038L235.43402264434167,77.0126444278288L235.43439963546012,77.01188835262018L235.43463525490915,77.01136698247046
   ```

Generates a very tiny always filled pattern like enter image description here

Need offline solution that generates similar result as the online Aspose geojson to svg convertor

CodePudding user response:

I shall provide a solution in D3.js (version: 7.1.1)

const geojson = {
  type: 'FeatureCollection',
  features: [
    {
      geometry: {
        type: 'LineString',
        coordinates: [
          [77.601923, 13.054111],
          [77.602046, 13.054097],
          [77.601984, 13.054261],
          [77.601954, 13.055172],
          [77.601861, 13.055171],
          [77.601613, 13.055162],
          [77.601534, 13.055159],
          [77.601223, 13.055148],
          [77.600907, 13.055136],
          [77.60085, 13.055134],
          [77.600585, 13.055125],
          [77.600492, 13.055122],
          [77.600256, 13.055113],
          [77.600144, 13.055116],
          [77.599887, 13.055124],
          [77.599678, 13.05515],
          [77.599419, 13.055186],
          [77.599237, 13.055262],
          [77.599059, 13.055332],
          [77.598979, 13.055365],
          [77.598696, 13.055528],
          [77.598316, 13.055735],
          [77.597942, 13.055909],
          [77.597914, 13.055993],
          [77.597911, 13.056119],
          [77.597979, 13.056299],
          [77.598195, 13.056721],
          [77.59833, 13.057012],
        ],
      },
      type: 'Feature',
      properties: {
        description: 'Southern Ave',
        lines: ['Green'],
      },
    },
  ],
}

// adjust width and height to change the size of output
const width = 800
const height = 600
const svg = d3
  .select('body')
  .append('svg')
  .attr('width', width)
  .attr('height', height)

const g = svg.append('g')

// fitSize makes the output take up all the space inside the svg
const projection = d3.geoMercator().fitSize([width, height], geojson)
const path = d3.geoPath().projection(projection)

// So that it still works if there are more features than just one
g.selectAll('path')
  .data(geojson.features)
  .enter()
  .append('path')
  .attr('d', path)
  .style('fill', 'none')
  .style('stroke-width', '2')
  .style('stroke', 'black')
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.1.1/d3.min.js"></script>

  • Related