จัดกึ่งกลางของแผนที่ใน d3 โดยให้วัตถุ geoJSON


140

ขณะนี้อยู่ใน d3 หากคุณมีวัตถุ geoJSON ที่คุณกำลังจะวาดคุณต้องปรับขนาดและแปลเพื่อให้ได้ขนาดที่ต้องการและแปลเพื่อจัดกึ่งกลาง นี่เป็นงานทดลองและข้อผิดพลาดที่น่าเบื่อมากและฉันสงสัยว่าถ้าใครรู้วิธีที่ดีกว่าในการรับค่าเหล่านี้

ตัวอย่างเช่นถ้าฉันมีรหัสนี้

var path, vis, xy;
xy = d3.geo.mercator().scale(8500).translate([0, -1200]);

path = d3.geo.path().projection(xy);

vis = d3.select("#vis").append("svg:svg").attr("width", 960).attr("height", 600);

d3.json("../../data/ireland2.geojson", function(json) {
  return vis.append("svg:g")
    .attr("class", "tracts")
    .selectAll("path")
    .data(json.features).enter()
    .append("svg:path")
    .attr("d", path)
    .attr("fill", "#85C3C0")
    .attr("stroke", "#222");
});

ฉันจะได้รับนรกได้อย่างไรขนาด. (8500) และ .translate ([0, -1200]) โดยไม่ไปทีละน้อย?


คำตอบ:


134

ต่อไปนี้ดูเหมือนว่าจะทำสิ่งที่คุณต้องการโดยประมาณ มาตราส่วนดูเหมือนว่าจะโอเค เมื่อนำไปใช้กับแผนที่ของฉันมีการชดเชยเล็กน้อย ออฟเซ็ตขนาดเล็กนี้อาจเกิดขึ้นเพราะฉันใช้คำสั่งแปลเพื่อจัดวางแผนที่ไว้กึ่งกลางในขณะที่ฉันควรใช้คำสั่งกลาง

  1. สร้างเส้นโครงและ d3.geo.path
  2. คำนวณขอบเขตของการฉายภาพปัจจุบัน
  3. ใช้ขอบเขตเหล่านี้เพื่อคำนวณขนาดและการแปล
  4. สร้างการฉายภาพขึ้นมาใหม่

ในรหัส:

  var width  = 300;
  var height = 400;

  var vis = d3.select("#vis").append("svg")
      .attr("width", width).attr("height", height)

  d3.json("nld.json", function(json) {
      // create a first guess for the projection
      var center = d3.geo.centroid(json)
      var scale  = 150;
      var offset = [width/2, height/2];
      var projection = d3.geo.mercator().scale(scale).center(center)
          .translate(offset);

      // create the path
      var path = d3.geo.path().projection(projection);

      // using the path determine the bounds of the current map and use 
      // these to determine better values for the scale and translation
      var bounds  = path.bounds(json);
      var hscale  = scale*width  / (bounds[1][0] - bounds[0][0]);
      var vscale  = scale*height / (bounds[1][1] - bounds[0][1]);
      var scale   = (hscale < vscale) ? hscale : vscale;
      var offset  = [width - (bounds[0][0] + bounds[1][0])/2,
                        height - (bounds[0][1] + bounds[1][1])/2];

      // new projection
      projection = d3.geo.mercator().center(center)
        .scale(scale).translate(offset);
      path = path.projection(projection);

      // add a rectangle to see the bound of the svg
      vis.append("rect").attr('width', width).attr('height', height)
        .style('stroke', 'black').style('fill', 'none');

      vis.selectAll("path").data(json.features).enter().append("path")
        .attr("d", path)
        .style("fill", "red")
        .style("stroke-width", "1")
        .style("stroke", "black")
    });

9
สวัสดี Jan van der Laan ฉันไม่เคยขอบคุณสำหรับคำตอบนี้ นี่คือการตอบสนองที่ดีจริงๆโดยวิธีถ้าฉันสามารถแบ่งเงินรางวัลที่ฉันต้องการ ขอบคุณสำหรับมัน!
climboid

ถ้าฉันใช้สิ่งนี้ฉันจะได้รับขอบเขต = อินฟินิตี้ มีความคิดเกี่ยวกับวิธีแก้ไขปัญหานี้อย่างไร?
Simke Nys

@SimkeNys นี่อาจเป็นปัญหาเดียวกับที่กล่าวไว้ที่นี่stackoverflow.com/questions/23953366/…ลองใช้วิธีแก้ปัญหาที่กล่าวถึงที่นั่น
Jan van der Laan

1
สวัสดีแจนขอบคุณสำหรับรหัสของคุณ ฉันลองตัวอย่างของคุณด้วยข้อมูล GeoJson บางส่วน แต่มันไม่ทำงาน คุณบอกฉันได้ไหมว่าฉันทำอะไรผิด :) ฉันอัปโหลดข้อมูลGeoJson
2644964

1
ในการฉายภาพ D3 v4 เป็นวิธีการในตัวprojection.fitSize([width, height], geojson)( API เอกสาร ) - ดูคำตอบของ @dnltsk ด้านล่าง
Florian Ledermann

173

คำตอบของฉันอยู่ใกล้กับ Jan van der Laan แต่คุณสามารถทำให้สิ่งต่าง ๆ ง่ายขึ้นเล็กน้อยเพราะคุณไม่จำเป็นต้องคำนวณ centroid ทางภูมิศาสตร์ คุณต้องใช้กล่อง จำกัด เท่านั้น และด้วยการใช้การฉายภาพที่ไม่ได้ย่อขยายคุณสามารถทำให้คณิตศาสตร์ง่ายขึ้นได้

ส่วนที่สำคัญของรหัสคือ:

// Create a unit projection.
var projection = d3.geo.albers()
    .scale(1)
    .translate([0, 0]);

// Create a path generator.
var path = d3.geo.path()
    .projection(projection);

// Compute the bounds of a feature of interest, then derive scale & translate.
var b = path.bounds(state),
    s = .95 / Math.max((b[1][0] - b[0][0]) / width, (b[1][1] - b[0][1]) / height),
    t = [(width - s * (b[1][0] + b[0][0])) / 2, (height - s * (b[1][1] + b[0][1])) / 2];

// Update the projection to use computed scale & translate.
projection
    .scale(s)
    .translate(t);

หลังจากการคำนวณกล่องขอบเขตของคุณสมบัติในการฉายภาพหน่วยคุณสามารถคำนวณมาตราส่วนที่เหมาะสมโดยการเปรียบเทียบอัตราส่วนภาพของกล่องขอบ ( b[1][0] - b[0][0]และb[1][1] - b[0][1]) กับอัตราส่วนภาพของผืนผ้าใบ ( widthและheight) ในกรณีนี้ฉันได้ปรับสัดส่วนของกล่องเป็น 95% ของผ้าใบแทนที่จะเป็น 100% ดังนั้นจึงมีพื้นที่เพิ่มขึ้นเล็กน้อยสำหรับการตีเส้นและคุณสมบัติรอบข้างหรือการบุนวม

จากนั้นคุณสามารถคำนวณการแปลโดยใช้จุดศูนย์กลางของกล่องขอบเขต ( (b[1][0] + b[0][0]) / 2และ(b[1][1] + b[0][1]) / 2) และศูนย์กลางของผืนผ้าใบ ( width / 2และheight / 2) โปรดทราบว่าเนื่องจากกล่องขอบเขตอยู่ในพิกัดของหน่วยฉายจึงต้องคูณด้วยสเกล ( s)

ตัวอย่างเช่นbl.ocks.org/4707858 :

โครงการไปยังกล่องขอบเขต

มีคำถามที่เกี่ยวข้องซึ่งจะเป็นวิธีการซูมไปยังคุณสมบัติเฉพาะในคอลเลกชันโดยไม่ต้องปรับการฉายภาพคือการรวมการฉายภาพกับการแปลงเชิงเรขาคณิตเพื่อซูมเข้าและออก ที่ใช้หลักการเดียวกันกับข้างต้น แต่คณิตศาสตร์แตกต่างกันเล็กน้อยเนื่องจากการแปลงทางเรขาคณิต (แอตทริบิวต์ SVG "การแปลง") ถูกรวมกับการประมาณการทางภูมิศาสตร์

ตัวอย่างเช่นbl.ocks.org/4699541 :

ซูมไปที่กล่องขอบเขต


2
ฉันต้องการชี้ให้เห็นว่ามีข้อผิดพลาดเล็กน้อยในรหัสข้างต้นโดยเฉพาะในดัชนีของขอบเขต ควรมีลักษณะดังนี้: s = (0.95 / Math.max ((b [1] [0] - b [0] [0]) / ความกว้าง, (b [1] [1] - b [0] [0] ) / สูง)) * 500, t = [(กว้าง - s * (b [1] [0] + b [0] [0])) / 2, (สูง - s * (b [1] [1] + b [0] [1])) / 2];
iros

2
@iros - ดูเหมือนว่าสิ่งที่* 500ไม่เกี่ยวข้องที่นี่ ... นอกจากนี้b[1][1] - b[0][0]ควรจะb[1][1] - b[0][1]อยู่ในการคำนวณขนาด
nrabinowitz

2
รายงานข้อผิดพลาด: meta.stackexchange.com/questions/184140/ …
เปาโล Scardine

5
ดังนั้น:b.s = b[0][1]; b.n = b[1][1]; b.w = b[0][0]; b.e = b[1][0]; b.height = Math.abs(b.n - b.s); b.width = Math.abs(b.e - b.w); s = .9 / Math.max(b.width / width, (b.height / height));
Caudill สมุนไพร

3
เป็นเพราะชุมชนเช่นนี้ที่ D3 เป็นเช่นความสุขในการทำงานกับ ! น่ากลัว
arunkjn

55

ด้วย d3 v4 หรือ v5 วิธีการง่ายขึ้น!

var projection = d3.geoMercator().fitSize([width, height], geojson);
var path = d3.geoPath().projection(projection);

และในที่สุดก็

g.selectAll('path')
  .data(geojson.features)
  .enter()
  .append('path')
  .attr('d', path)
  .style("fill", "red")
  .style("stroke-width", "1")
  .style("stroke", "black");

สนุกไชโย


2
ฉันหวังว่าคำตอบนี้จะได้รับการโหวตมากขึ้น เคยทำงานกับd3v4มาระยะหนึ่งแล้วเพิ่งค้นพบวิธีการนี้
ทำเครื่องหมาย

2
ในกรณีที่ไม่gมาจากไหน? นั่นคือ svg container หรือไม่?
Tschallacka

1
Tschallacka gควร<g></g>แท็ก
giankotarola

1
ความอัปยศนี้อยู่ไกลและหลังจาก 2 คำตอบที่มีคุณภาพ มันง่ายที่จะพลาดสิ่งนี้และเห็นได้ชัดว่าเรียบง่ายกว่าคำตอบอื่น ๆ
เคิร์ต

1
ขอบคุณ. ทำงานใน v5 ด้วย!
Chaitanya Bangera

53

ฉันใหม่สำหรับ d3 - จะพยายามอธิบายวิธีที่ฉันเข้าใจ แต่ฉันไม่แน่ใจว่าฉันได้รับทุกอย่างถูกต้อง

ความลับคือรู้ว่าวิธีการบางอย่างจะทำงานในพื้นที่ทำแผนที่ (ละติจูด, ลองจิจูด) และอื่น ๆ ในพื้นที่คาร์ทีเซียน (x, y บนหน้าจอ) พื้นที่การทำแผนที่ (โลกของเรา) เป็น (เกือบ) ทรงกลมพื้นที่คาร์ทีเซียน (หน้าจอ) จะแบน - เพื่อ map หนึ่งในช่วงอื่น ๆ ที่คุณจำเป็นต้องมีขั้นตอนวิธีการที่เรียกว่าการฉาย พื้นที่นี้สั้นเกินกว่าจะเจาะลึกลงไปในเรื่องที่น่าสนใจของการคาดการณ์และวิธีที่มันบิดเบือนลักษณะทางภูมิศาสตร์เพื่อที่จะเปลี่ยนเป็นทรงกลมเป็นระนาบ บางตัวได้รับการออกแบบมาเพื่อการอนุรักษ์มุมและอื่น ๆ เป็นการอนุรักษ์ระยะทางและอื่น ๆ - มีการประนีประนอมอยู่เสมอ (Mike Bostock มีตัวอย่างมากมาย)

ป้อนคำอธิบายรูปภาพที่นี่

ใน d3 วัตถุเส้นโครงมีคุณสมบัติกึ่งกลาง / ตัวตั้งค่าที่กำหนดในหน่วยแผนที่:

projection.center ([ตั้ง])

หากระบุจุดศูนย์กลางให้ตั้งค่ากึ่งกลางของเส้นโครงเป็นตำแหน่งที่ระบุอาร์เรย์สององค์ประกอบของลองจิจูดและละติจูดเป็นองศาและส่งคืนเส้นโครง หากไม่ได้ระบุจุดศูนย์กลางให้ส่งกลับจุดศูนย์กลางปัจจุบันซึ่งค่าเริ่มต้นคือ⟨0°, 0 °⟩

นอกจากนี้ยังมีการแปลให้เป็นพิกเซล - ที่ศูนย์การฉายยืนเทียบกับผืนผ้าใบ:

projection.translate ([จุด])

หากระบุจุดให้ตั้งค่าการแปลของโปรเจ็กเตอร์ให้ตรงกับอาเรย์สององค์ประกอบที่ระบุ [x, y] และส่งคืนการฉาย หากไม่ได้ระบุจุดให้ส่งคืนออฟเซ็ตการแปลปัจจุบันซึ่งค่าเริ่มต้นเป็น [480, 250] ออฟเซ็ตการแปลกำหนดพิกัดพิกเซลของกึ่งกลางของโปรเจ็กเตอร์ การชดเชยการแปลเริ่มต้นจะวางตำแหน่ง⟨0°, 0 °⟩ที่กึ่งกลางของพื้นที่ 960 × 500

เมื่อฉันต้องการจัดกึ่งกลางคุณลักษณะในผืนผ้าใบฉันชอบตั้งค่ากึ่งกลางของฉายภาพไว้ที่กึ่งกลางของกรอบคุณสมบัติ - สิ่งนี้ใช้ได้กับฉันเมื่อใช้Mercator (WGS 84, ใช้ใน google maps) สำหรับประเทศของฉัน (บราซิล) ไม่เคยทดสอบโดยใช้การฉายภาพและซีกโลกอื่น ๆ คุณอาจต้องทำการปรับเปลี่ยนสำหรับสถานการณ์อื่น ๆ แต่ถ้าคุณตอกย้ำหลักการพื้นฐานเหล่านี้คุณจะไม่เป็นไร

ตัวอย่างเช่นกำหนดเส้นโครงและเส้นทาง:

var projection = d3.geo.mercator()
    .scale(1);

var path = d3.geo.path()
    .projection(projection);

boundsวิธีจากpathผลตอบแทนกรอบพิกเซล ใช้เพื่อค้นหามาตราส่วนที่ถูกต้องโดยเปรียบเทียบขนาดเป็นพิกเซลกับขนาดในหน่วยแผนที่ (0.95 ให้ระยะขอบ 5% ที่เหมาะที่สุดสำหรับความกว้างหรือความสูง) เรขาคณิตพื้นฐานที่นี่การคำนวณความกว้าง / ความสูงของสี่เหลี่ยมให้มุมตรงข้ามกับเส้นทแยงมุม:

var b = path.bounds(feature),
    s = 0.9 / Math.max(
                   (b[1][0] - b[0][0]) / width, 
                   (b[1][1] - b[0][1]) / height
               );
projection.scale(s); 

ป้อนคำอธิบายรูปภาพที่นี่

ใช้d3.geo.boundsวิธีการหากล่องขอบในหน่วยแผนที่:

b = d3.geo.bounds(feature);

ตั้งค่ากึ่งกลางของเส้นโครงเป็นศูนย์กลางของกล่องขอบ:

projection.center([(b[1][0]+b[0][0])/2, (b[1][1]+b[0][1])/2]);

ใช้translateวิธีการย้ายจุดศูนย์กลางของแผนที่ไปยังกึ่งกลางผืนผ้าใบ:

projection.translate([width/2, height/2]);

ถึงตอนนี้คุณควรมีสถานที่ที่กึ่งกลางของแผนที่ซูมด้วยระยะขอบ 5%


มี bl.ocks ที่ไหนสักแห่ง?
Hugolpz

ขออภัยไม่มี bl.ocks หรือส่วนสำคัญคุณพยายามทำอะไร มันเป็นแบบคลิกเพื่อซูมไหม เผยแพร่และฉันสามารถดูรหัสของคุณได้
เปาโล Scardine

คำตอบและรูปภาพของ Bostockมีลิงก์ไปยังตัวอย่าง bl.ocks.org ซึ่งให้ฉันคัดลอกรหัสทั้งหมด งานเสร็จแล้ว +1 และขอบคุณสำหรับภาพประกอบที่ยอดเยี่ยมของคุณ!
Hugolpz

4

มีวิธีcenter () ที่คุณสามารถใช้เพื่อยอมรับคู่ lat / lon

จากสิ่งที่ฉันเข้าใจแล้ว Translate () จะใช้เพื่อย้ายพิกเซลของแผนที่เท่านั้น ฉันไม่แน่ใจว่าจะกำหนดขนาดได้อย่างไร


8
หากคุณใช้ TopoJSON และต้องการจัดตำแหน่งทั้งแผนที่คุณสามารถเรียกใช้ topojson ด้วย --bbox เพื่อรวมแอตทริบิวต์ bbox ในวัตถุ JSON พิกัดละติจูด / ลองจิจูดสำหรับจุดศูนย์กลางควรเป็น [(b [0] + b [2]) / 2, (b [1] + b [3]) / 2] (โดยที่ b คือค่า bbox)
เปาโล Scardine

3

นอกเหนือจากศูนย์กลางแผนที่ใน d3 ที่กำหนดวัตถุ geoJSONโปรดทราบว่าคุณอาจต้องการfitExtent()มากกว่าfitSize()หากคุณต้องการระบุการขยายรอบขอบวัตถุของคุณ fitSize()กำหนดช่องว่างภายในนี้เป็น 0 โดยอัตโนมัติ


2

ฉันมองไปรอบ ๆ บนอินเทอร์เน็ตเพื่อหาวิธีที่ไม่ยุ่งยากในการจัดตำแหน่งแผนที่ของฉันและได้รับแรงบันดาลใจจากคำตอบของ Jan van der Laan และ mbostock นี่คือวิธีที่ง่ายกว่าในการใช้ jQuery หากคุณใช้คอนเทนเนอร์สำหรับ svg ฉันสร้างเส้นขอบของ 95% สำหรับช่องว่างภายใน / ขอบ ฯลฯ

var width = $("#container").width() * 0.95,
    height = $("#container").width() * 0.95 / 1.9 //using height() doesn't work since there's nothing inside

var projection = d3.geo.mercator().translate([width / 2, height / 2]).scale(width);
var path = d3.geo.path().projection(projection);

var svg = d3.select("#container").append("svg").attr("width", width).attr("height", height);

หากคุณกำลังมองหามาตราส่วนที่แน่นอนคำตอบนี้จะไม่เหมาะกับคุณ แต่ถ้าชอบฉันคุณต้องการแสดงแผนที่ที่รวมศูนย์ไว้ในคอนเทนเนอร์นี่น่าจะเพียงพอแล้ว ฉันพยายามแสดงแผนที่ Mercator และพบว่าวิธีนี้มีประโยชน์ในการรวมศูนย์กลางแผนที่ของฉันและฉันสามารถตัดส่วนขั้วโลกใต้ออกได้ง่ายเนื่องจากฉันไม่ต้องการ


1

หากต้องการเลื่อน / ซูมแผนที่คุณควรดูการวาง SVG บนแผ่นพับ นั่นจะง่ายกว่าการเปลี่ยน SVG ดูตัวอย่างนี้http://bost.ocks.org/mike/leaflet/จากนั้นวิธีเปลี่ยนศูนย์กลางแผนที่ในแผ่นพับ


หากการเพิ่มการพึ่งพาอาศัยกันเป็นเรื่องที่น่ากังวล PAN และ ZOOM สามารถทำได้อย่างง่ายดายใน d3 บริสุทธิ์ดูstackoverflow.com/questions/17093614//
เปาโล Scardine

คำตอบนี้ไม่ได้เกี่ยวข้องกับ d3 จริงๆ คุณสามารถเลื่อน / ซูมแผนที่ใน d3 ได้เช่นกันไม่จำเป็นต้องใช้แผ่นพับ (เพิ่งรู้ว่าโพสต์เก่านี้เป็นเพียงการเรียกดูคำตอบ)
JARRRRG

0

ด้วยคำตอบของ mbostocks และความเห็นของ Herb Caudill ฉันเริ่มพบปัญหากับ Alaska ตั้งแต่ฉันใช้ Mercator Projector ฉันควรทราบว่าเพื่อจุดประสงค์ของฉันเองฉันกำลังพยายามทำโครงการและเป็นศูนย์กลางของสหรัฐอเมริกา ฉันพบว่าฉันต้องแต่งงานกับคำตอบทั้งสองด้วยคำตอบของแจนแวนเดอร์ลันโดยมีข้อยกเว้นสำหรับรูปหลายเหลี่ยมที่ซ้อนกันในซีกโลก (รูปหลายเหลี่ยมที่ลงท้ายด้วยค่าสัมบูรณ์สำหรับตะวันออก - ตะวันตกที่มากกว่า 1):

  1. ตั้งค่าการฉายภาพง่ายๆใน Mercator:

    projection = d3.geo.mercator (). scale (1) .translate ([0,0]);

  2. สร้างเส้นทาง:

    path = d3.geo.path (). projection (การฉายภาพ);

3. ตั้งค่าขอบเขตของฉัน:

var bounds = path.bounds(topoJson),
  dx = Math.abs(bounds[1][0] - bounds[0][0]),
  dy = Math.abs(bounds[1][1] - bounds[0][1]),
  x = (bounds[1][0] + bounds[0][0]),
  y = (bounds[1][1] + bounds[0][1]);

4. เพิ่มข้อยกเว้นสำหรับอลาสก้าและรัฐที่ทับซ้อนกับซีกโลก:

if(dx > 1){
var center = d3.geo.centroid(topojson.feature(json, json.objects[topoObj]));
scale = height / dy * 0.85;
console.log(scale);
projection = projection
    .scale(scale)
    .center(center)
    .translate([ width/2, height/2]);
}else{
scale = 0.85 / Math.max( dx / width, dy / height );
offset = [ (width - scale * x)/2 , (height - scale * y)/2];

// new projection
projection = projection                     
    .scale(scale)
    .translate(offset);
}

ฉันหวังว่านี่จะช่วยได้.


0

สำหรับผู้ที่ต้องการปรับแนวตั้งและแนวนอนนี่คือคำตอบ:

  var width  = 300;
  var height = 400;

  var vis = d3.select("#vis").append("svg")
      .attr("width", width).attr("height", height)

  d3.json("nld.json", function(json) {
      // create a first guess for the projection
      var center = d3.geo.centroid(json)
      var scale  = 150;
      var offset = [width/2, height/2];
      var projection = d3.geo.mercator().scale(scale).center(center)
          .translate(offset);

      // create the path
      var path = d3.geo.path().projection(projection);

      // using the path determine the bounds of the current map and use 
      // these to determine better values for the scale and translation
      var bounds  = path.bounds(json);
      var hscale  = scale*width  / (bounds[1][0] - bounds[0][0]);
      var vscale  = scale*height / (bounds[1][1] - bounds[0][1]);
      var scale   = (hscale < vscale) ? hscale : vscale;
      var offset  = [width - (bounds[0][0] + bounds[1][0])/2,
                        height - (bounds[0][1] + bounds[1][1])/2];

      // new projection
      projection = d3.geo.mercator().center(center)
        .scale(scale).translate(offset);
      path = path.projection(projection);

      // adjust projection
      var bounds  = path.bounds(json);
      offset[0] = offset[0] + (width - bounds[1][0] - bounds[0][0]) / 2;
      offset[1] = offset[1] + (height - bounds[1][1] - bounds[0][1]) / 2;

      projection = d3.geo.mercator().center(center)
        .scale(scale).translate(offset);
      path = path.projection(projection);

      // add a rectangle to see the bound of the svg
      vis.append("rect").attr('width', width).attr('height', height)
        .style('stroke', 'black').style('fill', 'none');

      vis.selectAll("path").data(json.features).enter().append("path")
        .attr("d", path)
        .style("fill", "red")
        .style("stroke-width", "1")
        .style("stroke", "black")
    });

0

ฉันจะจัดศูนย์กลางของ Topojson ไว้ที่ใดซึ่งฉันต้องการดึงคุณลักษณะออก:

      var projection = d3.geo.albersUsa();

      var path = d3.geo.path()
        .projection(projection);


      var tracts = topojson.feature(mapdata, mapdata.objects.tx_counties);

      projection
          .scale(1)
          .translate([0, 0]);

      var b = path.bounds(tracts),
          s = .95 / Math.max((b[1][0] - b[0][0]) / width, (b[1][1] - b[0][1]) / height),
          t = [(width - s * (b[1][0] + b[0][0])) / 2, (height - s * (b[1][1] + b[0][1])) / 2];

      projection
          .scale(s)
          .translate(t);

        svg.append("path")
            .datum(topojson.feature(mapdata, mapdata.objects.tx_counties))
            .attr("d", path)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.