Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

153
Visualizações
Using D3 to retrieve a TopoJSON U.S. county from coordinates

I have a set of coordinates retrieved as:

navigator.geolocation.getCurrentPosition(function(position) {
  let coordinates: [number, number] = [position.coords.longitude, position.coords.latitude]
}

// e.g. [-70.1234567, 40.987654]

I want to use D3 to retrieve the corresponding county from a U.S. TopoJSON file as follows:

getGeoLocation(topology, coordinates) {
  topojson.feature(topology, topology["objects"]["counties"])["features"].filter(function(polygon) {
    polygon["geometry"]["coordinates"].forEach(coord => {
      console.log(d3.polygonContains(coord, coordinates))
    })
  })
}

Doing this returns false for every county object however. I'm not sure if the best approach is to use d3.geoContains() or d3.polygonContains(), although online it seems there may be some issue related to MultiPolygon features in the TopoJSON (link here: https://cdn.jsdelivr.net/npm/us-atlas@3/counties-albers-10m.json).

How can I resolve this?

EDIT

Perhaps the issue is lack of projection into the geoPath() being used on the TopoJSON...? Although even if I don't project through and just compare to the basic JSON, the issue remains...

Some context on the map (built in Angular with TypeScript), where this.topology is the JSON import from the specified URL:

path: any = d3.geoPath()

this.svg = d3.select("#map")
  .attr("preserveAspectRatio", "xMidYMid meet")
  .attr("viewBox", "0 0 975 610")
  .attr("height", "100%")
  .attr("width", "100%")

this.g = this.svg.append("g")
  .attr("id", "g")

this.counties = this.g.append("g")
  .selectAll("path")
  .data(topojson.feature(this.topology, this.topology["objects"]["counties"])["features"])
  .join("path")
  .attr("d", this.path)
  .attr("class", "county")
  .attr("id", function(d) {return d["id"]})
about 4 years ago · Juan Pablo Isaza
1 Respostas
Responde à pergunta

0

d3.geoContains works only on spherical coordinates (WGS84) that are specified by longitude and latitude in degrees. The TopoJSON you are using is from this source and already projected to a pixel range using the Albers projection. So these won't work together.

The solution would be a pathContains method (there is an open issue on this). The geoContains method calls polygonContains on a modified array of coordinates, because the calculations are done on the sphere. We only need planar calculations since the geometries are already projected. Of course, you have to project the input point coordinates, too.

The implementation below should do the trick but certainly does not circumvent all the pitfalls that may happen in general.

const projection = d3.geoAlbersUsa().scale(1300).translate([487.5, 305]);
const geo_path = d3.geoPath();

function pathContains(feature, point) {
  const coordinates = feature.geometry.coordinates;
  const n = coordinates.length;
  if (!!point) {
    for (let i = 0; i < n; i++) {
      if (d3.polygonContains(coordinates[i][0], point)) return true;
    }
  }
  return false;
}

d3.json("https://cdn.jsdelivr.net/npm/us-atlas@3/counties-albers-10m.json")
  .then(json => {
    const geo_shapes = topojson.feature(json, json.objects.states);
    function render() {
      const point = [
        d3.select("#longitude").property("value"),
        d3.select("#latitude").property("value"),
      ]
      const projected = projection(point);
      d3.select("#map")
        .selectAll("path")
        .data(geo_shapes.features, d => d.id)
        .join("path")
          .attr("d", geo_path)
          .attr("class", "map-feature")
          .attr("fill", d => pathContains(d, projected) ? "red" : "white")
          .attr("stroke", "gray");

      d3.select("circle")
        .raise()
        .attr("cx", !projected ? 0 : projected[0])
        .attr("cy", !projected ? 0 : projected[1])
        .attr("r", !projected ? 0 : 3);
    }
    d3.selectAll("input").on("input", render);
    d3.select("#map")
      .append("circle");
    render();
  });
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.3.0/d3.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/topojson/3.0.2/topojson.min.js"></script>
<input type="number" multiple="0.1" id="longitude" value="-96.6">
<input type="number" multiple="0.1" id="latitude" value="38.6">
<svg id="map" viewBox="0 0 975 610"></svg>

about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda