惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
V
Visual Studio Blog
IT之家
IT之家
博客园 - 聂微东
The Cloudflare Blog
月光博客
月光博客
阮一峰的网络日志
阮一峰的网络日志
S
SegmentFault 最新的问题
Apple Machine Learning Research
Apple Machine Learning Research
酷 壳 – CoolShell
酷 壳 – CoolShell
爱范儿
爱范儿
H
Help Net Security
博客园 - 叶小钗
V
V2EX
WordPress大学
WordPress大学
J
Java Code Geeks
Hugging Face - Blog
Hugging Face - Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园_首页
C
Check Point Blog
B
Blog
D
DataBreaches.Net
美团技术团队
罗磊的独立博客

Red Blob Games: latest blog posts

Red Blob Games: Differential heuristics Red Blob Games: Responsive design calculator Red Blob Games: Academic citations Red Blob Games: Highlighting interactive code blocks Red Blob Games: Optimizing page size Red Blob Games: Writing a guide to SDF fonts Red Blob Games: URLs with trailing punctuation Red Blob Games: What I did in 2025 Red Blob Games: Goodbye Sass Goodbye Sass Red Blob Games: RotMG map seeds Red Blob Games: Mapgen4 Mapgen4's use of WebGL2 Red Blob Games: Mapgen4 river shader Red Blob Games: Mapgen4 renderer Red Blob Games: Harnessing ChatGPT hallucinations Red Blob Games: Let Let's write a search engine, part 2 of 2 Red Blob Games: Let Let's write a search engine, part 1 of 2 Red Blob Games: Hexagon conversions Red Blob Games: Mapgen4 trade routes Red Blob Games: De-optimizing mapgen4 Red Blob Games: Hexagon spiral coordinates Red Blob Games: Thoughts on Flash Red Blob Games: What I did in 2024 Red Blob Games: Hexagon page animations Red Blob Games: SDF Halos SDF Halos Red Blob Games: SDF headless tests, part 2
Red Blob Games: Draggable examples
2024-04-18 · via Red Blob Games: latest blog posts
Blog post: 17 Apr 2024

On my pages I often want to be able to move an object around in a diagram using the mouse or touch. Last year I spent some time learning about browser mouse+touch events, and wrote a page about event handlers for dragging objects around. I hadn’t realized it at the time, but it was only half the solution.

Event handlers and state handlers

What was missing was that the events should affect the application state. I had been writing this code for many years, but I never explained it on the event handler page. I decided to write some examples, starting with: drag events should change application state {x,y} which should change the position of an object on the screen, either using positioning or transforms:

  1. svg <​circle cx="$x" cy="$y" />
  2. svg <​circle transform="translate($x,$y)" />
  3. html <​div style="position:absolute; left: $x; top: $y" />
  4. html <​div style="transform: translate($x,$y)" />

The main idea is that the event handlers are independent of the state handlers. The event handlers do not know whether I’m using position:absolute or transform:translate(). The event handlers do not apply snap-to-grid or constraints, like they do in other libraries like jquery-ui-draggable or react-draggable. Instead, the state handler handles those things. That means the same event handlers can be used for a wide variety of dragging behaviors, including non-rectangular constraints and non-grid snapping. The event handlers can work for both svg and html. This structure gives me the flexibility I wanted for my projects. I made some examples to show that this separation allows the kinds of common features other libraries have:

  1. Constrained drag (could be a rectangle, but could be any shape)
  2. Snap to nearest point (could be a grid, but could be anything)
  3. Drag with a handle (could be a rectangle, but could be anything)

The state handlers do not know whether I’m capturing mouse or touch or pointer events. Only the event handlers handle those things. That means the state handlers can also be connected to other systems, such as animation libraries or text input boxes or scripts.

Constrained drag with snapping

The second idea I wanted to show on this page is that the same event handlers can be used when not dragging an object, so I made some examples:

  1. “Scrub” a number input left and right to change it
  2. Draw on a canvas
  3. Draw on an svg grid
  4. Drag a circle drawn inside a canvas, even though no DOM object is being dragged
  5. Move and resize a rectangle using nested drag handlers
Drawing on a canvas

I thought making these examples would take a week or two, but I ended up spending a lot more time on it. I made a code viewer that showed the event and state handlers for each example. I made a custom highlighter that highlighted lines of code to pay attention to. I made a code generator that partially generated the example code, then ran it. I considered making the examples editable, but decided to instead link to live editable editables on jsfiddle and codepen.

Displaying the code powering an example

Taking longer than a week was ok. Some of my projects are timeboxed[1], and I give myself a week to work on them. I typically use timeboxing when I’m learning something. But this page isn’t one of those. It’s a reference page that I’m willing to spend a lot more time on. I’ll come back to it as I learn more or better ways of doing things. I probably spent 4 weeks on this.

One thing I had wondered about was: why isn’t this a library? I had presented it as a recipe, something to be copied and modified for each situation. But it could’ve been a library, right? But in making these examples I got to see that my own uses are so varied that a library would be overly complicated. The event handlers and state handlers are not fully independent, like I had thought they would/should be. So for now I’ll leave it as a recipe, and revisit it later.

Take a look at the examples and feel free to copy them and use them in your own projects!