d3.js单击并应用缩放和平移以将位于目标分区内的点分配到触发的细分

问题描述 投票:7回答:1

基于the response and example made by Andrew Reid,我制作了这个points_in_subdivisons这里的笔代码:单击屏幕上的区域(德国)时我们希望提供从地图上的一个特写到另一个的平滑动画通过使用ZOOM OUT,PAN,ZOOM IN。

  • 我在国家/地区级别上有许多部门(国家),然后在每个国家/地区中有很多子部门(区域)。
  • 在我的示例中,很多点分散在所有分区(国家)上,主要位于德国上方。
  • [当我必须单击目标分区(国家)时,我必须仅获得与我刚刚单击的目标分区(国家)相对应的点
  • 这表示触发细分(区域)的缩放(当单击制作),代码应采用仅存在于内部的所有要点目标区域(国家/地区)的轮廓(刚刚单击)和点封闭式应散布在其相应的分区(区域)中。

要实现此功能,根据迈克尔·罗文斯基的评论:在操纵()函数中,该代码只能过滤和提取嵌入在目标细分区域和触发细分区域内的点,并排除位于外部的标记。内部函数redraw()中的enter退出模式效果很好。

var svg = d3.select("svg");

width = 960;
height = 500;
var dataArray  = [];
var mydataArray= []; 
var projection = d3.geoMercator();
var baseProjection = d3.geoMercator();

var path = d3.geoPath().projection(projection);
var gBackground = svg.append("g"); // appended first
var  gProvince = svg.append("g");  
var gDataPoints = svg.append("g"); // appended second
var ttooltip = d3.select("body").append("div")
      .attr("class", "ttooltip");
var csvPath="https://dl.dropbox.com/s/rb9trt4zy87ezi3/lonlat.csv?dl=0";

d3.csv(csvPath, function(error, data) {

  if (error) throw error;

  d3.json("https://gist.githubusercontent.com/rveciana/5919944/raw/2fef6be25d39ebeb3bead3933b2c9380497ddff4/nuts0.json", function(error, nuts0) {

  if (error) throw error;

  d3.json("https://gist.githubusercontent.com/rveciana/5919944/raw/2fef6be25d39ebeb3bead3933b2c9380497ddff4/nuts2.json", function(error, nuts2) {
    if (error) throw error;

  // convert topojson back to geojson
  var countries = topojson.feature(nuts0, nuts0.objects.nuts0);
  var regions = topojson.feature(nuts2, nuts2.objects.nuts2);
  baseProjection.fitSize([width,height],regions);
  projection.fitSize([width,height],regions);
  var color = d3.scaleLinear().range(["steelblue","darkblue"]).domain([0,countries.features.length]);
  var regionColor = d3.scaleLinear().range(["orange","red"]);

  baseProjection.fitSize([width,height],countries);
  projection.fitSize([width,height],countries);
  var featureCollectionCountries = { "type":"FeatureCollection", "features": countries.features };
  gBackground
    .attr("class", "country")
    .selectAll("path")
    .data(countries.features)
    .enter()
    .append("path")
    .attr("fill",function(d,i) { return color(i); })
    .attr("opacity",0.7)
    .attr("d", path)
    .style("stroke","black")
    .style("stroke-width",0)
    .on("mouseover", function() {
        d3.select(this)
          .style("stroke-width",1)
          .raise();
    })
    .on("mouseout", function(d,i) {
        d3.select(this)
          .style("stroke-width", 0 );
    })
    ///// now zoom in when clicked and show subdivisions:
    .on("click", function(d) {
        // remove all other subdivisions:
        d3.selectAll(".region")
          .remove();

        // add new features:


        var features = regions.features.filter(function(feature) { return feature.properties.nuts_id.substring(0,2) == d.properties.nuts_id; });



        regionColor.domain([0,features.length])

        gProvince.selectAll(null)
          .data(features)
          .enter()
          .append("path")
          .attr("class","region")
          .attr("fill", function(d,i) { return regionColor(i) })
          .attr("d", path)
          .style("stroke","black")
          .style("stroke-width",0)
          .on("click", function() {
            zoom(projection,baseProjection);
            d3.selectAll(".subdivision")
              .remove();          
          })
          .on("mouseover", function() {
                d3.select(this)
                  .style("stroke-width",1)
                  .raise();
          })
          .on("mouseout", function(d,i) {
                d3.select(this)
                  .style("stroke-width", 0 );
          })
          .raise()

        // zoom to selected features:
        var featureCollection = { "type":"FeatureCollection", "features": features }

        manipulate(data,features);
        redraw(featureCollection);

        var endProjection = d3.geoMercator();

        zoom(projection,endProjection.fitExtent([[50,50],[width-50,height-50]],featureCollection));

    }); 

    dataArray  = data;
    redraw(featureCollectionCountries);
  });
});
});

function zoom(startProjection,endProjection,middleProjection) {

  if(!middleProjection) {
      d3.selectAll("path")
        .transition()
        .attrTween("d", function(d) {
          var s = d3.interpolate(startProjection.scale(), endProjection.scale());
          var x = d3.interpolate(startProjection.translate()[0], endProjection.translate()[0]);
          var y = d3.interpolate(startProjection.translate()[1], endProjection.translate()[1]);
            return function(t) {
              projection
                .scale(s(t))
                .translate([x(t),y(t)])

              path.projection(projection);
              return path(d);
            }
         })
        .duration(1000);
    }
    else {
      d3.selectAll("path")
        .transition()
        .attrTween("d", function(d) {

          var s1 = d3.interpolate(startProjection.scale(),middleProjection.scale());
          var s2 = d3.interpolate(middleProjection.scale(),endProjection.scale()); 
          var x = d3.interpolate(startProjection.translate()[0], endProjection.translate()[0]);
          var y = d3.interpolate(startProjection.translate()[1], endProjection.translate()[1]);

          function s(t) {
            if (t < 0.5) return s1; return s2; 
          }

           return function(t) {                 
               projection
                .translate([x(t),y(t)])
                .scale(s(t)(t))

              path.projection(projection);
              return path(d);
            }
         })
        .duration(1500);    
    }

}


function redraw(featureCollection,type) {
        var mapG = d3.select('svg g.country');

        d3.selectAll('circle')
          .remove();

        let grp = gDataPoints
                  .attr("class", "circle")
                  .selectAll("circle")
                  .data(dataArray,function(d) { return d.NOM; })
        let grpEnter = grp.enter()
        let group = grpEnter
        group.append("circle")
             .attr('fill', 'rgba(135, 5, 151, 125)')
             .attr('stroke', 'black')
             .each(function(d) {
                                 if (d.lon === null ) return;
                                 if (isNaN(d.lon ))return;
                                 if (d.lat === null) return;
                                 if (isNaN(d.lat ))return;
                                 var pos = projection([parseFloat(d.lon), parseFloat(d.lat)]);
                                 d.cx = pos[0];
                                 d.cy = pos[1];
             })
             .attr("cx", function(d) {
                        return d.cx;
             })
            .attr("cy", function(d) {
                    return d.cy;
            })
            .attr("r",0.5)
            .on("mouseover", showTooltip)
            .on("mouseout", hideTooltip)          
            .on('mousemove', function(d) {
                                var xPos = d3.mouse(this)[0] - 15;
                                var yPos = d3.mouse(this)[1] - 55;
                                ttooltip.attr('transform', 'translate(' + xPos + ',' + yPos + ')');
                                ttooltip.style('opacity', 1);
                                var html = "<span>" + d.lon+ "</span>, <span>" + d.lat + "</span>";
                                 ttooltip.html(html);

            });
            // Setup each circle with a transition, each transition working on transform attribute,
            // and using the translateFn
            group
                .transition()
                .duration(2000)
                .attrTween("transform",function(d) {
                             return  mapG._groups[0][0] != null ? recenter(featureCollection): null;
                 });
            group.exit().remove() // exit > remove >  g

    }



    function recenter(featureCollection) {
        console.log('recentering');     

    };


function manipulate(data,features){      

                    dataArray= [];
                    mydataArray =[];        

                    data.forEach(function(ddd) 
                    {
                        features.forEach(function(feature) 
                        {
                            var polygoneOriginal =feature;

                            var points = [parseFloat(ddd.lon), parseFloat(ddd.lat)];

                            var isIn = d3.geoContains(polygoneOriginal, points);
                            if(isIn)
                            {

                               var element = ddd;
                                mydataArray.pushIfNotExist(element, function(e) { 
                                    return e.lat === element.lat && e.lon === element.lon   ; 
                                });

                            }

                        });


                    });

                    if(mydataArray.length>0)
                    {

                       var columnsArray= ["lon","lat"];
                       dataArray=mydataArray;
                       dataArray.columns = columnsArray;


                    }      
}


    function showTooltip(d) {
      var html = "<span>" + d.lon+ "</span>, <span>" + d.lat + "</span>";
      ttooltip.html(html);
      ttooltip
        .style("left", window.pageXOffset + d3.event.x + 12 + "px")
        .style("top", window.pageYOffset + d3.event.y + 12 + "px")
        .transition()
        .style("opacity", 1);

        return d3.select(this).attr('fill', 'rgba(103, 65, 114, 0.8)');

    }

function hideTooltip() {
      ttooltip
        .transition()
        .style("opacity", 0);
         return d3.select(this).attr('fill', 'rgba(103, 65, 114, 0.5)');
}


// check if an element exists in array using a comparer function
// comparer : function(currentElement)
Array.prototype.inArray = function(comparer) { 
    for(var i=0; i < this.length; i++) { 
        if(comparer(this[i])) return true; 
    }
    return false; 
}; 

// adds an element to the array if it does not already exist using a comparer 
// function
Array.prototype.pushIfNotExist = function(element, comparer) { 
    if (!this.inArray(comparer)) {
        this.push(element);
    }
};

我的问题如下:如何使“缩放”(对于点圆)正常工作:现在,在地图上单击x y点将不会缩放。它们在背景中渲染为圆形,我希望它们与地图一起移动。这意味着如何应用相同的动画缩放(当单击分区来触发细分时),以便目标细分内的那些点在过渡中跟随并随地图一起移动,我们可以看到圆点清楚地分布在[[正确的相应细分]]? 更新

[Andrew Reid描述了here如何使用d3.js完成平滑缩放

所以遵循他的提示。

我在redraw()函数中添加了以下说明

var mapG = d3.select('svg g.country'); group .transition() .duration(2000) .attrTween("transform",function(d) { return mapG._groups[0][0] != null ? recenter(): null; });

然后我们应该将代码添加到该函数中,该函数实际上应该将过去者(featureCollection)函数移动到

function recenter(featureCollection) { // TO ADD CODE TO BE IMPLEMENTED HERE };

您的合作,参与和帮助应该描述一个具有自己的csv文件和自己的投影的圈子的直接解决方案,或者是圈子与json文件合并的替代解决方案:例如圈子协调lon / lat并合并到国家/地区。 json counties.json和community.json和city.json以及json文件中的多层功能,并处理每一层中的每次点击(国家-点击-内部区域-点击-内部社区在城市和标记内单击并且在插值的平滑缩放应用于每个图层的情况下,标签可以充分移动。

非常感谢您的合作,参与和帮助!

根据安德鲁·里德(Andrew Reid)的回答和示例,我在这里点了笔代码:points_in_subdivisons:单击屏幕上的区域(德国)时,我们希望提供一个平滑的动画...
d3.js svg zoom map-projections
1个回答
0
投票
© www.soinside.com 2019 - 2024. All rights reserved.