这是一个奇怪的问题,而且有点复杂,提前道歉。 更新 - 最后发现是两个问题请看我的答案。
以下是我的错误:EXCEPTION: this.svg.selectAll(...).data(...).enter is not a function
我有一个 Angular CLI 客户端和一个 Node API 服务器。我可以通过可观察对象 (下面的代码) 从服务中检索一个 states.json 文件。d3 喜欢这个文件并显示了预期的美国地图。
一旦我将服务的目标从文件更改为 IBM Bluemix Cloudant 服务器,我在客户端中就会得到上面的错误。
当我使用 ngOnInit 进行变化并控制台记录输出时,最初 mapData 打印为空数组,并且抛出错误。 这是错误的明显来源,因为没有数据,但 Chrome 调试器显示获取请求处于挂起状态。当请求完成时,数据按预期打印在控制台中。
- angular-cli 版本为 1.0.0-beta.26
- angular 版本为 ^2.3.1
- d3 版本为 ^4.4.4
- rxjs 版本为 ^5.0.1
map.component.ts:
import { Component, ElementRef, Input } from '@angular/core';
import * as D3 from 'd3';
import '../rxjs-operators';
import { MapService } from '../map.service';
@Component({
selector: 'map-component',
templateUrl: './map.component.html',
styleUrls: ['./map.component.css']
})
export class MapComponent {
errorMessage: string;
height;
host;
htmlElement: HTMLElement;
mapData;
margin;
projection;
path;
svg;
width;
constructor (private _element: ElementRef, private _mapService: MapService) {
this.host = D3.select(this._element.nativeElement);
this.getMapData();
this.setup();
this.buildSVG();
}
getMapData() {
this._mapService.getMapData()
.subscribe(
mapData => this.setMap(mapData),
error => this.errorMessage = <any>error
)
}
setup() {
this.margin = {
top: 15,
right: 50,
bottom: 40,
left: 50
};
this.width = document.querySelector('#map').clientWidth - this.margin.left - this.margin.right;
this.height = this.width * 0.6 - this.margin.bottom - this.margin.top;
}
buildSVG() {
this.host.html('');
this.svg = this.host.append('svg')
.attr('width', this.width + this.margin.left + this.margin.right)
.attr('height', this.height + this.margin.top + this.margin.bottom)
.append('g')
.attr('transform', 'translate(' + this.margin.left + ',' + this.margin.top + ')');
}
setMap(mapData) {
this.mapData = mapData;
this.projection = D3.geoAlbersUsa()
.translate([this.width /2 , this.height /2 ])
.scale(650);
this.path = D3.geoPath()
.projection(this.projection);
this.svg.selectAll('path')
.data(this.mapData.features)
.enter().append('path')
.attr('d', this.path)
.style('stroke', '#fff')
.style('stroke-width', '1')
.style('fill', 'lightgrey');
}
}
地图服务.ts:
import { Http, Response } from '@angular/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
@Injectable()
export class MapService {
private url = 'http://localhost:3000/api/mapData';
private socket;
constructor (private _http: Http) { }
getMapData(): Observable<any> {
return this._http.get(this.url)
.map(this.extractData)
.catch(this.handleError);
}
private extractData(res: Response) {
let body = res.json();
return body.data || {};
}
private handleError(error: any) {
let errMsg = (error.message) ? error.message :
error.status ? `${error.status} - ${error.statusText}` : 'Server error';
console.error(errMsg);
return Promise.reject(errMsg);
}
}
这是因为异步处理且调用数据时间过长导致的吗?我曾希望这个Uncaught TypeError: canvas.selectAll(...).data(...).enter is not a function in d3问题能够提供一些见解,但我并没有看到任何信息。非常感谢您的任何帮助和见解!编辑:
以下是来自Mark要求的Chrome标题部分的屏幕截图。响应选项卡显示数据正常传输为GeoJSON对象。我还将该响应复制到本地文件中,并使用它作为地图源进行了测试,结果为正面反馈。
迄今为止的数据测试:GeoJSON 文件(2.1mb)
- 本地文件,本地服务器:成功(响应时间 54ms)
- 相同的文件,远程服务器:D3 在数据返回浏览器之前出现错误(750ms)
- 从远程服务器调用 API:D3 在数据返回浏览器之前出现错误(2.1 秒)
![snap of Chrome Headers](https://istack.dev59.com/eLmXh.webp)
mapData.features
的输出吗? - AssansetMap()
方法会被调用两次吗?一次是传递一个空数组,另一次是传递预期的数组吗? - wdickerson