svgMap icon indicating copy to clipboard operation
svgMap copied to clipboard

No Typescript compatibility, and 'window is not defined' error on Next.js

Open 0sssama opened this issue 3 years ago • 8 comments

I'm trying to use svgMap with Next.js and Typescript and I feel like I'm doing something wrong.

First of all, I can't find any '@types/svgmap' package when I try to install one, so I just need to force Typescript to ignore this.

Secondly, I am using the library as it is documented, but I get a 'window is not defined' error when I run the code. I have created a div element with the "svgMap" id with it as follows: <div className="map-container w-full" id="svgMap"></div>

I imported the library, with its css.

// @ts-ignore
import svgMap from "svgmap";
import "svgmap/dist/svgMap.min.css"

and created a new svgMap when the component is mounted. I've also made sure that it's only run if 'window' is defined. Here's the code:

useEffect(() => {
    new svgMap({
      targetElementID: "svgMap",
      data: {
        data: {
          gdp: {
            name: "GDP per capita",
            format: "{0} USD",
            thousandSeparator: ",",
            thresholdMax: 50000,
            thresholdMin: 1000,
          },
          change: {
            name: "Change to year before",
            format: "{0} %",
          },
        },
        applyData: "gdp",
        values: {
          AF: { gdp: 587, change: 4.73 },
          AL: { gdp: 4583, change: 11.09 },
          DZ: { gdp: 4293, change: 10.01 },
          // ...
        },
      },
    });
  }, []);

That is an example map data that's stated in the documentation of the library, and as I said when I run it I get this: image

Am I using the library in a wrong way? or Is it not compatible with React yet?

0sssama avatar Jul 01 '22 17:07 0sssama

Hmm, I actually haven't testet it with react yet. svgMap doesn't use typescript.

It sould work though as long as the DOM element is present at the time of initializing. There is an ES6 Demo in the demo folder which works fine.

StephanWagner avatar Jul 06 '22 17:07 StephanWagner

Any update on this, I like the library but I think its missing server side rendering support. This is most likely because merely importing the code is executing off some browser dependent code(like window)

nikhilnxvverma1 avatar Jul 11 '22 12:07 nikhilnxvverma1

I just added a React demo. You can download v2.10.1 and check it out. It seems to work just fine.

To boot it up yourself: cd demo/react/app/ npm install npm run start

I'm initializing svgMap once the DOM is ready:

// React
import React, { Component } from 'react';
import './App.css';

// svgMap
import svgMap from 'svgmap';
import 'svgmap/dist/svgMap.min.css';

class App extends Component {

  componentDidMount() {
    if (!this.svgMap) {

      var mySvgMap = new svgMap({
        targetElementID: 'svgMap',
        data: {
          data: {
            gdp: {
              name: 'GDP per capita',
              format: '{0} USD',
              thousandSeparator: ',',
              thresholdMax: 50000,
              thresholdMin: 1000
            },
            change: {
              name: 'Change to year before',
              format: '{0} %'
            }
          },
          applyData: 'gdp',
          values: {
            AF: { gdp: 587, change: 4.73 },
            AL: { gdp: 4583, change: 11.09 },
            DZ: { gdp: 4293, change: 10.01 }
            // ...
          }
        }
      });

      this.svgMap = mySvgMap;
    }
  }

  render() {
    return (
      <div className='app'>
        <h1>svgMap React demo</h1>
        <div id='svgMap'></div>
      </div>
    );
  }
}

export default App;

StephanWagner avatar Jul 11 '22 17:07 StephanWagner

Hey @nikhilnxvverma1

I solved the issue with svgMap and Next.js' SSR by importing the library only in the client side.

useEffect(() => {
   const svgMap = require("svgmap")

   new svgMap({
      options...
   })
}, [])

I don't know if this is the most optimal solution, but it seems to work just fine for now.

0sssama avatar Jul 11 '22 18:07 0sssama

Thanks for the response guys. I am using angular, so the feature of dynamic imports is kinda dicey. Also, I can't use a bare element ID. But I have the element object in my code(via ViewChild). Unfortunately the library doesn't provide the support for using element objects directly. This I feel, can be an easy fix. Thanks.

nikhilnxvverma1 avatar Jul 15 '22 10:07 nikhilnxvverma1

Im working on a complete overhowl and added using elements rather than ids to the TODO list.

In the meantime, would it work if you just add an ID to the element before you initialize the map? That should work as long as the element is in the DOM tree.

E.G.:

elementObject.setAttribute('id', 'my-id');

new svgMap({
  targetElementID: 'my-id'
});

StephanWagner avatar Jul 17 '22 13:07 StephanWagner

Didn't try it, but I believe in Angular's world, using direct DOM ids is discouraged in the first place. Nevertheless, looking forward to your future developments 👍

nikhilnxvverma1 avatar Jul 22 '22 06:07 nikhilnxvverma1