一、获取中国的地图数据
地图json数据下载二、绘制过程中遇到的问题
1、理解SVG viewport,viewBox,preserveAspectRatio缩放
1)viewBox
作用:viewBox顾名思意是“视区盒子”的意思,定义该属性,内容会根据你的设置,铺满区域。
2)viewport3)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() { } }