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

推荐订阅源

Martin Fowler
Martin Fowler
Y
Y Combinator Blog
M
MIT News - Artificial intelligence
The Cloudflare Blog
WordPress大学
WordPress大学
H
Hackread – Cybersecurity News, Data Breaches, AI and More
博客园 - 司徒正美
小众软件
小众软件
Blog — PlanetScale
Blog — PlanetScale
雷峰网
雷峰网
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
J
Java Code Geeks
云风的 BLOG
云风的 BLOG
C
Check Point Blog
D
DataBreaches.Net
T
The Blog of Author Tim Ferriss
V
V2EX
F
Fortinet All Blogs
B
Blog
大猫的无限游戏
大猫的无限游戏
N
Netflix TechBlog - Medium
B
Blog RSS Feed
A
About on SuperTechFans
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC

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!