ng-alain+D3绘制地图

一、获取中国的地图数据

     地图json数据下载

二、绘制过程中遇到的问题

    1、理解SVG viewport,viewBox,preserveAspectRatio缩放
1)viewBox
         viewBox="x, y, width, height" // x:左上角横坐标,y:左上角纵坐标,width:宽度,height:高度
         作用:viewBox顾名思意是“视区盒子”的意思,定义该属性,内容会根据你的设置,铺满区域。
2)viewport

3)preserveAspectRation

    2、增加缩放、拖拽 
/**
 * 绘制地图
 */
drawMap() {
  const svg = this.svg;
  const width = Number(this.width);
  const height = Number(this.height);
  let color = this.util.getColor(null);
  color = color.concat(color, color, color);

  const g = svg.append('g');
  svg.call(d3.zoom()
    .scaleExtent([1 / 2, 8])
    .on("zoom", zoomed));

  const me = this;
  // https://raw.githubusercontent.com/aruis/chinamap/master/data/cn.json
  d3.json(DATA_CHINA_JSON).then((res)=>{
    // fitExtent方法填充画布 语法检测不过,通过取巧方式通过
    // 先定义一个数组,将对象push进去,将data[0]作为参数传入
    const data = [];
    data.push(res)
    // center() 函数是用于设定地图的中心位置,[107,31] 指的是经度和纬度。
    // scale() 函数用于设定放大的比例。
    // translate() 函数用于设定平移。
    const proj = d3.geoMercator().center([105, 38])
      .fitExtent([[0, 0], [width, height]], data[0]);
      // .scale(850)
      // .translate([ width / 2, height/2 ]);
    const path = d3.geoPath().projection(proj);

    g.append('g')
      .selectAll('path')
      .data(res['features'])
      .enter()
      .append('path')
      .on('mouseover', function (d, i) {
        d3.select(this).attr('fill','yellow');
        me.tip.html('<div>'+d.properties.name+'</div>');
        me.tip.show();
      })
      .on('mouseout', function (d, i) {
        d3.select(this)
          .attr('fill',color[i]);
          me.tip.hide();
      })
      .attr('fill',function (d, i) {
        return color[i];
      })
      .attr('d', path);
  })
  function zoomed() {
    g.attr("transform", d3.event.transform);
  }
  function dragged(d) {
    d3.select(this).attr("cx", d.x = d3.event.x).attr("cy", d.y = d3.event.y);
  }
}
遇到的问题问题:
Argument of type '{}' is not assignable to parameter of type 'ExtendedGeometryCollection<GeoGeometryObjects>'.
  Property 'type' is missing in type '{}'.

    语法检查一直报错

    解决办法:将数据包裹到数组中,让后把数组的[0]传进去

    
      // fitExtent方法填充画布 语法检测不过,通过取巧方式通过
      // 先定义一个数组,将对象push进去,将data[0]作为参数传入
      const data = [];
      data.push(res)
      // center() 函数是用于设定地图的中心位置,[107,31] 指的是经度和纬度。
      // scale() 函数用于设定放大的比例。
      // translate() 函数用于设定平移。
      const proj = d3.geoMercator().center([105, 38])
        .fitExtent([[0, 0], [width, height]], data[0]);
        // .scale(850)
        // .translate([ width / 2, height/2 ]);
      const path = d3.geoPath().projection(proj);
    3、完整代码

    

const DATA_CHINA_JSON = 'assets/axis/d3_shan3xi.json';


import {
  Component,
  OnDestroy,
  OnInit,
  Input,
  AfterContentInit,
  Output,
  EventEmitter,
  ElementRef,
} from '@angular/core';

import { NzMessageService } from 'ng-zorro-antd';
import { _HttpClient } from '@delon/theme';
import { AppUtil } from '@core/util/util.service';
import * as d3 from 'd3';

@Component({
  selector: 'app-D3chart',
  template: `<nz-content [ngStyle]="{'padding': 0,'width': width,'height':height}">
    <svg [ngStyle]="{'width': width - 48,'height':height}"></svg>
    <div id="app-D3chart_tip" class="chart-tip-d3"></div>
    <canvas id="app-D3chart_canvas" height="0" width="0"></canvas>
  </nz-content>
  `,
  styles: [
    `
      path {
        fill: #ccc;
        stroke: #fff;
        stroke-width: .5px;
      }

      path:hover {
        fill: red;
      }
      .chart-tip-d3 {
        color: white;
        border: 1px solid white;
        border-radius: 3px;
        font-size: 14px;
        background: #212226;
        opacity: 0;
        position: absolute;
        pointer-events: none;
      }
  `,
  ],
})
export class D3WidgetComponent implements OnInit, OnDestroy, AfterContentInit{
  constructor(private http: _HttpClient,
              public msg: NzMessageService,
              public util: AppUtil,
              public el: ElementRef,
              ) {
  }
  static readonly KEY = 'app-D3chart';
  dom: any;
  svg: any;
  tip: any;
  @Input() width = '100%';
  @Input() height = '100%';
  @Output('getWidth')
  getWidth: EventEmitter<number> = new EventEmitter<number>();
  ngOnInit() {
    this.initDom();
    this.tip = this.initTip();
    this.drawMap();
  }

  /**
   * dom初始化
   */
  initDom() {
    const dom = this.el.nativeElement.querySelector('div');
    this.dom = dom;
    this.getWidth.emit();
    this.width = dom.offsetWidth || this.width;
    this.height = dom.offsetHeight || parseInt(this.height, 10);

    const svg = d3.select(this.el.nativeElement.querySelector('svg'))
      .attr('width', Number(this.width) - 48)
      .attr('height', this.height)
      .attr('preserveAspectRatio', 'xMidYMid')
      .attr('viewBox', '0 0 ' + this.width + ' ' + this.height);
    this.svg = svg;
  }

  /**
   * 绘制地图
   */
  drawMap() {
    const svg = this.svg;
    const width = Number(this.width) - 48;
    const height = Number(this.height);
    let color = this.util.getColor(null);
    color = color.concat(color, color, color);

    const g = svg.append('g');
    svg.call(d3.zoom()
      .scaleExtent([1 / 2, 8])
      .on("zoom", zoomed));

    const me = this;
    // https://raw.githubusercontent.com/aruis/chinamap/master/data/cn.json
    d3.json(DATA_CHINA_JSON).then((res)=>{
      // fitExtent方法填充画布 语法检测不过,通过取巧方式通过
      // 先定义一个数组,将对象push进去,将data[0]作为参数传入
      const data = [];
      data.push(res)
      // center() 函数是用于设定地图的中心位置,[107,31] 指的是经度和纬度。
      // scale() 函数用于设定放大的比例。
      // translate() 函数用于设定平移。
      const proj = d3.geoMercator().center([105, 38])
        .fitExtent([[0, 0], [width, height]], data[0]);
        // .scale(850)
        // .translate([ width / 2, height/2 ]);
      const path = d3.geoPath().projection(proj);

      g.append('g')
        .selectAll('path')
        .data(res['features'])
        .enter()
        .append('path')
        .on('mouseover', function (d, i) {
          d3.select(this).attr('fill','yellow');
          me.tip.html('<div>'+d.properties.name+'</div>');
          me.tip.show();
        })
        .on('mouseout', function (d, i) {
          d3.select(this)
            .attr('fill',color[i]);
            me.tip.hide();
        })
        .attr('fill',function (d, i) {
          return color[i];
        })
        .attr('d', path);
    })
    function zoomed() {
      g.attr("transform", d3.event.transform);
    }
    function dragged(d) {
      d3.select(this).attr("cx", d.x = d3.event.x).attr("cy", d.y = d3.event.y);
    }
  }

  /**
   * tio 处理
   * @param d
   * @returns {D3Tooltip}
   */
  initTip() {
    function D3Tooltip() {

    }
    D3Tooltip.prototype.html = function(html) {
      this.$el = d3.select('#app-D3chart_tip');
      this.$el.html(html);
    };

    D3Tooltip.prototype.show = function() {
      const d3Event = d3.event;
      this.$el
        .transition()
        .duration(200)
        .style('opacity', 0.8);
      this.$el
        .style('left', d3Event.pageX + 'px')
        .style('top', d3Event.pageY - 128 + 'px');
    };

    D3Tooltip.prototype.hide = function() {
      this.$el
        .transition()
        .duration(500)
        .style('opacity', 0);
    };
    return new D3Tooltip();
  }
  ngAfterContentInit() {

  }
  ngOnDestroy() {

  }
}

猜你喜欢

转载自blog.csdn.net/ligaoming_123/article/details/80825565
今日推荐