{"id":24815470,"url":"https://github.com/zaboco/elm-draggable","last_synced_at":"2025-06-10T21:33:06.192Z","repository":{"id":54878725,"uuid":"73212687","full_name":"zaboco/elm-draggable","owner":"zaboco","description":"An easy way to make DOM elements draggable","archived":false,"fork":false,"pushed_at":"2021-01-22T12:28:59.000Z","size":546,"stargazers_count":65,"open_issues_count":1,"forks_count":16,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-06T14:43:24.772Z","etag":null,"topics":["dragging","elm"],"latest_commit_sha":null,"homepage":"http://package.elm-lang.org/packages/zaboco/elm-draggable/latest","language":"Elm","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zaboco.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-11-08T17:59:35.000Z","updated_at":"2024-10-04T21:22:46.000Z","dependencies_parsed_at":"2022-08-14T05:30:59.314Z","dependency_job_id":null,"html_url":"https://github.com/zaboco/elm-draggable","commit_stats":null,"previous_names":[],"tags_count":22,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zaboco%2Felm-draggable","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zaboco%2Felm-draggable/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zaboco%2Felm-draggable/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zaboco%2Felm-draggable/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zaboco","download_url":"https://codeload.github.com/zaboco/elm-draggable/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zaboco%2Felm-draggable/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259154571,"owners_count":22813631,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dragging","elm"],"created_at":"2025-01-30T16:29:09.127Z","updated_at":"2025-06-10T21:33:06.128Z","avatar_url":"https://github.com/zaboco.png","language":"Elm","funding_links":[],"categories":[],"sub_categories":[],"readme":"# elm-draggable\nAn easy way to make DOM elements draggable\n\n[![elm version](https://img.shields.io/badge/elm-v0.19-blue.svg?style=flat-square)](http://elm-lang.org)\n[![Build Status](https://travis-ci.org/zaboco/elm-draggable.svg?branch=master)](https://travis-ci.org/zaboco/elm-draggable)\n\n## Install\nHave [elm installed](https://guide.elm-lang.org/install.html).\n\n```sh\nelm install zaboco/elm-draggable\n```\n\n## Live examples\n- [Basic](https://zaboco.github.io/elm-draggable/basic.html) / [Code](https://github.com/zaboco/elm-draggable/blob/master/examples/BasicExample.elm)\n- [Custom events](https://zaboco.github.io/elm-draggable/custom.html) / [Code](https://github.com/zaboco/elm-draggable/blob/master/examples/CustomEventsExample.elm)\n- [Constraints - restrict dragging to one axis at a time](https://zaboco.github.io/elm-draggable/constraints.html) / [Code](https://github.com/zaboco/elm-draggable/blob/master/examples/ConstraintsExample.elm)\n- [Pan \u0026 Zoom - drag to pan \u0026 scroll to zoom](https://zaboco.github.io/elm-draggable/pan-and-zoom.html) / [Code](https://github.com/zaboco/elm-draggable/blob/master/examples/PanAndZoomExample.elm)\n- [Multiple Targets](https://zaboco.github.io/elm-draggable/multiple.html) / [Code](https://github.com/zaboco/elm-draggable/blob/master/examples/MultipleTargetsExample.elm)\n\n## Usage\n\nThis library is meant to be easy to use, by keeping its internal details hidden and only communicating to the parent application by emitting [`Event` messages](http://faq.elm-community.org/#how-do-i-generate-a-new-message-as-a-command). So, each time the internals change and something relevant happens (such as \"started dragging\", \"dragged at\", etc.), a new message is sent as a `Cmd` and handled in the main `update` function. To better understand how this works, see the snippets below and also the [working examples](https://github.com/zaboco/elm-draggable/blob/master/examples/).\n\n### Basic\n\nIn order to make a DOM element draggable, you'll need to:\n\n#### 1. Import this library\n```elm\nimport Draggable\n```\n\n#### 2. Define your model\nInclude:\n- The element's position.\n- The internal `Drag` state. Note that, for simplicity, the model entry holding this state **must** be called `drag`, since the update function below follows this naming convention. A future update could allow using custom field names. Please note that for the sake of example, we are specifying `String` as the type to tag draggable elements with. If you have only one such element, `()` might be a better type.\n```elm\ntype alias Model =\n    { position : ( Int, Int )\n    , drag : Draggable.State String\n    }\n```\n\n#### 3. Initialize the `Drag` state and the element's position\n```elm\ninitModel : Model\ninitModel =\n    { position = ( 0, 0 )\n    , drag = Draggable.init\n    }\n```\n\n#### 4. Define the message types that will be handled by your application\n- `OnDragBy` is for actually updating the position, taking a `Draggable.Delta` as an argument. `Delta` is just an alias for a tuple of `(Float, Float)` and it represents the distance between two consecutive drag points.\n- `DragMsg` is for handling internal `Drag` state updates.\n```elm\ntype Msg\n    = OnDragBy Draggable.Delta\n    | DragMsg (Draggable.Msg String)\n```\n\n#### 5. Setup the config used when updating the `Drag` state\nFor the simplest case, you only have to provide a handler for `onDragBy`:\n```elm\ndragConfig : Draggable.Config String Msg\ndragConfig =\n    Draggable.basicConfig OnDragBy\n```\n\n#### 6. Your update function must handle the messages declared above\n- For `OnDragBy`, which will be emitted when the user drags the element, the new position will be computed using the `Delta` `(dx, dy)`\n- `DragMsg` will be forwarded to `Draggable.update` which takes care of both updating the `Drag` state and sending the appropriate event commands. In order to do that, it receives the `dragConfig`. As mentioned above, this function assumes that the model has a `drag` field holding the internal `Drag` state.\n```elm\nupdate : Msg -\u003e Model -\u003e ( Model, Cmd Msg )\nupdate msg ({ position } as model) =\n    case msg of\n        OnDragBy ( dx, dy ) -\u003e\n            let\n                ( x, y ) =\n                    position\n            in\n                ( { model | position = ( round (toFloat x + dx), round (toFloat y + dy) ) }, Cmd.none )\n\n        DragMsg dragMsg -\u003e\n            Draggable.update dragConfig dragMsg model\n```\n\n#### 7. In order to keep track of the mouse events, you must include the relevant subscriptions\n```elm\nsubscriptions : Model -\u003e Sub Msg\nsubscriptions { drag } =\n    Draggable.subscriptions DragMsg drag\n```\n\n#### 8. Triggering drag\nInside your `view` function, you must somehow make the element draggable. You do that by adding a trigger for the `mousedown` event. You must also specify a `key` for that element. This can be useful when there are multiple drag targets in the same view.\n\nOf course, you'll also have to style your DOM element such that it reflects its moving position (with `top: x; left: y` or [`transform: translate`](http://www.w3schools.com/css/css3_2dtransforms.asp))\n```elm\nview : Model -\u003e Html Msg\nview { position } =\n    Html.div\n        [ Draggable.mouseTrigger \"my-element\" DragMsg\n        -- , Html.Attributes.style (someStyleThatSetsPosition position)\n        ]\n        [ Html.text \"Drag me\" ]\n```\n\nFor working demos, see the [basic example](https://github.com/zaboco/elm-draggable/blob/master/examples/BasicExample.elm) or the [examples with multiple targets](https://github.com/zaboco/elm-draggable/blob/master/examples/MultipleTargetsExample.elm)\n\n#### 9. Triggering on touch\nIf you want to trigger drags on touch events (i.e. on mobile platforms) as well\nas mouse events, you need to add `touchTriggers` to your elements. Building on\nthe previous example, it looks like this.\n\n```elm\nview : Model -\u003e Html Msg\nview { position } =\n    Html.div\n        [ Draggable.mouseTrigger \"my-element\" DragMsg\n        -- , Html.Attributes.style (someStyleThatSetsPosition position)\n        ] ++ (Draggable.touchTriggers \"my-element\" DragMsg)\n        [ Html.text \"Drag me\" ]\n```\n\nThe\n[basic example](https://github.com/zaboco/elm-draggable/blob/master/examples/BasicExample.elm) demonstrates\nthis as well.\n\n### Advanced\n\n#### Custom config\nBesides tracking the mouse moves, this library can also track all the other associated events related to dragging. But, before enumerating these events, it's import to note that an element is not considered to be dragging if the mouse was simply clicked (without moving). That allows tracking both `click` and `drag` events:\n- \"mouse down\" + \"mouse up\" = \"click\"\n- \"mouse down\" + \"mouse moves\" + \"mouse up\" = \"drag\"\n\nSo, the mouse events are:\n- `onMouseDown` - on mouse press.\n- `onDragStart` - on the first mouse move after pressing.\n- `onDragBy` - on every mouse move.\n- `onDragEnd` - on releasing the mouse after dragging.\n- `onClick` - on releasing the mouse without dragging.\n\nAll of these events are optional, and can be provided to `Draggable.customConfig` using an API similar to the one used by `VirtualDom.node` to specify the `Attribute`s. For example, if we want to handle all the events, we define the `config` like:\n```elm\nimport Draggable\nimport Draggable.Events exposing (onClick, onDragBy, onDragEnd, onDragStart, onMouseDown)\n\ndragConfig : Draggable.Config String Msg\ndragConfig =\n    Draggable.customConfig\n        [ onDragStart OnDragStart\n        , onDragEnd OnDragEnd\n        , onDragBy OnDragBy\n        , onClick CountClick\n        , onMouseDown (SetClicked True)\n        ]\n```\n\n__Note__: If we need to handle `mouseup` after either a `drag` or a `click`, we can use the `DOM` event handler `onMouseUp` from `Html.Events` or `Svg.Events`.\n\nSee [the full example](https://github.com/zaboco/elm-draggable/blob/master/examples/CustomEventsExample.elm)\n\n#### Custom Delta\nBy default, `OnDragBy` message will have a `Draggable.Delta` parameter, which, as we saw, is just an alias for `(Float, Float)`. However, there are situations when we would like some other data type for representing our `delta`.\n\nLuckily, that's pretty easy using function composition. For example, we can use a [Vec2](https://package.elm-lang.org/packages/elm-explorations/linear-algebra/1.0.3/Math-Vector2#Vec2) type from the `linear-algebra` library, which provides handy function like `translate`, `scale` and `negate`.\n\n```elm\nimport Math.Vector2 as Vector2 exposing (Vec2)\n\ntype Msg\n    = OnDragBy Vec2\n--  | ...\n\ndragConfig : Draggable.Config Msg\ndragConfig =\n    Draggable.basicConfig (OnDragBy \u003c\u003c (\\( dx, dy ) -\u003e Vector2.vec2 dx dy))\n```\n\nThere is actually [an example right for this use-case](https://github.com/zaboco/elm-draggable/blob/master/examples/PanAndZoomExample.elm)\n\n#### Custom mouse trigger\nThere are cases when we need some additional information (e.g. mouse offset) about the `mousedown` event which triggers the drag. For these cases, there is an advanced `customMouseTrigger` which also takes a JSON `Decoder` for the [`MouseEvent`](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent).\n\n```elm\nimport Json.Decode as Decode exposing (Decoder)\n\ntype Msg\n    = CustomMouseDown (Draggable.Msg ()) (Float, Float)\n--  | ...\n\nupdate msg model =\n    case msg of\n        CustomMouseDown dragMsg startPoint -\u003e\n            { model | startPoint = startPoint }\n                |\u003e Draggable.update dragConfig dragMsg\n\nview { scene } =\n    Svg.svg\n        [ Draggable.customMouseTrigger () mouseOffsetDecoder CustomMouseDown\n--      , ...\n        ]\n        []\n\nmouseOffsetDecoder : Decoder (Float, Float)\nmouseOffsetDecoder =\n    Decode.map2 (,)\n        (Decode.field \"offsetX\" Decode.float)\n        (Decode.field \"offsetY\" Decode.float)\n```\n[Full example](https://github.com/zaboco/elm-draggable/blob/master/examples/FreeDrawingExample.elm)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzaboco%2Felm-draggable","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzaboco%2Felm-draggable","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzaboco%2Felm-draggable/lists"}