The d3 drag functionality is only active when the axis ticks are selected

Currently, I am developing a unique package that combines Angular and D3 (v3) and my main focus is on integrating D3's dragging feature into the package. Although I am very close to achieving success, there is a minor bug that I need to address. When the plots are initially rendered, the elements (specifically rectangles) cannot be dragged unless the text on the x-axis is selected using the cursor. Once the text is highlighted, the dragging functionality works perfectly. However, fixing this initial bug is crucial for the overall user experience.

To better illustrate the issue, you can find a demonstration in a Github.io project here. The dragging behavior from D3 is defined in the ivml library version 0.0.0 (included in the repository) within lines 903-966, which I have included below:

    if (Bars.events.dragE) {

        // Note: xs(0) refers to pixel value at 0 on the x-scale. Must be reset for generalizability

        // function returns width (in pixels) of bar. Used to ensure drag doesn't exceed plot area

        function returnw(d, i){
            if (values_function(d, i) <= 0) {
                Bars.elements.barController.offset(position_function(d, i), xs(0) - xs(values_function(d, i)), values_function(d, i));
                return xs(0) - xs(values_function(d, i));
            }
            else {
                Bars.elements.barController.offset(position_function(d, i), xs(values_function(d, i)) - xs(0), values_function(d, i))
                return Math.abs(xs(0)-xs(values_function(d, i)))
            }
        }

        var drag = d3.behavior.drag()
        .on('dragstart', draginit)
        .on('drag', dragmove)
        .on('dragend', dragfin);

        function draginit(d){
            d3.event.sourceEvent.stopPropagation();
            // replace fill color with variable for user input function
            Bars.events.dragE(d, i, d3.select(this).attr('style', 'fill: yellow; stroke: black; stroke-width: 3px;'))
        }

        function dragmove(d){
            var svgwidth = Bars.elements.chartController.plotObject.attributes.width //margin of plotObject
            var svginterval = svgwidth/(Bars.elements.chartController.plotObject.attributes.xmax-Bars.elements.chartController.plotObject.attributes.xmin) //number of pixels between whole numbers in coordinate plot
            Bars.events.dragE(d, i, 
            d3.select(this)
                .attr("x", function(d, i){
                    if (d3.event.x < 0) {return 0}
                    else if (d3.event.x + returnw(d,i) > svgwidth){ return (svgwidth - returnw(d,i))}
                    else {return xs(Math.floor(d3.event.x/svginterval)) } }));

            var valuechange = d3.event.x < 0 ? 0 : (d3.event.x + returnw(d,i) > svgwidth ? svgwidth - returnw(d,i) : d3.event.x);

            console.log("Start value changed to: ", Math.floor(valuechange/svginterval));
        }

        function dragfin(d){
            Bars.events.dragE(d, i, d3.select(this).attr('style', 'stroke: black; stroke-width: 0px;')
            .attr('fill', Bars.attributes.fill))

        }


        rects.attr("cursor", "ew-resize")
        .on('dragstart', function(d, i){
            Bars.events.dragE(d, i, d3.select(this).call(drag))
        })
        .on('drag', function (d, i) {
            window.dragThis = this;
            Bars.events.dragE(d, i, 
                d3.select(this).call(drag)) 
        })
        .on("dragend", function(d, i){
            Bars.events.dragE(d, i, d3.select(this).call(drag))

        })
    }

As I continue to navigate through Angular, Javascript, and D3 functionalities, any advice or suggestions on resolving this slight setback would be immensely valuable!

Answer №1

I have developed a custom d3v5 code for implementing the drag behavior in bar graphs without any prior selection requirement. I recommend bypassing the D3-Angular integration and directly coding the graph using D3v5 by invoking a function that generates the graph based on the provided dataset.

The data used in the original bar chart utilized the frequency field as the bar value.

<!DOCTYPE html>
<!-- modified from the bar chart example at https://bl.ocks.org/mbostock/3885304 -->
<meta charset="utf-8">
<style>
.active {
  stroke: #000;
  stroke-width: 2px;
}
.axis--y path {
  display: none;
}
</style>
<svg width="960" height="500"></svg>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>

var svg = d3.select("svg"),
    margin = {top: 20, right: 20, bottom: 30, left: 40},
    width = +svg.attr("width") - margin.left - margin.right,
    height = +svg.attr("height") - margin.top - margin.bottom;

var x = d3.scaleLinear().rangeRound([0, width]),
    y = d3.scaleBand().rangeRound([height, 0]).paddingInner(0.1);

var g = svg.append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

var data = [
    {letter: 'A', x: 0, frequency: 1 },
    {letter: 'B', x: 0, frequency: 13 },
    {letter: 'C', x: 0, frequency: 6 },
    {letter: 'D', x: 0, frequency: 2 },
    {letter: 'E', x: 0, frequency: 5 },
    {letter: 'F', x: 0, frequency: 9 }
];

var colorFx = function(d, i){
                  var colors = ['blue', 'green', 'yellow', 'purple', 'orange'];
                  return colors[Math.floor(Math.random()*colors.length)];
              };

  x.domain([0, 7 + d3.max(data, function(d) { return d.frequency; })]);
  y.domain(data.map(function(d) { return d.letter; }));


  g.append("g")
      .attr("class", "axis axis--x")
      .attr("transform", "translate(0," + height + ")")
      .call(d3.axisBottom(x));

  g.append("g")
      .attr("class", "axis axis--y")
      .call(d3.axisLeft(y));

  g.selectAll(".bar")
    .data(data)
    .enter().append("rect")
      .attr("class", "bar")
      .attr("fill", colorFx)
      .attr("x", function(d) { return 0; })
      .attr("y", function(d) { return y(d.letter); })
      .attr("width", function(d) { return x(d.frequency); } )
      .attr("height", y.bandwidth() )
    .call(d3.drag()
      .on("start", dragstarted)
      .on("drag", dragged)
      .on("end", dragended));

var prevDragPosition = { x: 0, y: 0};

function dragstarted(d) {
  prevDragPosition.x = d3.event.x;
  prevDragPosition.y = d3.event.y;
  d3.select(this).classed("active", true);
}

function dragged(d) {
  // calculating the movement offset required for the rectangle
  var deltaX = x.invert(d3.event.x) - x.invert(prevDragPosition.x);
  var node = d3.select(this);
  var dd = node.attr("x");
  var rectX = d.x + deltaX;
  // constraining x position within the specified domain limits
  rectX = Math.max(x.domain()[0], rectX);
  rectX = Math.min(x.domain()[1]-d.frequency, rectX);
  d.x = rectX;
  node.attr("x", x(rectX));
  prevDragPosition.x = d3.event.x;
  prevDragPosition.y = d3.event.y;
}

function dragended(d, i) {
  d3.select(this).classed("active", false);
}

</script>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Unable to locate element using document.getElementById in ASP.NET form

Currently, I am working on a project to create an ASP.NET webforms page that will showcase a Google map using the Google Maps JavaScript API with multiple markers. Everything is functioning smoothly as long as I don't place <div id="map-canvas"> ...

Creating a Composite of Several Boxes in THREE.js

My goal is to display multiple boxes together in a specific structure shown in the image I have attached. I am interested in testing the GPU limitations by increasing the number of boxes, and then later on, I will focus on optimization. The framework I am ...

Is the Expand All / Collapse All feature malfunctioning when used with a tree table?

I have been working on implementing the Expand All/Collapse All feature for a nested tree table, but unfortunately, I am not achieving the desired output. I referred to a related question on this topic which can be found here. You can also view the code on ...

How can I shift the button's location within a pop-up in Ionic 1?

enter image description here I am struggling to make the button green underneath the three other buttons. Can someone please assist me with this? Here is my code: $scope.showIntroductionPage = function(childs){ if(childs == 0){ var myPopup = $io ...

An AngularJS error has been caught: [$injector:modulerr]

After implementing AngularJS in my application, I encountered an error when adding a configuration section for routing: Uncaught Error: [$injector:modulerr] http://errors.angularjs.org/1.2.9/$injector/modulerr?p0=demoApp&p1=Error%3A…nts%2FGitHub%2FS ...

What is your strategy for managing errors when utilizing xui's xhr functionality?

Recently, I've been utilizing the code below to extract data from an external source. <script type="text/javascript"> xui.ready(function() { var url = 'http://www.domain.com/getData.aspx'; x$().xhr(url, ...

Sharing objects between parallel states in Angular

Is there a way to seamlessly transfer a selected user from the details view to an edit view for parallel editing? In the details view, I capture 'selectedUser' and then need to make edits in specific fields within the edit view. There are two p ...

When the horizontal scroll is turned off, it also disables the functionality of my mobile-friendly

I came across a helpful post on StackOverflow that suggested using the following code to disable horizontal scrolling: html, body { overflow-x: hidden; } This solution did resolve my issue of horizontal scrolling, but unfortunately it caused problems ...

Despite locating the button, Protractor still encounters difficulties when attempting to click on it

I've been having trouble clicking on a button using Protractor. The issue is that even though the driver can locate the element, it still won't click on it. Any assistance would be greatly appreciated. Thank you in advance. Here is the HTML for ...

Press the button in an HTML document to activate JavaScript

What could be the issue with my code? I have a button in HTML <a class="btn btn-warning btn-mini publish-btn" href="#" data-rowid="@computer.id" data-toggle="modal" data-target="#myModal">Outdated</a> and my modal <fieldset style="text-al ...

Is there a benefit to using middlewares instead of the standard built-in functions in Express.js?

Express.js offers a wide range of middlewares that replace built-in functions. One example is body-parser, which parses HTTP request bodies, replacing the built-in function express.bodyParser. body-parser replaces the built-in function express.bodyParse ...

Is it the browser's responsibility to convert ES6 to ES5 internally?

Given the support for ES6 in modern browsers, do they internally convert ES6 to ES5 before executing the code? Or can they process ES6 natively using a C++ engine? If they are able to run ES6 directly, how do they guarantee that executing ES6 code produce ...

Is there a way to extract the text that lies between two closed HTML

Looking for a solution using jQuery. <pre><marker id="markerStart"></marker> aaaaa <span style='font-family:monospace;background-color:#a0a0a0;'>bbb</span>bb cc<marker id="markerEnd"></marker>ccc </pr ...

Styling with CSS and JavaScript: The ultimate method for desaturating multiple images

I am currently designing a portfolio website that will feature desaturated thumbnails of all my work. When you hover over each thumbnail, the color will fade in and out upon mouseover. Since this page will include numerous thumbnails, I have been contempl ...

Background of jQuery-UI Slider

Can the background color of a jQuery-UI Slider widget be set using JavaScript? This is the default setting: What I am trying to accomplish is the following: The green range should be determined based on historical data. I want to visually show the user ...

Issue with Vue 2 emitting events and not properly executing associated method, despite correct setup

I am attempting to trigger an event from a child Vue component to its parent using this.$emit('collapsemenu'). However, when I try to capture this event in the parent using v-on:collapsemenu="collapseMenuf($event)", nothing seems to ha ...

Unleashing the power of jQuery ajax without requiring a server

I've been incorporating jQuery ajax calls on my HTML pages. $.ajax({ url: 'search/' + page + '.html', dataType: 'text', success: function(data) { $(".searchData").html(data); $(".searchData"). ...

Routing WebSocket connections with Node.js

Currently, I am in the process of developing a chat application for my company which will run on node js with websocket (ws). The app is designed to cater to various departments within the organization, each with its own set of users. My goal is to ensure ...

Using the Trigger Method in a Vue JS Component with Sibling Components

Seeking assistance once again for a VueJS2 project. Currently, I have a setup with a parent component, along with child1 and child2. The scenario is that the form in child1 needs to receive data from child2, which acts as a table. When a checkbox on a row ...

display the fieldset based on selected dropdown option

In my form, I have 5 different products with attributes. I want to display only one product field-set when the user selects from a dropdown menu and increments. $scope.choices = [{id:'choice1'},{id:'choice1'},]; //Function to add a ne ...