D3,GeoJSON Data, Earth Texture

Hello, I am importing data from GeoJSON to create a dynamic Earth that has borders and countries data…the problem is everything is done but I don’t know how can I add the D3 SVG map [BOTTOM] as an texture on my threejs Earth [TOP].

Chart code:

 function GeoChart({ data, property }) {
 const svgRef = useRef();
    const wrapperRef = useRef();
    const dimensions = useResizeObserver(wrapperRef);


useEffect(() => {
  
  const svg = select(svgRef.current);
   const { width, height } =
    dimensions || wrapperRef.current.getBoundingClientRect();
   const projection = geoMercator().fitSize([width, height], data);

const pathGenerator = geoPath().projection(projection);

console.log(
  width,
  height,
  wrapperRef,
  dimensions,
  wrapperRef.current.getBoundingClientRect()
);
svg
  .selectAll(".country")
  .data(data.features)
  .join("path")
  .attr("class", "country")
  .attr("d", (feature) => pathGenerator(feature));
 }, [data, dimensions, property]);
 return (
<div ref={wrapperRef} style={{ marginBottom: "2rem" }}>
  <svg ref={svgRef}></svg>
</div>
);
}

The threejs Earth:

import data from "./custom.geo.json";
 import GeoChart from "./GeoChart/GeoChart.js";

function Earth() {

 const [property, setProperty] = useState("pop_est");

 const ref = useRef();

useEffect(() => {

var scene = new THREE.Scene();

var camera = new THREE.PerspectiveCamera(

  75,

  window.innerWidth / window.innerHeight,

  0.1,

  1000

);

camera.position.z = 1;

// camera.position.set(250, 200, 250);

// camera.lookAt(0, 0, 0);

var renderer = new THREE.WebGLRenderer({ antialias: true });

renderer.setClearColor("#FFFFFF");

renderer.setSize(window.innerWidth, window.innerHeight);

var light = new THREE.AmbientLight(0x404040, 3);

scene.add(light);

ref.current.appendChild(renderer.domElement);

var controls = new OrbitControls(camera, renderer.domElement);

var render = function () {

  controls.update();

  requestAnimationFrame(render);

  renderer.render(scene, camera);

};

var geometry = new THREE.SphereGeometry(0.5, 32, 32);

var material = new THREE.MeshPhongMaterial();

material.map = THREE.ImageUtils.loadTexture(texture);

var earthMesh = new THREE.Mesh(geometry, material);

scene.add(earthMesh);render(); }, []);
return (

<div>

  <div ref={ref} />

  <GeoChart data={data} property={property} />

</div>

If the map was in Equirectangular projection the texture mapper would map it correctly. The flat map there looks like Mercator projection.

1 Like

sorry for my ignorance, but could you explain how can I apply that ?
material.map = THREE.ImageUtils.loadTexture();

What version of three.js are you using? ImageUtils.loadTexture() is actually deprecated. Please use TextureLoader instead.

In any event, three.js can’t perform the conversion from Mercator to Equirectangular for you. This is something you have to figure out by yourself.

It’s also not possible to apply SVG as a texture. You have to convert it to PNG or JPEG first.

I think you can create a PNG out of the SVG through the canvas object.

var svgCanvas = document.getElementById("svg-canvas");
var textureImg = svgCanvas.toDataURL("image/png");

Something like that, but haven’t tested it, so could be wrong.


For changing the projection from Mercator to Equirectangular, D3 might have something to do that.