将 Bl.ocks.org 图实现到 Vue.js 组件中

Implementing a Bl.ocks.org graph into a Vue.js component

我是 D3 初学者,我想在我的 Vue.js 组件中使用 this d3 元素。这里的问题是我需要的周期性轮换不起作用。它开始在全局定义的元素投影上循环 null 错误。似乎第一次有效,但在第二次中,对象不再定义。

代码如下:

<template>
    <div>
        <svg></svg>
    </div>
</template>

<script>
import * as d3 from "d3";
import { feature } from "topojson-client";
import { json } from "d3-fetch";
export default {
    name: "WorldCases",
    data: function() {
        return {
            svg: null,
            markerGroup: null,
            projection: null,
            initialScale: null,
            path: null,
            center: null,
            config: null,
            locations: [
                { latitude: 22, longitude: 88 },
                { latitude: 12.61315, longitude: 38.37723 },
                { latitude: -30, longitude: -58 },
                { latitude: -14.270972, longitude: -170.132217 },
                { latitude: 28.033886, longitude: 1.659626 },
                { latitude: 40.463667, longitude: -3.74922 },
                { latitude: 35.907757, longitude: 127.766922 },
                { latitude: 23.634501, longitude: -102.552784 },
            ],
        };
    },
    mounted() {
        this.graph();
    },
    methods: {
        graph() {
            const width = 960;
            const height = 500;
            this.config = {
                speed: 0.005,
                verticalTilt: -30,
                horizontalTilt: 0,
            };
            this.svg = d3
                .select("svg")
                .attr("width", width)
                .attr("height", height);
            this.markerGroup = this.svg.append("g");
            this.projection = d3.geoOrthographic();
            console.log(this.projection);
            this.initialScale = this.projection.scale();
            this.path = d3.geoPath().projection(this.projection);
            this.center = [width / 2, height / 2];

            this.drawGlobe();
            this.drawGraticule();

            d3.timer(function(elapsed) {
                this.projection.rotate([
                    this.config.speed * elapsed - 120,
                    this.config.verticalTilt,
                    this.config.horizontalTilt,
                ]);
                this.svg.selectAll("path").attr("d", this.path);
                this.drawMarkers();
            }); 
        },
        drawGlobe() {
            Promise.all([json("./world-110m.json")]).then(([worldData, error]) => {
                // Do your stuff. Content of both files is now available in stations and svg
                this.svg
                    .selectAll(".segment")
                    .data(feature(worldData, worldData.objects.countries).features)
                    .enter()
                    .append("path")
                    .attr("class", "segment")
                    .attr("d", this.path)
                    .style("stroke", "#888")
                    .style("stroke-width", "1px")
                    .style("fill", (d, i) => "#e5e5e5")
                    .style("opacity", ".6");
                this.drawMarkers();
            });
        },
        drawMarkers() {
            const markers = this.markerGroup.selectAll("circle").data(this.locations);
            markers
                .enter()
                .append("circle")
                .merge(markers)
                .attr("cx", (d) => this.projection([d.longitude, d.latitude])[0])
                .attr("cy", (d) => this.projection([d.longitude, d.latitude])[1])
                .attr("fill", (d) => {
                    const coordinate = [d.longitude, d.latitude];
                    var gdistance = d3.geoDistance(coordinate, this.projection.invert(this.center));
                    return gdistance > 1.57 ? "none" : "steelblue";
                })
                .attr("r", 7);

            this.markerGroup.each(function() {
                this.parentNode.appendChild(this);
            });
        },

        drawGraticule() {
            const graticule = d3.geoGraticule().step([10, 10]);

            this.svg
                .append("path")
                .datum(graticule)
                .attr("class", "graticule")
                .attr("d", this.path)
                .style("fill", "#fff")
                .style("stroke", "#ccc");
        },
    },
};
</script>

<style></style>

错误如下图所示:

我该如何解决?在此配置中它不起作用。

谢谢

我解决了我的问题,记得在 Javascript 中,当我们在其他函数中工作时,有时“this”元素并不总是我们所期望的。

所以我需要做的是将“this”对象保存在一个变量中并使用该变量来执行我需要的操作:

var x = this;
d3.timer(function(elapsed) {
            x.projection.rotate([
                x.config.speed * elapsed - 120,
                x.config.verticalTilt,
                x.config.horizontalTilt,
            ]);
            x.svg.selectAll("path").attr("d", this.path);
            x.drawMarkers();
        });