Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vuejs #44

Open
kevindesousa opened this issue Aug 30, 2018 · 3 comments
Open

Vuejs #44

kevindesousa opened this issue Aug 30, 2018 · 3 comments

Comments

@kevindesousa
Copy link

How use with ES6 and VueJS ?

Importing
import * as d3 from 'd3'
import contextMenu from 'd3-context-menu'

Init
let d3ContextMenu = contextMenu(d3)

Config
.on('contextmenu', d3ContextMenu([ { title: 'Item #1', action: (elm, d, i) => { console.log('Item #1 clicked!') console.log('The data for this circle is: ' + d) } }, { title: 'Item #2', action: (elm, d, i) => { console.log('You have clicked the second item!') console.log('The data for this circle is: ' + d) } } ]))

My graph work, but nothing on click, just the real right click of the browser...

@heliomsolivas
Copy link

Have you solved it? I'm with this issue too

@SamuelEarl
Copy link

SamuelEarl commented Dec 13, 2019

I am using D3 v5 and Vue.js and I could not get this plugin to work in my project. So I created a context menu using HTML and I love it! It is very easy to create with modern frameworks, like Vue, where you can control the component state easily. This is a sample of my Vue component:

<template>
  <div id="chart-component">
    <div id="context-menu" v-if="showContextMenu">
      <div><button class="menu-item" @click="method1('arg')">Option 1</button></div>
      <div><button class="menu-item" @click="method2('arg')">Option 2</button></div>
      <div><button class="menu-item" @click="method3('arg')">Option 3</button></div>
    </div>
    <div id="chart-container"></div>
  </div>
</template>

<script>
import * as d3 from "d3";

export default {
  data() {
    return {
      showContextMenu: false
    }
  },

  beforeDestroy() {
    const chartComponent = document.getElementById("chart-component");
    chartComponent.removeEventListener("contextmenu", this.setContextMenuCoords);
  },

  methods: {
    createChart() {
      const chartComponent = document.getElementById("chart-component");
      chartComponent.addEventListener("contextmenu", this.setContextMenuCoords);
      ...
      this.someGroup.append("rect")
        .attr("width", this.rect.width)
        .attr("height", this.rect.height)
        .on("contextmenu", function(d) {
          // Prevent the default context menu from appearing.
          d3.event.preventDefault();
          // Pass the data object (d) and the DOM element (this) to vm.contextMenu.
          vm.contextMenu(d, this);
        });

      // Hide the context menu when a user left-clicks anywhere outside of the context menu.
      // This will also reset and hide the context menus after a user clicks any option within the context menus.
      d3.select("body")
        .on("click", function() {
          vm.showContextMenu = false;
        });
    },

    contextMenu(d, domEl) {
      // Use d and domEl, if necessary.
      this.showContextMenu = true;
    },

    /**
     * NOTE: The D3 event listeners are fired before the addEventListener functions are fired. 
     * So the context-menu elements will exist in the DOM by the time this method is executed.
     */
    setContextMenuCoords(event) {
      event.preventDefault();

      const ctxMenu = document.getElementById("context-menu");
      // If the user right-clicked somewhere other than on rect element that was appended to someGroup, then the ctxMenu will not exist. The following conditional check is to prevent errors when the user right-clicks outside of the rect element.
      if (ctxMenu) {
        // Get the width and height of the current context menu with the window.getComputedStyle() method.
        const compStyles = window.getComputedStyle(ctxMenu);
        const menuWidth = parseInt(compStyles.width);
        const menuHeight = parseInt(compStyles.height);

        // Get the dimensions of the <svg> element.
        const baseSvgEl = document.getElementById("svg");
        const chartRightEdge = baseSvgEl.getBoundingClientRect().right;
        const chartBottomEdge = baseSvgEl.getBoundingClientRect().bottom;

        // Get the right-click coordinates. (NOTE: The right-click event is called "contextmenu".)
        const mousePosX = event.clientX;
        const mousePosY = event.clientY;

        // If the right-click coordinates are too close to the right edge of the chart, then shift the context menu to the left so it does not overflow to the right of the chart area.
        if ((mousePosX + menuWidth) < chartRightEdge) {
          ctxMenu.style.left = mousePosX + "px";
        }
        else {
          ctxMenu.style.left = mousePosX - menuWidth + "px";
        }
        // If the right-click coordinates are too close to the bottom edge of the chart, then shift the context menu up so it does not overflow below the chart area.
        if ((mousePosY + menuHeight) < chartBottomEdge) {
          ctxMenu.style.top = mousePosY + "px";
        }
        else {
          ctxMenu.style.top = mousePosY - menuHeight + "px";
        }
      }
    },
  }
};
</script>

<style lang="stylus" scoped>
  #context-menu {
    position: absolute;
    width: 200px;
    background-color: white;
    z-index: 100;
    border: 1px solid rgba(0, 0, 0, 0.3);;
    box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4);

    .menu-item {
      width: 100%;
      padding: 10px;
      text-align: left;
      background-color: inherit;
      &:hover {
        background-color: lighten(steelblue, 50%);
      }
    }
  }
</style>

I didn't define all of the properties in the Vue data option, but if you are familiar with Vue and D3 then that shouldn't matter.

You basically create a context menu from plain HTML and show or hide it using D3 events. You also attach an event listener onto the component that listens for the "contextmenu" event. When a user right-clicks anywhere on the component, you handle that event with the setContextMenuCoords method, which sets the top and left position properties of the context menu. The comments in the code above should help to clarify.

I hope that helps. Good luck!

@DineshKarri443
Copy link

@SamuelEarl I am trying to implement a context-menu from your solution above, one issue with this solution is when I right click on a node the contextmenu comes up fine, but when I right-click again immediately on an empty area ( where there are no nodes ), the context menu still comes up. It's only when we do a left click that the context-menu goes away.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants