javascript - vue 组件中的 d3.js - 如何将鼠标事件挂接到元素?

标签 javascript d3.js vue.js vuejs2 vue-component

我有一个用于交互式 D3.js map 的普通 javascript 工作代码,现在正尝试从中创建一个 vue.js 组件。我已将所有函数定义为方法,但没有收到任何警告或错误消息,但没有鼠标事件被 Hook 。我已经尝试过 D3.js 方式 (.on("click", this.clickBG)) 以及 vue (.attr("v-on:click","clickBG")) 都没有成功。

    // vorlage: https://dev.to/ignoreintuition/binding-data-to-charts-using-vue-components-and-d3-4i27
    import * as d3 from 'd3';
    
    export default {
        props: ['data','vegbed'], 
        data: function () {
            return {
                gardenbox: {}
            }
        },
        computed: {
            displaywidth: function() { return 600; },
            displayheight: function() { return this.displaywidth*(this.vegbed.length/this.vegbed.width); },
            margin: function() { return {top: 0, right: 0, bottom: 0, left: 0}; }
        },
        methods: {
            initalizeChart: function () {
                this.drawGardenBox();
            },

            virtDia: function (realDia) {
                return (this.displaywidth/this.vegbed.width)*realDia;
            },
            
            clickPlant: function() {
                d3.selectAll(".selected").raise().classed("selected",false);
                d3.select(_this).selectAll(".plant").raise().classed("selected", true);
                d3.selectAll("#"+this.id).classed("selected", true);      
            },
            clickBG: function() {
                console.log("click");
                d3.selectAll(".selected").raise().classed("selected",false);
            },
            
            draggedPlant: function(d) {
                d3.select(this).attr("transform","translate("+(d.x = d3.event.x)+","+(d.y = d3.event.y)+")");
            },
            
            dragStartedPlant: function() {
                d3.selectAll(".selected").raise().classed("selected",false);
                d3.select(this).selectAll(".plant").raise().classed("selected", true);
                d3.selectAll("#"+this.id).classed("selected", true);

                //d3.event.sourceEvent.stopPropagation();
            },    
            dragEndedPlant: function(d) {
                
            },
            refreshBed: function () {
                let _this = this; // Workaround to call functions from inside callbacks
                var gplant = this.gardenbox.selectAll("g")
                    .data(this.data).enter().append("g")
                    .attr("id", function(d){ return d.id; })
                    .attr("transform", function(d){ return "translate("+d.x+","+d.y+")";  })
                    .on("click", this.clickPlant)
                    //.attr("v-on:click","this.clickPlant")
                    .call(d3.drag()
                    .on("start", this.draggedPlant)
                    .on("drag", this.dragStartedPlant)
                    .on("end", this.dragEndedPlant));

                gplant.append("circle") // max size
                    .attr('class', 'plant')
                    .attr("cx", function(d) { return d.x; })
                    .attr("cy", function(d) { return d.y; })
                    .attr("r", function(d) { return _this.virtDia(d.plant.adult_diameter); });

                gplant.append("circle") // min size
                    .attr('class', 'plant')
                    .attr("cx", function(d) { return d.x; })
                    .attr("cy", function(d) { return d.y; })
                    .attr("r", function(d) { return _this.virtDia(d.plant.exposure_diameter); });

                gplant.append("image")
                    .attr('class', 'plant')
                    .attr("xlink:href", function(d) { return d.picref; })
                    .attr("x", function(d) { return d.x-(d.picsize/2); })
                    .attr("y", function(d) { return d.y-(d.picsize/2); })
                    .attr("width", function(d) { return d.picsize; })
                    .attr("height", function(d) { return d.picsize; });
            },
            
            drawGardenBox: function () {
                this.gardenbox = d3.select('#vegbedcontainer').append('svg')
                        .attr("width", this.displaywidth + this.margin.left + this.margin.right)
                        .attr("height", this.displayheight + this.margin.top + this.margin.bottom)
                // hintergrund für deselect zeichen
                var bg = this.gardenbox.append("g")
                        //.attr("v-on:click","clickBG");
                        .on("click", this.clickBG); // unselect on background click

                bg.append("rect") 
                    .attr('class', 'bg')
                    .attr("x", this.margin.left)
                    .attr("y", this.margin.top)
                    .attr("width", this.displaywidth + this.margin.left + this.margin.right)
                    .attr("height", this.displayheight + this.margin.top + this.margin.bottom)
            }
        },


        // lifecycle events
        mounted: function () { // <-- lifecycle events
            console.log('VegBedEditor mounted.')
            this.initalizeChart();
            this.refreshBed();
        },
        // watch functions
        watch: { // <-- watch functions
            'data': {
                handler: function (val) {
                    this.refreshBed();
                },
                deep: true
            }
        },
        template: `<div id="vegbedcontainer"><!-- SVG goes here --></div>`
    }

最佳答案

这是在我的 Vue 应用程序中运行的一些实验的结果。

在 svg 背景上设置点击处理程序

drawGardenBox: function () {
  this.gardenbox = d3.select('#vegbedcontainer').append('svg')
    .attr("width", this.displaywidth + this.margin.left + this.margin.right)
    .attr("height", this.displayheight + this.margin.top + this.margin.bottom)

  var bg = d3.select('svg')
    .on("click", this.clickBG); // unselect on background click

停止来自其他处理程序的点击传播

clickPlant: function() {
  d3.selectAll(".selected").raise().classed("selected",false);
  d3.select(_this).selectAll(".plant").raise().classed("selected", true);
  d3.selectAll("#"+this.id).classed("selected", true); 
  d3.event.stopPropagation(); 
},

设置 d3.event

我只导入了 d3 库的选定部分,包括 event,但最初 d3.event.stopPropagation() 失败了,因为 d3.event 为空。

感谢这个问题importing d3.event into a custom build using rollup ,我更改了 event 导入,它现在可以工作了

import { select, selectAll, event, customEvent } from 'd3-selection'
import { zoom } from 'd3-zoom'
import { tree, hierarchy } from 'd3-hierarchy'

export const d3 = {
  select,
  selectAll,
  tree,
  hierarchy,
  zoom,
  // event,
  get event() { return event; },
  customEvent
}

关于javascript - vue 组件中的 d3.js - 如何将鼠标事件挂接到元素?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53715028/

相关文章:

javascript - 查看 dom 元素在哪里被 javascript 清空

javascript - 网络包 : How to convert variables on build

javascript - 当 Vue 路由器放置在文件夹中时,它不会找不到模块

javascript - simpleGrid 是否需要额外下载?

javascript - JavaScript 中的递归异步函数

javascript - 将公式存储在表中并在 JavaScript/PHP 函数中使用该公式

javascript - [Vue警告] : Missing required prop

angularjs - nvd3 图表开始在浏览器中被压扁

javascript - 如何使用 JQuery 在 d3 中返回国家代码?

javascript - 递归循环包装?