图示
DiagramMinimap - 缩略图
在一个比窗口更大的东西里,你现在在哪。
用法
什么时候用它
来自@misoto22/folio/diagrams
import { DiagramMinimap } from '@misoto22/folio/diagrams'说明
在一个比窗口更大的东西里,你现在在哪。
同时是两样东西,而且两样都必须有:整张图形的一个缩影,以及一个矩形,标出框此刻正盖在它的哪一部分上。光有缩影回答的是「那里有什么」;矩形回答的是「那我在哪」——后者才是一个刚平移过两次的读者真正的问题。
矩形是推导出来的,从不另存。它的位置来自画布自己的 view——就是画布正在用来做变换的那三个数——除以地图的缩放比,再夹进那块板子里:一个已经平移到图形边缘之外的视口,有一半是压在空白纸上的,把矩形画到那外面去,等于声称这张地图延伸到了它并没有延伸到的地方。另存一份「视口在哪」,正是一张缩略图开始和它所映照的东西对不上的方式;而一张对不上的地图,比没有地图更糟。
在图形有尺寸之前,什么都不画。content 通常是量出来的,而一次测量的第一个值是零——那样缩放比会是 1,缩影会变成图形左上角那一块的原尺寸,矩形盖在它上面什么也不意味着。空着一帧,才是「还没到」的老实版本。
点击是重新居中,不是跳转。onSeek 报出的是内容坐标系里的一个点,那正是画布 centerOn 接受的东西。缩略图自己不移动任何东西:它对视图没有权柄,它只说读者指了哪儿。拖动会一直寻位,而且只有起点落在地图上的拖动才算——一个在别处按下、再拖过来的按键,不是这个组件该回答的手势。
结构
| 部件 | 说明 |
|---|---|
| 地图框必填 | 一块定宽的底——width 没另说就是 200px——高度跟着画面自己的宽高比走,并以 group 的身份命名,免得它成为图旁边一个没有标签的盒子。 |
| 缩影必填 | children,套上一层 width 除以 content.width 的 CSS scale,锚在左上角,对辅助技术隐藏,对指针透明。只有 content 有了尺寸才画——宽度为 0 时缩放比会是 1,缩影就成了画面左上角那块原尺寸的部分。它只回答一眼扫过去「那里有什么」,别的什么都不回答。 |
| 视口矩形必填 | 一个带 accent 底色的矩形,由画布的 view 和地图的缩放比算出来,裁在这块底之内——所以一个平移到画面之外的视口,不会再声称地图还往更远处延伸——并设了几个像素的下限,这样深度放大时屏幕上仍然剩得下点东西可看。它每次渲染都重新推导,从不另存一份。 |
| 定位层 | 盖在地图上的那层透明的东西,把一次按下、或者一次起点就落在它身上的拖动,换算成内容坐标系里的一个点,交给 onSeek。在别处按下、再拖过它的按键,什么也不会移动。地图自己也一样——它对视图没有任何话语权。 |
实践建议
推荐
- 喂给它画布自己的 onViewChange。那个矩形就是这三个数字的算术,所以这样接起来的地图不可能和它所映照的那个框对不上——而另存一份「视口在哪」的副本,恰恰就是对不上的由来。
- content 要按画面天然的 CSS 尺寸量。这里的一切都是按 width 除以 content.width 缩放的,所以一个错的 content 宽度,会把缩影和矩形按同一个错误的系数一起缩放:地图看起来照样合理,指的却是画面上错误的那一块。宽度为 0 则改画一块空底,而一次还没落地的测量,本来就该长这个样子。
- 框有多大,交给画布来说。DiagramCanvas 发出的每一个 view 都带着它当时量出来的那个框,所以把 onViewChange 透传过去就够了——frame 这个属性是留给这个组件无从得知的框的,而一个手写的框,正是让那个矩形开始说谎的唯一一个数。
- onSeek 直接接到画布句柄的 centerOn 上。那个点送来时就在内容坐标系里,而 centerOn 本来接收的就是这个空间,所以重新居中不需要你自己做任何换算。
避免
- 它只认指针,而且对辅助技术隐藏:没有 Tab 停靠点,没有按键,缩影也有意什么都不发布,因为它映照的那张图已经发布过了。要到远处的角落去,键盘的路径仍然是画布的方向键,所以缩略图绝不能是抵达某个角落的唯一途径。
- 缩影是同一份标记缩小后的样子,不是一张简化的画——每一个标签都跟着一起缩下去,所以一张宽图缩到 200px 就是一个形状,不是一份能读的副本。它回答你在哪;某个节点写了什么,那是图的活。
示例
default
只有当框比画作更小时,一张地图才值得画出来,所以 frame 承载的是画布自己以 CSS 像素计的盒子,content 承载的是图形的自然尺寸。那个矩形是每次变化时从画布的 view 推导出来的、不是另存的,这正是为什么两者永远不会对不上。在地图上点击或拖动会报出画作坐标系里的一个点,而移动的动作由 centerOn 来做——缩略图对视图没有权柄,它只说读者指了哪儿。
5 elements and 4 relationships.
- Browser (external)
- CloudFront (cloud)
- API (backend)
- Postgres (database)
- SQS (messagebus)
- Browser → CloudFront
- CloudFront → API
- API → Postgres
- API → SQS
Drag to pan. Plus and minus zoom, zero resets, the arrow keys pan.
what the rectangle is
同一张地图的三份,除了 view 之外别无差异。那个矩形是拿那三个数算出来的——框左上角对应的内容点,是取负的偏移量除以缩放比,再换算到地图上——所以「视口在哪」没有第二份副本,也就没有什么需要同步。放大会让这个矩形变小、而不是移动,而这正是读者想要的那个读法:它说明的是他们此刻看到的是整体的多大一部分。这三个都没有传 onSeek,所以它们是读数而不是控件,指针也保持它平常的光标。
when a minimap earns its place
两种情形并排放着。左边,框是一扇窗,望着一个四倍于它面积的东西,所以那个矩形圈出了一部分,地图回答了「你在哪」;右边,框已经装下了整幅画作,矩形从边到边盖满了地图,而它的每一个像素说的都是读者本来就已经看见的那一件事。只在第一种情形下渲染缩略图——在第二种情形下,它是这张图的第二份绘制,花掉一次渲染,却什么也没告诉任何人。
无障碍
- 缩略图是 aria-hidden 的。它映照的那张图已经发布了自己的摘要,再来一份会把整张图念两遍。