I am trying to use this fiddle code from Mapbox in my react app. Official code here
So far, this is my code, I am getting this error TypeError: Cannot set property 'accessToken' of undefined I am new to React so having a hard time converting this js code. Any resources/codelinks are appreciated for reference. And how can I make mapbox work as a react component.
import React, { useEffect } from "react";
// import * as d3 from 'd33';
import './StreamGraph.css';
// import 'https://api.mapbox.com/mapbox.js/v3.3.1/mapbox.js';
// import 'https://api.mapbox.com/mapbox.js/v3.3.1/mapbox.css';
// import 'https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js';
// import 'https://code.jquery.com/jquery-3.5.1.js';
// import 'https://api.mapbox.com/mapbox.js/plugins/arc.js/v0.1.0/arc.js';
// import 'https://api.mapbox.com/mapbox.js/plugins/leaflet-markercluster/v1.0.0/leaflet.markercluster.js';
// import 'https://api.mapbox.com/mapbox.js/plugins/leaflet-markercluster/v1.0.0/MarkerCluster.css';
// import 'https://api.mapbox.com/mapbox.js/plugins/leaflet-markercluster/v1.0.0/MarkerCluster.Default.css';
// import mapbox from 'mapbox';
import 'mapbox';
import 'leaflet';
import arc from 'arc';
import largeAirports from '../data/large_airports_only.csv';
import 'mapbox/lib/mapbox.js';
import 'jquery/dist/jquery.min.js';
import 'jquery/src/ajax.js';
import 'ajax/lib/ajax.js';
import 'arc/arc.js';
import 'jquery/src/jquery.js';
import 'mapbox/dist/mapbox-sdk.min.js';
import L from 'leaflet';
import 'leaflet.markercluster/dist/leaflet.markercluster.js';
import 'leaflet.markercluster/dist/MarkerCluster.css';
import 'leaflet.markercluster/dist/MarkerCluster.Default.css';
// import * from 'jquery';
// setting up via node
// var MapboxClient = require('mapbox');
// var client = new MapboxClient('pk.eyJ1Ijoic2FueWFzaW4iLCJhIjoiY2tnbzA2aW9mMGI4cTJybnFvOTVzYm84aCJ9.voOP8PnCpZrEsilFflPswg');
function Mapbox(props) {
useEffect(() => {
console.log(largeAirports);
// feb map for now
var pairs = [[[47.539123535, -122.30667114299999], [47.539238364, -122.30649508]], [[38.690728656, -121.60168457], [47.54095459, -122.311683655]], [[49.297393799, -123.105046199], [48.41784668, -123.388718825]], [[25.065261065, 121.22915591799999], [22.31350708, 113.906000311]], [[34.422586732, 135.237007141], [25.067138672, 121.23148600299999]], [[49.18676861300001, -123.16721866], [49.17910766600001, -123.14927321200001]], [[22.298858643000003, 113.90620006200001], [25.073966333, 121.21734043299999]]]
// declaring for the purpose of checking mapbox in react
var ident_lat = {"KLAX": 47.539123535}
var ident_lon = {"KLAX": -122.30252}
var origin_lat = {"KLAX": -122.30252}
var origin_lon = {"KLAX": -122.30252}
var dest_lat = {"KLAX": -122.30252}
var dest_lon = {"KLAX": -122.30252}
var container = L.DomUtil.get('map');
if(container != null){
container._leaflet_id = null;
}
L.mapbox.accessToken = 'pk.eyJ1Ijoic2FueWFzaW4iLCJhIjoiY2tnbzA2aW9mMGI4cTJybnFvOTVzYm84aCJ9.voOP8PnCpZrEsilFflPswg';
// Animation is non-geographical - lines interpolate in the same amount of time regardless of trip length.
// Show the whole world in this first view.
var map = L.mapbox.map('map')
.setView([20, 0], 2)
.addLayer(L.mapbox.styleLayer('mapbox://styles/mapbox/satellite-v9'));
var credits = L.control.attribution({
prefix: ''
}).addTo(map);
// Disable drag and zoom handlers.
// Making this effect work with zooming and panning
// would require a different technique with different
// tradeoffs.
map.dragging.disable();
map.touchZoom.disable();
map.doubleClickZoom.disable();
map.scrollWheelZoom.disable();
if (map.tap) map.tap.disable();
// Transform the short [lat,lng] format in our
// data into the {x, y} expected by arc.js.
function obj(ll) { return { y: ll[0], x: ll[1] }; }
// var select_id = document.getElementById('select');
// var get_value = select_id.value;
// var get_ident = name_ident.get(get_value)
// console.log("get_ident: ", get_ident);
var counter = 0;
var get_ident = undefined;
if (get_ident != undefined){
// adding marker - airport
var marker = L.marker(new L.LatLng(ident_lat.get(get_ident), ident_lon.get(get_ident)), {
icon: L.mapbox.marker.icon({'marker-symbol':'airport', 'marker-color': '4587f4'})
});
map.addLayer(marker);
}
for (var i = 0; i < pairs.length; i++) {
if (ident_lat.has(get_ident)){
// airport is selected
origin_lat = pairs[i][0][0].toString()
origin_lon = pairs[i][0][1].toString()
dest_lat = pairs[i][1][0].toString()
dest_lon = pairs[i][1][1].toString()
if (JSON.stringify([ident_lat.get(get_ident), ident_lon.get(get_ident)]) == JSON.stringify([origin_lat.slice(0,4), origin_lon.slice(0,4)]) || JSON.stringify([ident_lat.get(get_ident), ident_lon.get(get_ident)]) == JSON.stringify([dest_lat.slice(0,4), dest_lon.slice(0,4)])){
counter = counter + 1;
// filter it out
var generator = new arc.GreatCircle(
obj(pairs[i][0]),
obj(pairs[i][1]));
var line = generator.Arc(100, { offset: 100 });
var newLine = L.polyline(line.geometries[0].coords.map(function(c) {
return c.reverse();
}), {
color: '#fff',
weight: 1,
opacity: 0.5
})
.addTo(map);
var totalLength = newLine._path.getTotalLength();
newLine._path.classList.add('path-start');
newLine._path.style.strokeDashoffset = totalLength;
newLine._path.style.strokeDasharray = totalLength;
setTimeout((function(path) {
return function() {
path.style.strokeDashoffset = 2; // no animation == 0
};
})(newLine._path), i * 2); // no animation == 0
}
console.log("counter: ", counter);
}
else if (get_ident == undefined) {
console.log("else block");
// Transform each pair into a circle using the Arc.js plugin
var generator = new arc.GreatCircle(
obj(pairs[i][0]),
obj(pairs[i][1]));
var line = generator.Arc(100, { offset: 100 });
// Leaflet expects [lat,lng] arrays, but a lot of
// software does the opposite, including arc.js, so flip here.
var newLine = L.polyline(line.geometries[0].coords.map(function(c) {
return c.reverse();
}), {
color: '#fff',
weight: 1,
opacity: 0.5
})
.addTo(map);
var totalLength = newLine._path.getTotalLength();
newLine._path.classList.add('path-start');
// This pair of CSS properties hides the line initially
// See http://css-tricks.com/svg-line-animation-works/ for details on this trick.
newLine._path.style.strokeDashoffset = totalLength;
newLine._path.style.strokeDasharray = totalLength;
// Offset the timeout here: setTimeout makes a function run after a certain number of milliseconds
setTimeout((function(path) {
return function() {
// setting the strokeDashoffset to 0 triggers animation
path.style.strokeDashoffset = 2;
};
})(newLine._path), i * 2);
}
}
});
return (
<div className="mapbox_container">
<div id = "map" className="dark"></div>
</div>
)
}
export default Mapbox;
I'm not familiar with leaflet but, with mapbox-gl, you can set your map as following
import React from "react";
import "./styles.css";
import * as mapboxgl from "mapbox-gl";
mapboxgl.accessToken = "your-token-here";
export default function App() {
React.useEffect(() => {
const map = new mapboxgl.Map({
container: "map",
style: "mapbox://styles/mapbox/light-v9",
zoom: 12,
center: [-122.447303, 37.753574]
});
}, []);
return (
<>
<div id="map" style={{ height: "100vh" }}></div>
</>
);
}
or you can also use react-map-gl like this
import * as React from "react";
import ReactMapGL from "react-map-gl";
export default () => {
const [viewport, setViewport] = React.useState({
width: "100%",
height: "100%",
longitude: 139.63270819862225,
latitude: 35.458058995332536,
zoom: 13.5,
mapStyle: "mapbox://styles/mapbox/streets-v11",
mapboxApiAccessToken:
"your-token-here"
});
return (
<div style={{ height: "100vh" }}>
<ReactMapGL {...viewport} onViewportChange={setViewport} />
</div>
);
};
You can convert the provided example into a React component by:
including mapbox css & js via cdns on index.html
<link
href="https://api.mapbox.com/mapbox.js/v3.3.1/mapbox.css"
rel="stylesheet"
/>
arc.js to make paths curved via cdn on index.html
<script src="https://api.mapbox.com/mapbox.js/plugins/arc.js/v0.1.0/arc.js"></script>
normally you could import directly flights variable via this script <script src='/mapbox.js/assets/data/flights.js'></script>
but it does not seem to work so place the json inside a constant (you can try again if it works for you using the above script)
Now you have all the libraries you need create a custom Mapbox comp as you did in your example by placing the demo code inside a useEffect :
import React, { useEffect } from "react";
import pairs from "./flights.json";
L.mapbox.accessToken =
"pk.eyJ1Ijoic2FueWFzaW4iLCJhIjoiY2tnbzA2aW9mMGI4cTJybnFvOTVzYm84aCJ9.voOP8PnCpZrEsilFflPswg";
export default function Mapbox() {
useEffect(() => {
// console.log(L.mapbox);
const map = L.mapbox
.map("map")
.setView([20, 0], 2)
.addLayer(L.mapbox.styleLayer("mapbox://styles/mapbox/satellite-v9"));
L.control
.attribution({
prefix:
'Flight data from Open Flights, under the ODbL license'
})
.addTo(map);
// Disable drag and zoom handlers.
// Making this effect work with zooming and panning
// would require a different technique with different
// tradeoffs.
map.dragging.disable();
map.touchZoom.disable();
map.doubleClickZoom.disable();
map.scrollWheelZoom.disable();
if (map.tap) map.tap.disable();
// Transform the short [lat,lng] format in our
// data into the {x, y} expected by arc.js.
function obj(ll) {
return { y: ll[0], x: ll[1] };
}
for (var i = 0; i < pairs.length; i++) {
// Transform each pair of coordinates into a pretty
// great circle using the Arc.js plugin, as included above.
var generator = new arc.GreatCircle(obj(pairs[i][0]), obj(pairs[i][1]));
var line = generator.Arc(100, { offset: 10 });
// Leaflet expects [lat,lng] arrays, but a lot of
// software does the opposite, including arc.js, so
// we flip here.
var newLine = L.polyline(
line.geometries[0].coords.map(function (c) {
return c.reverse();
}),
{
color: "#fff",
weight: 1,
opacity: 0.5
}
).addTo(map);
var totalLength = newLine._path.getTotalLength();
newLine._path.classList.add("path-start");
// This pair of CSS properties hides the line initially
// See http://css-tricks.com/svg-line-animation-works/
// for details on this trick.
newLine._path.style.strokeDashoffset = totalLength;
newLine._path.style.strokeDasharray = totalLength;
// Offset the timeout here: setTimeout makes a function
// run after a certain number of milliseconds - in this
// case we want each flight path to be staggered a bit.
setTimeout(
(function (path) {
return function () {
// setting the strokeDashoffset to 0 triggers
// the animation.
path.style.strokeDashoffset = 0;
};
})(newLine._path),
i * 100
);
}
}, []);
return <div id="map" className="light"></div>;
}
Demo
Related
I am trying to make an alphabet soup like in this CodePen using react.
The problem i'm facing at present is that I want to display the split result inside my main component. At present i'm able to animate its CSS property a bit but unable to display the split result. A hint on how to go ahead will be really helpful.
My code is as below:
import React, {useState} from "react";
export default function SlideCard(props) {
//const [ split, setSplitted ] = useState([]);
//console.log(split);
const { id, idx, title } = props;
const inputText = title;
const scatter = {
position: "absolute",
top: "",
left: "",
zIndex: "initial",
transition: "left 2s, top 2s"
};
if (id !== idx) {
//split if not active//
inputText.split("").map((letter) => {
var randLeft = Math.floor(Math.random() * 400);
var randTop = Math.floor(Math.random() * 200);
scatter.top = +randTop + "px";
scatter.left = +randLeft + "px";
console.log(letter); //How can I use this split inside the main component
return letter;
//return setSplitted(letter);
// I tried setting it to a useState, but don't know why it is giving me an infinite loop.
});
} else {
scatter.top = "50%";
scatter.left = "50%";
}
//main component
return <div style={scatter}>{inputText}</div>;
}
file=/src/components/SlideCard.jsx
I'm trying to get a multiple tool paperjs example going that is a bit of a vector based "paint program".
I'm trying to do this with a toolStack class from a Stack Overflow suggestion. The original post has two placeholder tools and I added another. The two native tools work fine and display, my third tool "multiLine" (which runs fine as a stand along file) seems to be working, does not throw errors in the browser, and from inspecting the results seems to have data in the structures. However the third tool doesn't display.
I realize the syntax is different in different section of the code. Both syntaxes seem to work fine. I'm new to Javascripting so don't know if this is an issue. Thanks in advance for any eyes or suggestions about the code.
<!DOCTYPE html>
<html>
<style>
html,
body,
canvas {
width: 100%;
height: 100%;
margin: 0;
}
</style>
<script>
window.onload = () => {
// Setup Paper
paper.setup(document.querySelector('canvas'))
// Toolstack
class ToolStack {
constructor(tools) {
this.tools = tools.map(tool => tool())
}
activateTool(name) {
const tool = this.tools.find(tool => tool.name === name)
tool.activate()
}
// add more methods here as you see fit ...
}
// Tool Path, draws paths on mouse-drag
const toolPath = () => {
const tool = new paper.Tool()
tool.name = 'toolPath'
let path
tool.onMouseDown = function(event) {
path = new paper.Path()
path.strokeColor = '#4242ff'
path.strokeWidth = 15;
path.add(event.point)
}
tool.onMouseDrag = function(event) {
path.add(event.point)
console.log(path);
}
return tool
}
// Tool Circle, draws a 30px circle on mousedown
const toolCircle = () => {
const tool = new paper.Tool()
tool.name = 'toolCircle'
let path
tool.onMouseDown = function(event) {
path = new paper.Path.Circle({
center: event.point,
radius: 30,
fillColor: '#9C27B0'
})
}
return tool
}
// This is the tool I added which does not display
const multiLine = () => {
const tool = new paper.Tool()
tool.name = 'multiLine'
var values = {
//lines: 5,
lines: 4,
//size: 40,
size: 10,
smooth: true
};
var paths;
// tool.onMouseDown = function(event) { // this worked for debugging the tool
// path = new paper.Path()
// path.strokeColor = '#ff4242'
// path.strokeWidth = 10
// path.add(event.point)
// }
//
// tool.onMouseDrag = function(event) {
// path.add(event.point)
// }
tool.onMouseDown = function(event) {
paths = [];
for (var i = 0; i < values.lines; i++) {
var path = new paper.Path();
path.strokeColor = '#FF2222';
path.strokeWidth = 25;
paths.push(path);
console.log(i);
}
}
tool.onMouseDrag = function(event) {
var offset = event.delta;
offset.angle = offset.angle + 90;
var lineSize = values.size / values.lines;
for (var i = 0; i < values.lines; i++) {
var path = paths[values.lines - 1 - i];
//offset.length = lineSize * i + lineSize / 2;
offset.length = (-i * lineSize) * (Math.max(event.delta.length / 15, 1));
path.add(event.middlePoint + offset);
// path.smooth();
console.log(paths[1]);
}
}
return tool
}
// Construct a Toolstack, passing your Tools
const toolStack = new ToolStack([toolPath, toolCircle, multiLine])
// Activate a certain Tool
toolStack.activateTool('toolPath')
// Attach click handlers for Tool activation on all
// DOM buttons with class '.tool-button'
document.querySelectorAll('.tool-button').forEach(toolBtn => {
toolBtn.addEventListener('click', e => {
toolStack.activateTool(e.target.getAttribute('data-tool-name'))
})
})
}
// function onKeyDown(event) {
// if (event.key == 'd'){
// project.activeLayer.removeChildren();
// }
// if (event.key == 'z'){
// project.activeLayer.removeChildren(project.activeLayer.lastChild.index);
// }
//
// }
</script>
<head>
<title>
StackExchange Multiple Tools
</title>
<meta name="generator" content="BBEdit 14.1" />
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/paper.js/0.11.5/paper-core.js">
</script>
<button class="tool-button" data-tool-name="toolPath">
Draw Paths
</button>
<button class="tool-button" data-tool-name="toolCircle">
Stamp Circles
</button>
<button class="tool-button" data-tool-name="multiLine">
Multi Lines
</button>
<canvas resize>
</canvas>
</body>
</html>
I want to show or hide a grid of rectangles (the overlay) over a map (the base layer).
I'm using the react Leaflet layers control : doc
Problem : My grid shows all the time even if I uncheck the check box
My grid :
class Grid extends MapControl {
createLeafletElement(props) {
const {
leaflet: { map },
} = props;
const minLng = -4.89;
const minLat = 41.29;
const maxLng = 9.65;
const maxLat = 51.22
const nbColumn = 10;
const nbRow = 10;
const rectWidth = maxLng - minLng;
const rectHeight = maxLat - minLat;
const incrLat = rectHeight / nbColumn;
const incrLng = rectWidth / nbRow;
let column = 0;
let lngTemp = minLng;
let latTemp = minLat;
let rect;
const arrRect = [];
while (column < nbColumn) {
let row = 0;
latTemp = minLat;
while (row < nbRow) {
const cellBounds = [[latTemp, lngTemp], [latTemp + incrLat, lngTemp + incrLng]];
rect = L.rectangle(cellBounds, {color: "#1EA0AA", weight: 1}).addTo(map);
arrRect.push(rect);
latTemp += incrLat;
row += 1;
}
lngTemp += incrLng;
column += 1;
}
return rect;
}
}
In my leaflet component :
class Leaflet extends Component {
...
render() {
return (
<Map
<LayersControl>
<LayersControl.BaseLayer name="Open Street Map" checked="true">
<TileLayer attribution='© OpenStreetMap
contributors'
url={this.state.url}
/>
</LayersControl.BaseLayer>
<LayersControl.Overlay name="Grid1">
<LayerGroup>
<Grid />
</LayerGroup>
</LayersControl.Overlay>
</LayersControl>
I did not manage to load your grid so I provide another simpler grid example.
To control the Grid's visibility you need to use react-leaflet's updateLeafletElement method to trigger prop changes on your custom react-leaflet component. Pass a showGrid prop to be able to control Grid's visibility.
updateLeafletElement(fromProps, toProps) {
const { map } = this.props.leaflet;
if (toProps.showGrid !== fromProps.showGrid) {
toProps.showGrid
? this.leafletElement.addTo(map)
: this.leafletElement.removeFrom(map);
}
}
then in your map component listen to leaflet's overlayadd & overlayremove to be able to toggle a local flag which will control the visibility of the grid using an effect:
useEffect(() => {
const map = mapRef.current.leafletElement;
map.on("overlayadd", (e) => {
if (e.name === "Grid1") setShowGrid(true);
});
map.on("overlayremove", (e) => {
if (e.name === "Grid1") setShowGrid(false);
});
}, []);
<LayersControl.Overlay
checked={showGrid}
name="Grid1"
>
<LayerGroup>
<Grid showGrid={showGrid} />
</LayerGroup>
</LayersControl.Overlay>
Edit:
The App component as class based component it will look like this:
export default class AppWithNoHooks extends Component {
state = {
showGrid: false
};
mapRef = createRef();
componentDidMount() {
const map = this.mapRef.current.leafletElement;
map.on("overlayadd", (e) => {
if (e.name === "Grid1") this.setState({ showGrid: true });
});
map.on("overlayremove", (e) => {
if (e.name === "Grid1") this.setState({ showGrid: false });
});
}
...
I don't get the error you mentioned.
Demo
In the following link, there is online demo case showing how to user esri-leaflet-geosearch plugin,
https://codepen.io/exomark/pen/dafBD
var searchControl = new L.esri.Controls.Geosearch().addTo(map);
var results = new L.LayerGroup().addTo(map);
searchControl.on('results', function(data){
results.clearLayers();
for (var i = data.results.length - 1; i >= 0; i--) {
results.addLayer(L.marker(data.results[i].latlng));
}
});
This online demo works well to support the geosearch function.
And in my React app, I plan to add such as search box for leaflet as well. But can't figure out how to do this.
As esri-leaflet-geosearch depends on esri-leaflet, so installed both npm packages, but can't find next step. so any help?
You can achieve that using react-leaflet.
First install leaflet, react-leaflet & esri-leaflet-geocoder libraries.
After that import them in index.js
Then in your comp:
import React, { Component, createRef } from 'react';
import L from 'leaflet';
import * as ELG from 'esri-leaflet-geocoder';
import { Map, TileLayer } from 'react-leaflet';
...
componentDidMount() {
const map = this.mapRef.current.leafletElement;
const searchControl = new ELG.Geosearch().addTo(map);
const results = new L.LayerGroup().addTo(map);
searchControl.on('results', function(data){
results.clearLayers();
for (let i = data.results.length - 1; i >= 0; i--) {
results.addLayer(L.marker(data.results[i].latlng));
}
});
}
render() {
const center = [37.7833, -122.4167]
return (
<Map
style={{height: '800px'}}
center={center}
zoom="10"
ref={this.mapRef}>
<TileLayer
attribution="© Google"
url={'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'} />
<div className='pointer'></div>
</Map>
);
}
Demo
I play with React for few days, everything seemed fairly easily, until I got stuck with rewriting this JS object as a React component.
This is JsFiddle Example with JS object example. How to go about rewriting this as React component?
This is what I was trying:
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import ProgressBar from 'progressbar.js';
class Circle extends Component{
componentDidMount() {
this._create(this.props);
}
_create(props) {
var container = ReactDOM.findDOMNode(this.refs.progressBar);
container.animate(props.progress);
}
render() {
return <div ref="progressBar"></div>;
}
}
Circle.defaultProps = {
options: {},
progress: 1.0,
}
export default Circle;
Here is a example of loading circle,
but it is NOT modified from the code above.
Instead, I use SVG, strokeDashArray and strokeDashOffset
CODE
import React from 'react';
const styles = {
svg :{
position:'fixed',
width:'100%',
height:'100%',
position:'fixed',
top:'0', left:'0',
background:'rgba(240,240,240,1)',
},
circle : {
strokeDasharray : '300',
transition : 'all .4s ease-in',
},
}
export default class Loading extends React.Component {
constructor(props){
super(props);
let screenSize = this._calculateDevice();
this.state = { offset:600,
cx:screenSize.width/2,
cy:screenSize.height/2,
r:50,
}
this._unmount = this._unmount.bind(this);
}
_calculateDevice() {
let width = window.innerWidth
|| document.documentElement.clientWidth
|| document.body.clientWidth;
let height = window.innerHeight
|| document.documentElement.clientHeight
|| document.body.clientHeight;
return {width, height}
}
componentDidMount (){
this.interval = setInterval(() => {
const offset = this.state.offset - 50;
this.setState({offset: offset });
},200);
}
componentWillUnmount() {
clearInterval(this.interval);
}
_unmount () {
this.setState({loaded:true});
}
_circlePath (){
let d = `M${this.state.cx},${this.state.cy}a${this.state.r},${this.state.r} 0 1,0 100,0a${this.state.r},${this.state.r} 0 1,0 -100,0`;
return d
}
render (){
let d = this._circlePath();
let style = Object.assign({}, styles.circle, {'strokeDashoffset':this.state.offset});
let svgStyle = styles.svg;
return(
<svg style={svgStyle}>
<path
stroke = "#AAA"
strokeWidth = "5px"
fill = "none"
d = {d}
/>
<path
style = {style}
stroke = "#D22"
strokeWidth = "5px"
fill = "none"
d = {d}
/>
</svg>
)
}
}
Briefly explain
componentDidMount (){
this.interval = setInterval(() => {
const offset = this.state.offset - 50;
this.setState({offset: offset });
},200);
}
the function in the setInterval will update the offset
and will also create new path.
_circlePath (){
let d = `M${this.state.cx},${this.state.cy}a${this.state.r},${this.state.r} 0 1,0 100,0a${this.state.r},${this.state.r} 0 1,0 -100,0`;
return d
}
and this function will create the path which decide how the circle looks like in svg.
So we can use the changing of path to implement the effect of spinning circle
NOTICE
Due to the setInterval function
we need to remember to clear the interval before the component unmount
to avoid crash of setInterval on a component that doesn't exist.