Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
chaco / tools / data_label_tool.py
Size: Mime:
# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX
# All rights reserved.
#
# This software is provided without warranty under the terms of the BSD
# license included in LICENSE.txt and may be redistributed only under
# the conditions described in the aforementioned license. The license
# is also available online at http://www.enthought.com/licenses/BSD.txt
#
# Thanks for using Enthought open source!

""" Defines the DataLabelTool class.
"""
# Major library imports
from numpy import array, asarray, argmin, sqrt

# Enthought library imports
from traits.api import Any, Bool, Enum
from enable.tools.api import DragTool


class DataLabelTool(DragTool):
    """A tool for dragging a data label.

    Attach this tool to a DataLabel object by setting the tool's **component**
    to the DataLabel.
    """

    #: The mouse button that initiates the drag.
    drag_button = Enum("left", "right")

    #: Use the root of the label's arrow (if any) as the closest corner of the
    #: label?
    auto_arrow_root = Bool(True)

    # The original position of the label with respect to the data point.
    _original_offset = Any

    # This is used in the auto_arrow_root = 'corners' case.
    _corner_names = (
        "bottom left",
        "bottom right",
        "top right",
        "top left",
        "top center",
        "bottom center",
        "left center",
        "right center",
    )

    def is_draggable(self, x, y):
        """Returns whether the (x,y) position is in a region that is OK to
        drag.

        Overrides DragTool.
        """
        if self.component:
            label = self.component
            return (
                x >= label.x
                and x <= label.x2
                and y >= label.y
                and y <= label.y2
            )
        else:
            return False

    def drag_start(self, event):
        """Called when the drag operation starts.

        Implements DragTool.
        """
        if self.component:
            label = self.component
            pointx, pointy = label.component.map_screen(label.data_point)
            self._original_offset = (label.x - pointx, label.y - pointy)
            event.window.set_mouse_owner(self, event.net_transform())
            event.handled = True

    def dragging(self, event):
        """This method is called for every mouse_move event that the tool
        receives while the user is dragging the mouse.

        Implements DragTool. Moves and redraws the label.
        """
        if self.component:
            label = self.component
            dx = int(event.x - self.mouse_down_position[0])
            dy = int(event.y - self.mouse_down_position[1])

            label.label_position = (
                self._original_offset[0] + dx,
                self._original_offset[1] + dy,
            )

            if self.auto_arrow_root:
                # Determine which corner is closest to the point
                p = asarray(label.component.map_screen(label.data_point))
                x, y = label.position
                x2 = label.x2
                y2 = label.y2
                xmid = (x + x2) / 2
                ymid = (y + y2) / 2
                anchors = array(
                    (
                        (x, y),
                        (x2, y),
                        (x2, y2),
                        (x, y2),
                        (xmid, y2),
                        (xmid, y),
                        (x, ymid),
                        (x2, ymid),
                    )
                )
                diff = anchors - p
                closest = argmin((diff ** 2).sum(axis=-1))
                label.arrow_root = self._corner_names[closest]

            event.handled = True
            label.request_redraw()

    def drag_end(self, event):
        """Called when a mouse event causes the drag operation to end.

        Implements DragTool.
        """
        if self.component:
            if event.window.mouse_owner == self:
                event.window.set_mouse_owner(None)
            event.handled = True
            self.component.request_redraw()