one-screen-scale 1.0.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ligang <bpcnlg@163.com>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -6,9 +6,69 @@
6
6
 
7
7
  - 🎯 **真正的"一屏"** — 内容不溢出、不滚动(contain 模式)
8
8
  - 🧩 **零依赖核心** — 纯 JS,不绑定任何框架
9
- - ⚡ **指令 / Hook 开箱即用** — Vue 3 和 React 都支持
9
+ - ⚡ **指令 / Hook 开箱即用** — Vue 3 和 React 都支持;挂载时自动注入基础宽高样式
10
10
  - 🖥️ **Canvas 友好** — 通过反缩放补偿,ECharts 等 canvas 内容保持清晰
11
11
 
12
+ ## 主要面向场景
13
+
14
+ 面向已经用 **postcss-px-to-viewport**(或同类方案)做移动端适配的 H5 页面:
15
+
16
+ | 模式 | 用途 | 效果 |
17
+ |------|------|------|
18
+ | `contain`(默认) | 活动页 / 一屏落地页 | 任意设备完整展示一屏;高屏左右留白;极小视口仍能看到完整页;**PC 与手机看到的是同一张 H5** |
19
+ | `fixed-width` | 规则页 / 长表单 | 固定视觉宽度,内容可纵向滚动 |
20
+
21
+ 不必再单独开发一套 PC 页。
22
+
23
+ ## 页面怎么配合
24
+
25
+ 指令会**自动注入**下列基础样式(可用 `injectBaseStyles: false` 关闭):
26
+
27
+ **contain — 一屏**
28
+
29
+ ```css
30
+ width: 100vw;
31
+ min-height: 100vh;
32
+ min-height: 100dvh;
33
+ ```
34
+
35
+ 算法用元素的 `offsetWidth / offsetHeight` 和视口比:`scale = min(视口宽/内容宽, 视口高/内容高)`。
36
+ 所以 **内容高度必须能被正确量出来**,PC 上(px→vw 后)通常会高于视口,scale 才会小于 1。
37
+
38
+ ### ⚠️ contain 使用禁忌(否则 PC 看起来像「没缩放」)
39
+
40
+ 1. **禁止用 `height: 100vh` / `100dvh` 锁死根节点高度**
41
+ 只能用插件注入的 **`min-height`**。写成 `height: 100vh` 后,`offsetHeight ≈ 视口高` → `scaleY ≈ 1` → 整页几乎不缩。
42
+
43
+ 2. **禁止把撑高页面的大图 / 主视觉设为 `position: absolute`(或脱离文档流)**
44
+ 绝对定位不参与父级高度计算。常见错误:棋盘/海报 `position: absolute` + 外层 `flex: 1; min-height: 0` 去「填满一屏」→ 根节点高度仍被锁在视口上。
45
+ **正确做法:大图留在文档流里**(`position: relative` / 默认 static,`width: 100%; height: auto`),用图片自身比例撑开整页高度。
46
+
47
+ 3. **避免「整页 flex 填视口、子项 `flex:1; min-height:0`」当唯一高度来源**
48
+ 那会把布局收成刚好一屏,同样量不出「内容高于视口」。一屏裁切用 `overflow: hidden` 即可,高度仍交给内容。
49
+
50
+ **对照**
51
+
52
+ | 写法 | 结果 |
53
+ |------|------|
54
+ | `min-height: 100vh` + 大图在文档流 | ✅ PC/手机构图一致,contain 正常缩小 |
55
+ | `height: 100vh` 锁死 | ❌ PC scale≈1 |
56
+ | 大图 `absolute` + flex 填满视口 | ❌ 量不到真实内容高,PC 不缩 |
57
+
58
+ 图片异步加载导致偶发量矮:插件默认 `observeContent: true`,会在尺寸变化后自动 `refresh`。
59
+
60
+ **fixed-width — 长滚动**
61
+
62
+ 暂不自动注入基础 CSS;`width` / `height` 由 `refresh()` 行内补偿写入。业务自己管内部滚动等。
63
+ 滚动条被 scale 变细时,可用根节点上的 `--one-screen-inverse-scale` 做反缩放,例如:
64
+
65
+ ```css
66
+ /* 若项目用了 px-to-viewport,这里要用大写 Px,避免被转成 vw 后再 ×反缩放过粗 */
67
+ .scroll::-webkit-scrollbar {
68
+ width: calc(6Px * var(--one-screen-inverse-scale, 1));
69
+ }
70
+ ```
71
+
12
72
  ## 安装
13
73
 
14
74
  ```bash
@@ -21,6 +81,7 @@ npm install one-screen-scale
21
81
 
22
82
  ```vue
23
83
  <template>
84
+ <!-- 一屏:自动注入 min-height:100vh + width:100vw -->
24
85
  <div v-fit-screen class="page">
25
86
  <h1>活动标题</h1>
26
87
  <p>页面内容...</p>
@@ -32,24 +93,61 @@ import { vFitScreen } from 'one-screen-scale'
32
93
  </script>
33
94
  ```
34
95
 
35
- ### Vue 3 — Composable(需要 scale 值,如 ECharts 补偿)
96
+ ```vue
97
+ <template>
98
+ <!-- 长滚动 -->
99
+ <div v-fit-screen="{ mode: 'fixed-width' }" class="rules-page">
100
+ <header>...</header>
101
+ <main class="rules-body"><!-- overflow-y: auto --></main>
102
+ </div>
103
+ </template>
104
+ ```
105
+
106
+ ### Vue 3 — `v-compensate`(第三方组件反缩放)
107
+
108
+ 页面 `transform: scale` 后,ECharts 等常会尺寸偏小或量错。在槽位内再包一层即可(**JS 行内**写入):
109
+
110
+ `width/height: 100% * pageScale` + `transform: scale(inverse)`,scale 读祖先 `--one-screen-scale`。
36
111
 
37
112
  ```vue
38
113
  <template>
39
- <div ref="pageRef" class="page">
40
- <div :style="{ transform: `scale(${inverseScale})` }">
41
- <ECharts />
114
+ <div v-fit-screen class="page">
115
+ <div class="chart-slot">
116
+ <div v-compensate.resize-canvas class="chart-inner">
117
+ <div ref="chartEl" class="chart"></div>
118
+ </div>
42
119
  </div>
43
120
  </div>
44
121
  </template>
45
122
 
123
+ <script setup>
124
+ import * as echarts from 'echarts'
125
+ import { vFitScreen, vCompensate, setCompensateEcharts } from 'one-screen-scale'
126
+
127
+ // 可选:全局注入 echarts,供 resizeCanvas 自动探测
128
+ setCompensateEcharts(echarts)
129
+ </script>
130
+ ```
131
+
132
+ ```css
133
+ .chart-slot { width: 100%; height: 300px; overflow: hidden; } /* 设计稿槽位,需明确宽高 */
134
+ .chart-inner, .chart { width: 100%; height: 100%; }
135
+ ```
136
+
137
+ > **适用**:任意被页面 scale 搞小的区域,尤其 **canvas**——先反缩放,再用 `offsetWidth` 量盒(勿用 `getBoundingClientRect`)。
138
+ > **`{ resizeCanvas: true }` / `.resize-canvas`**:补偿后通知子树 canvas 重绘(探测 ECharts / Chart.js,并在每个 `<canvas>` 上派发 `one-screen-scale-canvas-resize`)。
139
+ > 只抵消页面 `v-fit-screen` 的 scale;**不处理**浏览器 Ctrl+/-。
140
+ > **不适用**:`el-slider` 等依赖指针坐标 / 易被 overflow 裁切的控件。
141
+
142
+ ### Vue 3 — Composable(需要拿到 scale 数值时)
143
+
144
+ ```vue
46
145
  <script setup>
47
146
  import { ref } from 'vue'
48
147
  import { useFitScreen } from 'one-screen-scale'
49
148
 
50
149
  const pageRef = ref(null)
51
150
  const { scale, inverseScale } = useFitScreen(pageRef)
52
- // inverseScale 可用于子元素反缩放补偿
53
151
  </script>
54
152
  ```
55
153
 
@@ -57,32 +155,43 @@ const { scale, inverseScale } = useFitScreen(pageRef)
57
155
 
58
156
  ```jsx
59
157
  import { useRef } from 'react'
60
- import { useFitScreen } from 'one-screen-scale/react'
158
+ import { useFitScreen, useCompensate } from 'one-screen-scale/react'
61
159
 
62
160
  function App() {
63
161
  const pageRef = useRef(null)
162
+ const chartInnerRef = useRef(null)
64
163
  const { scale, inverseScale } = useFitScreen(pageRef)
164
+ // 需要通知子树 canvas 重绘时加 { resizeCanvas: true }
165
+ useCompensate(chartInnerRef, { resizeCanvas: true })
65
166
 
66
167
  return (
67
168
  <div ref={pageRef} className="page">
68
- <h1>活动标题</h1>
169
+ <div className="chart-slot" style={{ width: 350, height: 300 }}>
170
+ <div ref={chartInnerRef} style={{ width: '100%', height: '100%' }}>
171
+ <div id="chart" style={{ width: '100%', height: '100%' }} />
172
+ </div>
173
+ </div>
69
174
  </div>
70
175
  )
71
176
  }
72
177
  ```
73
178
 
74
- ### 纯 JS / jQuery
179
+ ### 纯 JS / HTML
75
180
 
76
181
  ```js
77
- import { createScaler } from 'one-screen-scale'
182
+ import { createScaler, createCompensate } from 'one-screen-scale'
78
183
 
79
- const scaler = createScaler(document.querySelector('.page'), {
80
- mode: 'contain'
81
- })
184
+ const page = document.querySelector('.page')
185
+ const scaler = createScaler(page, { mode: 'contain' })
82
186
  scaler.start()
83
187
 
188
+ // 第三方组件反缩放(对应 Vue v-compensate / React useCompensate)
189
+ const inner = document.querySelector('.chart-inner')
190
+ const compensate = createCompensate(inner, { resizeCanvas: true })
191
+
84
192
  // 销毁
85
- scaler.stop()
193
+ compensate.stop()
194
+ scaler.stop() // 移除注入的 class,并还原本库写过的 inline 样式
86
195
  ```
87
196
 
88
197
  ## 两种模式
@@ -90,7 +199,7 @@ scaler.stop()
90
199
  | 模式 | 算法 | 效果 | 场景 |
91
200
  |------|------|------|------|
92
201
  | `contain`(默认) | `min(scaleX, scaleY)` | 内容完整可见,不溢出 | 活动页、落地页 |
93
- | `fixed-width` | `visualWidth / max(innerWidth, screenWidth)` | 固定手机观感宽度,可滚动 | 规则页、长表单 |
202
+ | `fixed-width` | `visualWidth / innerWidth`(视口 ≤ visualWidth 时为 1) | 固定手机观感宽度,可滚动 | 规则页、长表单 |
94
203
 
95
204
  ```js
96
205
  // contain(默认)
@@ -98,6 +207,9 @@ createScaler(el)
98
207
 
99
208
  // fixed-width
100
209
  createScaler(el, { mode: 'fixed-width', visualWidth: 450 })
210
+
211
+ // 自己写根节点宽高时关闭注入
212
+ createScaler(el, { injectBaseStyles: false })
101
213
  ```
102
214
 
103
215
  ## API
@@ -109,20 +221,37 @@ calculateScale(options: ScaleOptions): number
109
221
 
110
222
  applyScale(el: Element | string, scale: number, origin?: string): void
111
223
 
112
- getPageScale(el?: Element | string): number // 默认查 .share-page
113
- getInverseScale(el?: Element | string): number // 1 / getPageScale()
224
+ getPageScale(el?: Element | string): number
225
+ getInverseScale(el?: Element | string): number
114
226
 
115
227
  createScaler(el: Element | string, options?: ScalerOptions): ScalerInstance
228
+
229
+ ensureBaseStyleSheet(): HTMLStyleElement | null
230
+ applyBaseStyles(el: HTMLElement, mode?: 'contain' | 'fixed-width'): string | null
231
+ removeBaseStyles(el: HTMLElement): void
232
+ applyCompensateStyles(el: HTMLElement): string | null
233
+ removeCompensateStyles(el: HTMLElement): void
234
+
235
+ SCALE_CHANGE_EVENT // 'one-screen-scale-change',页面 scale 变化时 window 上触发
236
+
237
+ // 组件反缩放(仅抵消页面 scale)
238
+ resolvePageScale(fromEl?): number
239
+ applyCompensateTransform(el): { scale, inverseScale }
240
+ clearCompensateTransform(el): void
241
+ createCompensate(el, options?: CompensateOptions): { refresh, stop }
242
+ resizeCanvasUnder(el, echartsLib?): number
243
+ setCompensateEcharts(echarts): void // 可选,供 resizeCanvas 探测 ECharts
244
+ CANVAS_RESIZE_EVENT // 'one-screen-scale-canvas-resize'
116
245
  ```
117
246
 
118
247
  ### ScalerInstance
119
248
 
120
249
  ```ts
121
250
  {
122
- start(): number // 启动缩放 + 监听 resize,返回当前 scale
123
- stop(): void // 停止监听
251
+ start(): number // 注入基础样式 + 启动缩放 + 监听 resize
252
+ stop(): void // 停止监听,移除注入 class,还原 inline
124
253
  refresh(): number // 手动重算
125
- getScale(): number // 获取当前 scale
254
+ getScale(): number
126
255
  }
127
256
  ```
128
257
 
@@ -134,14 +263,16 @@ createScaler(el: Element | string, options?: ScalerOptions): ScalerInstance
134
263
  | `visualWidth` | `number` | `450` | fixed-width 模式目标视觉宽度 |
135
264
  | `origin` | `string` | `'top center'` | transform-origin |
136
265
  | `autoResize` | `boolean` | `true` | 自动监听窗口 resize |
266
+ | `injectBaseStyles` | `boolean` | `true` | 是否自动注入模式所需宽高样式 |
267
+ | `observeContent` | `boolean` | `true` | 内容尺寸变化(如图片加载撑高)时自动重算,避免偶发 scale 偏大 |
137
268
 
138
269
  ### Vue
139
270
 
140
271
  ```ts
141
- // 指令
142
272
  vFitScreen: Directive<HTMLElement, ScalerOptions>
273
+ vCompensate: Directive<HTMLElement> // 第三方反缩放
274
+ vFitCompensate: Directive<HTMLElement> // 同上别名
143
275
 
144
- // Composable
145
276
  useFitScreen(ref: Ref, options?: ScalerOptions): {
146
277
  scale: Ref<number>
147
278
  inverseScale: Ref<number>
@@ -149,31 +280,43 @@ useFitScreen(ref: Ref, options?: ScalerOptions): {
149
280
  }
150
281
  ```
151
282
 
152
- ### React
283
+ ### React(`one-screen-scale/react`)
153
284
 
154
285
  ```ts
155
- import { useFitScreen } from 'one-screen-scale/react'
156
-
157
- useFitScreen(ref: RefObject, options?: ScalerOptions): {
158
- scale: number
159
- inverseScale: number
160
- refresh: () => void
161
- }
286
+ useFitScreen(ref, options?: ScalerOptions): { scale, inverseScale, refresh }
287
+ useCompensate(ref, options?: CompensateOptions): { refresh } // 对应 v-compensate
162
288
  ```
163
289
 
164
- ## Canvas / ECharts 模糊问题
290
+ ### CompensateOptions
291
+
292
+ | 参数 | 类型 | 默认值 | 说明 |
293
+ |------|------|--------|------|
294
+ | `resizeCanvas` | `boolean` | — | **可选**。补偿后通知子树 canvas 重绘 |
295
+ | `onRefresh` | `(detail) => void` | — | 每次写入反缩放后回调 |
296
+ | `echarts` / `echartsLib` | — | — | 旧名,等价于开启 `resizeCanvas`;对象形式可传 echarts 模块 |
297
+
298
+ 也可 `setCompensateEcharts(echarts)` 全局注入,方便自动探测。
165
299
 
166
- CSS `transform: scale()` 缩放的是位图,canvas 内容会变糊。解决办法:对 canvas 容器做反缩放补偿。
300
+ ## Canvas 模糊 / 偏小
167
301
 
168
- ```js
169
- // Vue composable 示例
170
- const { inverseScale } = useFitScreen(pageRef)
302
+ CSS `transform: scale()` 会把 **所有 canvas** 一起缩小。先反缩放,再重绘:
303
+
304
+ | 环境 | 反缩放 | 通知 canvas 重绘 |
305
+ |------|--------|------------------|
306
+ | Vue | `v-compensate` | `v-compensate.resize-canvas` |
307
+ | React | `useCompensate(ref)` | `useCompensate(ref, { resizeCanvas: true })` |
308
+ | 纯 JS | `createCompensate(el)` | `createCompensate(el, { resizeCanvas: true })` |
171
309
 
172
- // 在包裹层上应用反缩放
173
- // <div :style="{ transform: `scale(${inverseScale})`, transformOrigin: 'top left' }">
310
+ `resizeCanvas` 会:探测已加载的 ECharts / Chart.js;并在每个 `<canvas>` 上派发事件,自研库可监听:
311
+
312
+ ```js
313
+ canvas.addEventListener('one-screen-scale-canvas-resize', (e) => {
314
+ const { width, height } = e.detail
315
+ myChart.resize(width, height)
316
+ })
174
317
  ```
175
318
 
176
- 反缩放后 canvas 以原生分辨率渲染,保持清晰。详情见 [Canvas 缩放补偿指南](https://github.com/nicepkg/one-screen-scale)。
319
+ 手写等价:`width/height: 100% * pageScale` + `transform: scale(1/pageScale)`,量尺寸用 `offsetWidth`。
177
320
 
178
321
  ## License
179
322
 
package/dist/index.cjs.js CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";var e=require("vue");function t(e){return e?"string"==typeof e?document.querySelector(e):e instanceof HTMLElement?e:e.value instanceof HTMLElement?e.value:e.current instanceof HTMLElement?e.current:null:null}function n({sourceWidth:e,sourceHeight:t,targetWidth:n=("undefined"!=typeof window?window.innerWidth:1920),targetHeight:r=("undefined"!=typeof window?window.innerHeight:1080),mode:i="contain",visualWidth:o=450,screenWidth:s=("undefined"!=typeof window?window.screen.width:1920)}){if(!e||!t||e<=0||t<=0)return 1;let a;if("fixed-width"===i)a=s<o?1:o/Math.max(n,s);else{const i=n/e,o=r/t;a=Math.min(i,o)}return a}function r(e,n,r="top center"){const i=t(e);i&&(i.style.transform=`scale(${n})`,i.style.transformOrigin=r)}function i(e){const n=t(e);if(!n)return 1;const r=window.getComputedStyle(n).transform;if(!r||"none"===r)return 1;const i=r.match(/matrix\(([^,]+),\s*[^,]+,\s*[^,]+,\s*([^,]+)/);if(i)return(parseFloat(i[1])+parseFloat(i[2]))/2;const o=r.match(/matrix3d\(([^,]+),[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,([^,]+)\)/);if(o)return(parseFloat(o[1])+parseFloat(o[2]))/2;const s=r.match(/scale\(([^)]+)\)/);if(s){const e=s[1].split(",").map(e=>parseFloat(e.trim()));return e.length>=2?(e[0]+e[1])/2:e[0]}return 1}function o(e=".share-page"){const t=i(e);return t>0?1/t:1}function s(e,i={}){const o=t(e);if(!o)throw new Error("[one-screen-scale] element not found");const{mode:s="contain",visualWidth:a=450,origin:c="top center",autoResize:u=!0}=i;let l=1,d=null;function f(){const e=n({sourceWidth:o.offsetWidth,sourceHeight:o.offsetHeight,targetWidth:window.innerWidth,targetHeight:window.innerHeight,mode:s,visualWidth:a,screenWidth:window.screen.width});return e!==l&&(l=e,r(o,e,c),"fixed-width"===s&&e>0&&(o.style.width=`${Math.max(window.innerWidth,window.screen.width)}px`,o.style.height=`${Math.round(window.innerHeight/e)}px`)),l}return{start:function(){return f(),u&&(d=()=>f(),window.addEventListener("resize",d)),l},stop:function(){d&&(window.removeEventListener("resize",d),d=null)},refresh:f,getScale:()=>l}}const a={mounted(e,t){const n=s(e,t.value||{});n.start(),e.__fitScreenScaler=n},updated(e,t){const n=e.__fitScreenScaler;n&&(t.value,n.refresh())},unmounted(e){const t=e.__fitScreenScaler;t&&(t.stop(),delete e.__fitScreenScaler)}};exports.applyScale=r,exports.calculateScale=n,exports.createScaler=s,exports.getInverseScale=o,exports.getPageScale=i,exports.useFitScreen=function(t,n={}){const r=e.ref(1),i=e.ref(1);let a=null,c=null;function u(e){if(!e)return;a=s(e,n);const t=a.start();r.value=t,i.value=o(e),c=()=>{r.value=a?.getScale?.()??1,i.value=o(e)},window.addEventListener("resize",c)}return e.onMounted(()=>{u(t?.value??t)}),t&&"object"==typeof t&&"value"in t&&e.watch(()=>t.value,e=>{e&&!a&&u(e)}),e.onUnmounted(()=>{c&&(window.removeEventListener("resize",c),c=null),a?.stop(),a=null}),{scale:r,inverseScale:i,refresh:()=>{const e=t?.value??t;if(!e||!a)return;const n=a.refresh();r.value=n,i.value=o(e)}}},exports.vFitScreen=a;
1
+ "use strict";var e=require("vue");const t="one-screen-scale-base-styles",n={contain:"one-screen-scale--contain","fixed-width":"one-screen-scale--fixed-width",compensate:"one-screen-scale--compensate"},r=`\n.${n.contain} {\n width: 100vw;\n min-height: 100vh;\n min-height: 100dvh;\n}\n/* fixed-width:占位 class,样式先不注入 */\n.${n["fixed-width"]} {\n}\n/*\n * 纯 CSS 反缩放(可选)。v-compensate 指令已改为 JS 行内写入同一公式,更稳。\n * ECharts/Canvas:请用 offsetWidth 量布局盒,勿用 getBoundingClientRect。\n */\n.${n.compensate} {\n transform: scale(var(--one-screen-inverse-scale, 1));\n transform-origin: top left;\n width: calc(100% * var(--one-screen-scale, 1));\n height: calc(100% * var(--one-screen-scale, 1));\n}\n`.trim();function o(){if("undefined"==typeof document)return null;let e=document.getElementById(t);return e?(e.textContent=r,e):(e=document.createElement("style"),e.id=t,e.textContent=r,document.head.appendChild(e),e)}function s(e,t="contain"){if(!e||void 0===e.classList)return null;o();const r=n[t]||n.contain;return[n.contain,n["fixed-width"]].forEach(t=>{t!==r&&e.classList.remove(t)}),e.classList.add(r),r}function i(e){e&&void 0!==e.classList&&e.classList.remove(n.contain,n["fixed-width"])}function a(e){return e?"string"==typeof e?document.querySelector(e):e instanceof HTMLElement?e:e.value instanceof HTMLElement?e.value:e.current instanceof HTMLElement?e.current:null:null}function c({sourceWidth:e,sourceHeight:t,targetWidth:n=("undefined"!=typeof window?window.innerWidth:1920),targetHeight:r=("undefined"!=typeof window?window.innerHeight:1080),mode:o="contain",visualWidth:s=450}){if(!e||!t||e<=0||t<=0)return 1;let i;if("fixed-width"===o)i=n>s?s/n:1;else{const o=n/e,s=r/t;i=Math.min(o,s)}return i}const l="one-screen-scale-change";function u(e,t,n="top center"){const r=a(e);if(!r)return;r.style.transform=`scale(${t})`,r.style.transformOrigin=n;const o=t>0?1/t:1;r.style.setProperty("--one-screen-scale",String(t)),r.style.setProperty("--one-screen-inverse-scale",String(o)),"undefined"!=typeof window&&window.dispatchEvent(new CustomEvent(l,{detail:{scale:t,inverseScale:o,el:r}}))}function f(e){const t=a(e);if(!t)return 1;const n=window.getComputedStyle(t).transform;if(!n||"none"===n)return 1;const r=n.match(/matrix\(([^,]+),\s*[^,]+,\s*[^,]+,\s*([^,]+)/);if(r)return(parseFloat(r[1])+parseFloat(r[2]))/2;const o=n.match(/matrix3d\(([^,]+),[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,([^,]+)\)/);if(o)return(parseFloat(o[1])+parseFloat(o[2]))/2;const s=n.match(/scale\(([^)]+)\)/);if(s){const e=s[1].split(",").map(e=>parseFloat(e.trim()));return e.length>=2?(e[0]+e[1])/2:e[0]}return 1}function d(e,t={}){const n=a(e);if(!n)throw new Error("[one-screen-scale] element not found");const{mode:r="contain",visualWidth:o=450,origin:l="top center",autoResize:f=!0,injectBaseStyles:d=!0,observeContent:m=!0}=t;let h=1,p=null,v=null,y=null,w=0,S=0,g=null,C=!1,_={w:0,h:0},E=0;const x={width:n.style.width,height:n.style.height,transform:n.style.transform,transformOrigin:n.style.transformOrigin};function b(){C=!0;const e=function(){const e=n.offsetWidth,t=n.offsetHeight,s=document.documentElement.clientWidth||window.innerWidth,i=window.innerHeight;return _={w:e,h:t},c({sourceWidth:e,sourceHeight:t,targetWidth:s,targetHeight:i,mode:r,visualWidth:o})}();if(h=e,u(n,e,l),"fixed-width"===r&&e>0){const t=`${document.documentElement.clientWidth||window.innerWidth}px`,r=`${Math.round(window.innerHeight/e)}px`;n.style.width!==t&&(n.style.width=t),n.style.height!==r&&(n.style.height=r)}const t=E;return cancelAnimationFrame(S),S=requestAnimationFrame(()=>{t===E&&(C=!1)}),h}function L(){if(C)return;cancelAnimationFrame(w);const e=E;w=requestAnimationFrame(()=>{if(e!==E)return;const t=n.offsetWidth,r=n.offsetHeight;t===_.w&&r===_.h&&n.style.transform||b()})}function z(){b()}return{start:function(){E+=1;const e=E;return C=!1,d&&s(n,r),b(),f&&(p=z,window.addEventListener("resize",p)),m&&"undefined"!=typeof window&&("undefined"!=typeof ResizeObserver&&(g=new ResizeObserver(()=>L()),g.observe(n)),v=e=>{const t=e.target;!t||"IMG"!==t.tagName&&"VIDEO"!==t.tagName&&"IFRAME"!==t.tagName||L()},n.addEventListener("load",v,!0),n.addEventListener("error",v,!0),document.fonts&&document.fonts.ready&&document.fonts.ready.then(()=>{e===E&&L()}).catch(()=>{}),"complete"===document.readyState?L():(y=()=>L(),window.addEventListener("load",y,{once:!0})),requestAnimationFrame(()=>{requestAnimationFrame(()=>L())})),h},stop:function(){E+=1,p&&(window.removeEventListener("resize",p),p=null),v&&(n.removeEventListener("load",v,!0),n.removeEventListener("error",v,!0),v=null),y&&(window.removeEventListener("load",y),y=null),g&&(g.disconnect(),g=null),cancelAnimationFrame(w),cancelAnimationFrame(S),w=0,S=0,d&&i(n),n.style.width=x.width,n.style.height=x.height,n.style.transform=x.transform,n.style.transformOrigin=x.transformOrigin,n.style.removeProperty("--one-screen-scale"),n.style.removeProperty("--one-screen-inverse-scale")},refresh:b,getScale:()=>h}}const m="one-screen-scale-canvas-resize";let h=null;function p(e){if(!e||"undefined"==typeof getComputedStyle)return NaN;const t=getComputedStyle(e).getPropertyValue("--one-screen-scale").trim();if(!t)return NaN;const n=parseFloat(t);return n>0?n:NaN}function v(e){if(!e||"undefined"==typeof getComputedStyle)return NaN;const t=getComputedStyle(e).transform;if(!t||"none"===t)return NaN;const n=t.match(/matrix\(([^,]+),\s*[^,]+,\s*[^,]+,\s*([^,]+)/);if(n)return(parseFloat(n[1])+parseFloat(n[2]))/2;const r=t.match(/matrix3d\(([^,]+),[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,([^,]+)\)/);if(r)return(parseFloat(r[1])+parseFloat(r[2]))/2;const o=t.match(/scale\(([^)]+)\)/);if(o){const e=o[1].split(",").map(e=>parseFloat(e.trim()));return e.length>=2?(e[0]+e[1])/2:e[0]}return NaN}function y(e){let t=e;for(;t&&1===t.nodeType;){const e=p(t);if(e>0)return e;t=t.parentElement}for(t=e;t&&1===t.nodeType;){if(!t.__oneScreenCompensate){const e=v(t);if(e>0&&1!==e)return e}t=t.parentElement}return 1}function w(e){if(!e)return{scale:1,inverseScale:1};const t=y(e),n=t>0?1/t:1;return e.style.transform=`scale(${n})`,e.style.transformOrigin="top left",e.style.width=100*t+"%",e.style.height=100*t+"%",e.style.overflow="visible",e.__oneScreenCompensate=!0,{scale:t,inverseScale:n}}function S(e){e&&(e.style.transform="",e.style.transformOrigin="",e.style.width="",e.style.height="",e.style.overflow="",delete e.__oneScreenCompensate)}function g(e){return{width:Math.max(1,Math.round(e?.offsetWidth||0)),height:Math.max(1,Math.round(e?.offsetHeight||0))}}function C(e,t){if(!e||"function"!=typeof t)return!1;let n;try{n=t(e)}catch{return!1}if(!n||"function"!=typeof n.resize)return!1;const{width:r,height:o}=g(e);try{return n.resize({width:r,height:o}),!0}catch{return!1}}function _(e){const t="undefined"!=typeof globalThis?globalThis.Chart:null,n=t?.getChart;if("function"!=typeof n)return!1;let r;try{r=n(e)}catch{return!1}if(!r||"function"!=typeof r.resize)return!1;try{return r.resize(),!0}catch{return!1}}function E(e,t){if(!e)return 0;const n=t||h||("undefined"!=typeof globalThis?globalThis.echarts:null)||null;const r=n?.getInstanceByDom;let o=0;const s=e.querySelectorAll?e.querySelectorAll("canvas"):[];for(const t of s){const n=t.parentElement||t,{width:s,height:i}=g(n);(C(t,r)||C(n,r))&&(o+=1),_(t)&&(o+=1);try{t.dispatchEvent(new CustomEvent(m,{bubbles:!0,detail:{width:s,height:i,canvas:t,el:e}}))}catch{}}if("function"==typeof r){const t=[e,...e.querySelectorAll("div")];for(const e of t)C(e,r)&&(o+=1)}return o}function x(e={}){return Boolean(e.resizeCanvas||e.echarts||e.echartsLib)}function b(e={}){return"object"==typeof e.echarts?e.echarts:e.echartsLib?e.echartsLib:void 0}function L(e){const t="function"==typeof e?e():e;return t&&"object"==typeof t?t:{}}function z(e,t={}){if(!e)throw new Error("[one-screen-scale] compensate element required");const n=x(L(t));let r=0,o=null,s=null,i=[],a=!1;const c=()=>{i.forEach(e=>clearTimeout(e)),i=[]},u=()=>{if(a)return;const n=L(t),{scale:r,inverseScale:o}=w(e);if("function"==typeof n.onRefresh)try{n.onRefresh({scale:r,inverseScale:o,el:e})}catch{}if(x(n)){const r=b(n);0===E(e,r)&&(c(),[50,200].forEach(n=>{const r=setTimeout(()=>{if(a)return;const n=L(t);E(e,b(n))},n);i.push(r)}))}},f=()=>{a||(cancelAnimationFrame(r),r=requestAnimationFrame(()=>{r=0,a||u()}))};u(),"undefined"!=typeof window&&(window.addEventListener(l,f),window.addEventListener("resize",f)),"undefined"!=typeof ResizeObserver&&(o=new ResizeObserver(f),e.parentElement&&o.observe(e.parentElement),o.observe(e)),n&&"undefined"!=typeof MutationObserver&&(s=new MutationObserver(f),s.observe(e,{childList:!0,subtree:!0}));return{refresh:u,stop:()=>{a=!0,cancelAnimationFrame(r),c(),r=0,"undefined"!=typeof window&&(window.removeEventListener(l,f),window.removeEventListener("resize",f)),o?.disconnect(),o=null,s?.disconnect(),s=null,S(e)}}}function A(e){return e.value&&"object"==typeof e.value?e.value:{}}function F(e,t){const n=A(t),r=d(e,n);r.start(),e.__fitScreenScaler=r,e.__fitScreenOptionsKey=JSON.stringify({mode:n.mode||"contain",visualWidth:n.visualWidth,origin:n.origin,autoResize:n.autoResize,injectBaseStyles:n.injectBaseStyles,observeContent:n.observeContent})}function O(e){const t=e.__fitScreenScaler;t&&(t.stop(),delete e.__fitScreenScaler,delete e.__fitScreenOptionsKey)}const N={mounted(e,t){F(e,t)},updated(e,t){const n=A(t),r=JSON.stringify({mode:n.mode||"contain",visualWidth:n.visualWidth,origin:n.origin,autoResize:n.autoResize,injectBaseStyles:n.injectBaseStyles,observeContent:n.observeContent});if(e.__fitScreenOptionsKey!==r)return O(e),void F(e,t);e.__fitScreenScaler?.refresh()},unmounted(e){O(e)}};function W(e){const t=e?.value,n=e?.modifiers||{},r=t&&"object"==typeof t?{...t}:{};return(n.resizeCanvas||n["resize-canvas"]||n.echarts||"resize-canvas"===t||"resizeCanvas"===t||"echarts"===t)&&(r.resizeCanvas=r.resizeCanvas||!0),r}function R(e){return JSON.stringify({resizeCanvas:Boolean(e.resizeCanvas||e.echarts||e.echartsLib),hasLib:Boolean(e.echarts&&"object"==typeof e.echarts||e.echartsLib),hasOnRefresh:"function"==typeof e.onRefresh})}function B(e){const t=z(e,()=>e.__oneScreenCompensateOptions||{});e.__oneScreenCompensateApi=t,e.__oneScreenCompensateKey=R(e.__oneScreenCompensateOptions||{})}const T={mounted(e,t){e.__oneScreenCompensateOptions=W(t),B(e)},updated(e,t){const n=W(t),r=R(n);if(e.__oneScreenCompensateOptions=n,e.__oneScreenCompensateKey!==r)return e.__oneScreenCompensateApi?.stop(),void B(e);e.__oneScreenCompensateApi?.refresh()},unmounted(e){e.__oneScreenCompensateApi?.stop(),delete e.__oneScreenCompensateApi,delete e.__oneScreenCompensateKey,delete e.__oneScreenCompensateOptions}},H=T;exports.BASE_CLASS=n,exports.CANVAS_RESIZE_EVENT=m,exports.SCALE_CHANGE_EVENT=l,exports.applyBaseStyles=s,exports.applyCompensateStyles=function(e){return e&&void 0!==e.classList?(o(),e.classList.add(n.compensate),n.compensate):null},exports.applyCompensateTransform=w,exports.applyScale=u,exports.calculateScale=c,exports.clearCompensateTransform=S,exports.createCompensate=z,exports.createScaler=d,exports.ensureBaseStyleSheet=o,exports.getInverseScale=function(e=".share-page"){const t=f(e);return t>0?1/t:1},exports.getPageScale=f,exports.removeBaseStyles=i,exports.removeCompensateStyles=function(e){e&&void 0!==e.classList&&e.classList.remove(n.compensate)},exports.resizeCanvasUnder=E,exports.resizeEchartsUnder=function(e,t){return E(e,t)},exports.resolvePageScale=y,exports.setCompensateEcharts=function(e){h=e||null},exports.useFitScreen=function(t,n={}){const r=e.ref(1),o=e.ref(1);let s=null,i=null;function a(e){if(!e)return;s=d(e,n);const t=s.start();r.value=t,o.value=t>0?1/t:1,i=t=>{t.detail?.el===e&&(r.value=t.detail.scale,o.value=t.detail.inverseScale)},window.addEventListener(l,i)}return e.onMounted(()=>{a(t?.value??t)}),t&&"object"==typeof t&&"value"in t&&e.watch(()=>t.value,e=>{e&&!s&&a(e)}),e.onUnmounted(()=>{i&&(window.removeEventListener(l,i),i=null),s?.stop(),s=null}),{scale:r,inverseScale:o,refresh:()=>{if(!(t?.value??t)||!s)return;const e=s.refresh();r.value=e,o.value=e>0?1/e:1}}},exports.vCompensate=T,exports.vFitCompensate=H,exports.vFitScreen=N;
2
2
  //# sourceMappingURL=index.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs.js","sources":["../src/core.js","../src/directives.js","../src/composables.js"],"sourcesContent":["/**\n * 一屏自适应缩放 — 核心算法(框架无关)\n *\n * 两种模式:\n * 'contain' 一屏展示,内容不溢出,用 min(scaleX, scaleY)\n * 'fixed-width' 固定视觉宽度,内容可滚动,反向补高\n */\n\n// ---------- helpers ----------\n\nfunction resolveEl(el) {\n if (!el) return null\n if (typeof el === 'string') return document.querySelector(el)\n if (el instanceof HTMLElement) return el\n // Vue ref / React ref\n if (el.value instanceof HTMLElement) return el.value\n if (el.current instanceof HTMLElement) return el.current\n return null\n}\n\n// ---------- scale calculation ----------\n\nexport function calculateScale({\n sourceWidth,\n sourceHeight,\n targetWidth = (typeof window !== 'undefined' ? window.innerWidth : 1920),\n targetHeight = (typeof window !== 'undefined' ? window.innerHeight : 1080),\n mode = 'contain',\n visualWidth = 450, // fixed-width 模式下的目标视觉宽度\n screenWidth = (typeof window !== 'undefined' ? window.screen.width : 1920), // fixed-width 模式下的设备屏幕宽度\n}) {\n if (!sourceWidth || !sourceHeight || sourceWidth <= 0 || sourceHeight <= 0) return 1\n\n let scale\n\n if (mode === 'fixed-width') {\n if(screenWidth < visualWidth){\n scale = 1\n }else{\n scale = visualWidth / Math.max(targetWidth, screenWidth)\n }\n } else {\n const sx = targetWidth / sourceWidth\n const sy = targetHeight / sourceHeight\n scale = Math.min(sx, sy)\n }\n\n return scale\n}\n\n// ---------- apply / read ----------\n\nexport function applyScale(el, scale, origin = 'top center') {\n const target = resolveEl(el)\n if (!target) return\n target.style.transform = `scale(${scale})`\n target.style.transformOrigin = origin\n}\n\nexport function getPageScale(el) {\n const target = resolveEl(el)\n if (!target) return 1\n\n const style = window.getComputedStyle(target)\n const t = style.transform\n if (!t || t === 'none') return 1\n\n // matrix(a, b, c, d, e, f) — 2d\n const m2 = t.match(/matrix\\(([^,]+),\\s*[^,]+,\\s*[^,]+,\\s*([^,]+)/)\n if (m2) return (parseFloat(m2[1]) + parseFloat(m2[2])) / 2\n\n // matrix3d — 3d\n const m3 = t.match(/matrix3d\\(([^,]+),[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,([^,]+)\\)/)\n if (m3) return (parseFloat(m3[1]) + parseFloat(m3[2])) / 2\n\n // scale(x, y) or scale(s)\n const sm = t.match(/scale\\(([^)]+)\\)/)\n if (sm) {\n const vals = sm[1].split(',').map(v => parseFloat(v.trim()))\n return vals.length >= 2 ? (vals[0] + vals[1]) / 2 : vals[0]\n }\n\n return 1\n}\n\nexport function getInverseScale(el = '.share-page') {\n const s = getPageScale(el)\n return s > 0 ? 1 / s : 1\n}\n\n// ---------- scaler instance ----------\n\nexport function createScaler(el, options = {}) {\n const target = resolveEl(el)\n if (!target) throw new Error('[one-screen-scale] element not found')\n\n const {\n mode = 'contain',\n visualWidth = 450,\n origin = 'top center',\n autoResize = true\n } = options\n\n let currentScale = 1\n let handler = null\n\n function compute() {\n const sw = target.offsetWidth\n const sh = target.offsetHeight\n const tw = window.innerWidth\n const th = window.innerHeight\n\n return calculateScale({\n sourceWidth: sw,\n sourceHeight: sh,\n targetWidth: tw,\n targetHeight: th,\n mode,\n visualWidth,\n screenWidth: window.screen.width\n })\n }\n\n function refresh() {\n const next = compute()\n if (next !== currentScale) {\n currentScale = next\n applyScale(target, next, origin)\n\n // fixed-width 模式:反向补偿高度\n if (mode === 'fixed-width' && next > 0) {\n target.style.width = `${Math.max(window.innerWidth, window.screen.width)}px`\n target.style.height = `${Math.round(window.innerHeight / next)}px`\n }\n }\n return currentScale\n }\n\n function start() {\n refresh()\n if (autoResize) {\n handler = () => refresh()\n window.addEventListener('resize', handler)\n }\n return currentScale\n }\n\n function stop() {\n if (handler) {\n window.removeEventListener('resize', handler)\n handler = null\n }\n }\n\n return { start, stop, refresh, getScale: () => currentScale }\n}\n","/**\n * Vue 3 指令\n * v-fit-screen 页面级缩放\n * v-compensate 组件级反缩放补偿\n */\nimport { createScaler } from './core.js'\n\n// ---- v-fit-screen ----\n\nexport const vFitScreen = {\n mounted(el, binding) {\n const options = binding.value || {}\n const scaler = createScaler(el, options)\n scaler.start()\n el.__fitScreenScaler = scaler\n },\n\n updated(el, binding) {\n const scaler = el.__fitScreenScaler\n if (scaler) {\n const options = binding.value || {}\n // 简单处理:重新 refresh\n scaler.refresh()\n }\n },\n\n unmounted(el) {\n const scaler = el.__fitScreenScaler\n if (scaler) {\n scaler.stop()\n delete el.__fitScreenScaler\n }\n }\n}\n","/**\n * Vue 3 Composable\n * useFitScreen(ref, options) → { scale, inverseScale, refresh }\n */\nimport { ref, onMounted, onUnmounted, watch } from 'vue'\nimport { createScaler, getInverseScale } from './core.js'\n\nexport function useFitScreen(targetRef, options = {}) {\n const scale = ref(1)\n const inverseScale = ref(1)\n\n let scaler = null\n let onResize = null\n\n function setup(el) {\n if (!el) return\n scaler = createScaler(el, options)\n const s = scaler.start()\n scale.value = s\n inverseScale.value = getInverseScale(el)\n\n onResize = () => {\n scale.value = scaler?.getScale?.() ?? 1\n inverseScale.value = getInverseScale(el)\n }\n window.addEventListener('resize', onResize)\n }\n\n function teardown() {\n if (onResize) {\n window.removeEventListener('resize', onResize)\n onResize = null\n }\n scaler?.stop()\n scaler = null\n }\n\n // 处理 ref 初始有值的情况\n onMounted(() => {\n const el = targetRef?.value ?? targetRef\n setup(el)\n })\n\n // 处理 ref 延迟赋值的情况(异步挂载)\n if (targetRef && typeof targetRef === 'object' && 'value' in targetRef) {\n watch(\n () => targetRef.value,\n (el) => {\n if (el && !scaler) setup(el)\n }\n )\n }\n\n onUnmounted(() => {\n teardown()\n })\n\n const refresh = () => {\n const el = targetRef?.value ?? targetRef\n if (!el || !scaler) return\n const s = scaler.refresh()\n scale.value = s\n inverseScale.value = getInverseScale(el)\n }\n\n return { scale, inverseScale, refresh }\n}\n"],"names":["resolveEl","el","document","querySelector","HTMLElement","value","current","calculateScale","sourceWidth","sourceHeight","targetWidth","window","innerWidth","targetHeight","innerHeight","mode","visualWidth","screenWidth","screen","width","scale","Math","max","sx","sy","min","applyScale","origin","target","style","transform","transformOrigin","getPageScale","t","getComputedStyle","m2","match","parseFloat","m3","sm","vals","split","map","v","trim","length","getInverseScale","s","createScaler","options","Error","autoResize","currentScale","handler","refresh","next","offsetWidth","offsetHeight","height","round","start","addEventListener","stop","removeEventListener","getScale","vFitScreen","mounted","binding","scaler","__fitScreenScaler","updated","unmounted","targetRef","ref","inverseScale","onResize","setup","onMounted","watch","onUnmounted"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs.js","sources":["../src/baseStyles.js","../src/core.js","../src/compensate.js","../src/directives.js","../src/composables.js"],"sourcesContent":["/**\n * 指令挂载时注入的「适配生效」基础样式。\n *\n * 前提:页面用了 postcss-px-to-viewport(或同类)把设计稿 px 转成 vw。\n *\n * - contain:宽拉满视口 + 最小一屏高,高度由内容撑开\n * - fixed-width:宽高由 refresh 行内补偿,暂不注入\n * - compensate:第三方组件反缩放(抵消页面 scale,ECharts / Element Plus 等)\n */\n\nexport const STYLE_ELEMENT_ID = 'one-screen-scale-base-styles'\n\nexport const BASE_CLASS = {\n contain: 'one-screen-scale--contain',\n 'fixed-width': 'one-screen-scale--fixed-width',\n compensate: 'one-screen-scale--compensate',\n}\n\nconst BASE_CSS = `\n.${BASE_CLASS.contain} {\n width: 100vw;\n min-height: 100vh;\n min-height: 100dvh;\n}\n/* fixed-width:占位 class,样式先不注入 */\n.${BASE_CLASS['fixed-width']} {\n}\n/*\n * 纯 CSS 反缩放(可选)。v-compensate 指令已改为 JS 行内写入同一公式,更稳。\n * ECharts/Canvas:请用 offsetWidth 量布局盒,勿用 getBoundingClientRect。\n */\n.${BASE_CLASS.compensate} {\n transform: scale(var(--one-screen-inverse-scale, 1));\n transform-origin: top left;\n width: calc(100% * var(--one-screen-scale, 1));\n height: calc(100% * var(--one-screen-scale, 1));\n}\n`.trim()\n\n/** 向 document 注入 / 同步基础样式表(已存在则更新内容,便于本地迭代) */\nexport function ensureBaseStyleSheet() {\n if (typeof document === 'undefined') return null\n let styleEl = document.getElementById(STYLE_ELEMENT_ID)\n if (styleEl) {\n styleEl.textContent = BASE_CSS\n return styleEl\n }\n\n styleEl = document.createElement('style')\n styleEl.id = STYLE_ELEMENT_ID\n styleEl.textContent = BASE_CSS\n document.head.appendChild(styleEl)\n return styleEl\n}\n\n/**\n * 给缩放根节点挂上对应模式的 class。\n * @returns {string | null} 本次加上的 class,便于 stop 时移除\n */\nexport function applyBaseStyles(el, mode = 'contain') {\n if (!el || typeof el.classList === 'undefined') return null\n ensureBaseStyleSheet()\n\n const nextClass = BASE_CLASS[mode] || BASE_CLASS.contain\n // 切换模式时清掉另一套页面级 class(不动 compensate)\n ;[BASE_CLASS.contain, BASE_CLASS['fixed-width']].forEach((cls) => {\n if (cls !== nextClass) el.classList.remove(cls)\n })\n el.classList.add(nextClass)\n return nextClass\n}\n\n/** 移除本库注入的页面级基础 class(不含 compensate) */\nexport function removeBaseStyles(el) {\n if (!el || typeof el.classList === 'undefined') return\n el.classList.remove(BASE_CLASS.contain, BASE_CLASS['fixed-width'])\n}\n\n/** 挂上反缩放补偿 class */\nexport function applyCompensateStyles(el) {\n if (!el || typeof el.classList === 'undefined') return null\n ensureBaseStyleSheet()\n el.classList.add(BASE_CLASS.compensate)\n return BASE_CLASS.compensate\n}\n\n/** 移除反缩放补偿 class */\nexport function removeCompensateStyles(el) {\n if (!el || typeof el.classList === 'undefined') return\n el.classList.remove(BASE_CLASS.compensate)\n}\n","/**\n * 一屏自适应缩放 — 核心算法(框架无关)\n *\n * 两种模式:\n * 'contain' 一屏展示,内容不溢出,用 min(scaleX, scaleY)\n * 'fixed-width' 固定视觉宽度,内容可滚动,反向补高\n *\n * 配套前提:H5 使用 postcss-px-to-viewport(或同类)做移动端适配。\n * createScaler / 指令默认会注入基础宽高样式,保证测量与缩放生效。\n *\n * 图片等异步内容会改变 offsetHeight:默认用 ResizeObserver / 图片 load\n * 在尺寸稳定后再 refresh,避免首屏偶发「量矮了 → scale 偏大」。\n */\n\nimport { applyBaseStyles, removeBaseStyles } from './baseStyles.js'\n\n// ---------- helpers ----------\n\nfunction resolveEl(el) {\n if (!el) return null\n if (typeof el === 'string') return document.querySelector(el)\n if (el instanceof HTMLElement) return el\n // Vue ref / React ref\n if (el.value instanceof HTMLElement) return el.value\n if (el.current instanceof HTMLElement) return el.current\n return null\n}\n\n// ---------- scale calculation ----------\n\nexport function calculateScale({\n sourceWidth,\n sourceHeight,\n targetWidth = (typeof window !== 'undefined' ? window.innerWidth : 1920),\n targetHeight = (typeof window !== 'undefined' ? window.innerHeight : 1080),\n mode = 'contain',\n visualWidth = 450, // fixed-width 模式下的目标视觉宽度\n}) {\n if (!sourceWidth || !sourceHeight || sourceWidth <= 0 || sourceHeight <= 0) return 1\n\n let scale\n\n if (mode === 'fixed-width') {\n // 只用视口宽:视口比目标宽才缩小,否则 1:1(保持清晰)\n scale = targetWidth > visualWidth ? visualWidth / targetWidth : 1\n } else {\n const sx = targetWidth / sourceWidth\n const sy = targetHeight / sourceHeight\n scale = Math.min(sx, sy)\n }\n\n return scale\n}\n\n// ---------- apply / read ----------\n\n/** 页面 scale 变化时抛出,供 ECharts.resize / 业务监听 */\nexport const SCALE_CHANGE_EVENT = 'one-screen-scale-change'\n\nexport function applyScale(el, scale, origin = 'top center') {\n const target = resolveEl(el)\n if (!target) return\n target.style.transform = `scale(${scale})`\n target.style.transformOrigin = origin\n // 供业务 / v-compensate 做反缩放(继承到子树)\n const inv = scale > 0 ? 1 / scale : 1\n target.style.setProperty('--one-screen-scale', String(scale))\n target.style.setProperty('--one-screen-inverse-scale', String(inv))\n if (typeof window !== 'undefined') {\n window.dispatchEvent(\n new CustomEvent(SCALE_CHANGE_EVENT, { detail: { scale, inverseScale: inv, el: target } })\n )\n }\n}\n\nexport function getPageScale(el) {\n const target = resolveEl(el)\n if (!target) return 1\n\n const style = window.getComputedStyle(target)\n const t = style.transform\n if (!t || t === 'none') return 1\n\n // matrix(a, b, c, d, e, f) — 2d\n const m2 = t.match(/matrix\\(([^,]+),\\s*[^,]+,\\s*[^,]+,\\s*([^,]+)/)\n if (m2) return (parseFloat(m2[1]) + parseFloat(m2[2])) / 2\n\n // matrix3d — 3d\n const m3 = t.match(/matrix3d\\(([^,]+),[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,([^,]+)\\)/)\n if (m3) return (parseFloat(m3[1]) + parseFloat(m3[2])) / 2\n\n // scale(x, y) or scale(s)\n const sm = t.match(/scale\\(([^)]+)\\)/)\n if (sm) {\n const vals = sm[1].split(',').map(v => parseFloat(v.trim()))\n return vals.length >= 2 ? (vals[0] + vals[1]) / 2 : vals[0]\n }\n\n return 1\n}\n\nexport function getInverseScale(el = '.share-page') {\n const s = getPageScale(el)\n return s > 0 ? 1 / s : 1\n}\n\n// ---------- scaler instance ----------\n\nexport function createScaler(el, options = {}) {\n const target = resolveEl(el)\n if (!target) throw new Error('[one-screen-scale] element not found')\n\n const {\n mode = 'contain',\n visualWidth = 450,\n origin = 'top center',\n autoResize = true,\n /** 是否自动注入模式所需的宽高基础样式,默认 true */\n injectBaseStyles = true,\n /**\n * 内容尺寸变化时自动重算(图片 load、字体、DOM 撑高)。\n * 解决刷新偶发「图未加载完就测量 → scale 偏大」。\n */\n observeContent = true,\n } = options\n\n let currentScale = 1\n let resizeHandler = null\n let loadHandler = null\n let windowLoadHandler = null\n let rafId = 0\n let unlockRaf = 0\n let ro = null\n let refreshing = false\n let lastMeasured = { w: 0, h: 0 }\n // start / stop 各加一,用来丢掉停掉之后才回来的字体、帧回调\n let session = 0\n\n // fixed-width 会改 inline width/height,stop 时还原\n const savedInline = {\n width: target.style.width,\n height: target.style.height,\n transform: target.style.transform,\n transformOrigin: target.style.transformOrigin,\n }\n\n function compute() {\n const sw = target.offsetWidth\n const sh = target.offsetHeight\n const tw = document.documentElement.clientWidth || window.innerWidth\n const th = window.innerHeight\n\n lastMeasured = { w: sw, h: sh }\n\n return calculateScale({\n sourceWidth: sw,\n sourceHeight: sh,\n targetWidth: tw,\n targetHeight: th,\n mode,\n visualWidth,\n })\n }\n\n function refresh() {\n refreshing = true\n const next = compute()\n currentScale = next\n // 始终写入,保证首次 scale=1 时也带上 transform-origin\n applyScale(target, next, origin)\n\n // fixed-width 模式:反向补偿高度(视觉宽固定,布局宽仍用视口宽再缩小)\n if (mode === 'fixed-width' && next > 0) {\n const viewportWidth = document.documentElement.clientWidth || window.innerWidth\n const nextW = `${viewportWidth}px`\n const nextH = `${Math.round(window.innerHeight / next)}px`\n // 值不变不写,避免 ResizeObserver 死循环\n if (target.style.width !== nextW) target.style.width = nextW\n if (target.style.height !== nextH) target.style.height = nextH\n }\n // 等布局提交后再放开,避免 RO 回调里立刻重入\n const token = session\n cancelAnimationFrame(unlockRaf)\n unlockRaf = requestAnimationFrame(() => {\n if (token !== session) return\n refreshing = false\n })\n return currentScale\n }\n\n function scheduleRefresh() {\n if (refreshing) return\n cancelAnimationFrame(rafId)\n const token = session\n rafId = requestAnimationFrame(() => {\n if (token !== session) return\n // 尺寸没变就跳过(fixed-width 改 height 触发的 RO)\n const w = target.offsetWidth\n const h = target.offsetHeight\n if (w === lastMeasured.w && h === lastMeasured.h && target.style.transform) {\n // 视口变化仍需算:由 window.resize 路径直接 refresh\n return\n }\n refresh()\n })\n }\n\n function onWindowResize() {\n refresh()\n }\n\n function start() {\n session += 1\n const token = session\n // 复用同一实例 start 时,上一次 stop 之后留下的锁要清掉\n refreshing = false\n if (injectBaseStyles) {\n applyBaseStyles(target, mode)\n }\n // 注入样式后再量尺寸\n refresh()\n\n if (autoResize) {\n resizeHandler = onWindowResize\n window.addEventListener('resize', resizeHandler)\n }\n\n if (observeContent && typeof window !== 'undefined') {\n // 1) 子树布局尺寸变化(图片解码后撑高最常见)\n if (typeof ResizeObserver !== 'undefined') {\n ro = new ResizeObserver(() => scheduleRefresh())\n ro.observe(target)\n }\n\n // 2) 捕获阶段听内部 img/video 的 load(含后插入的节点)\n loadHandler = (e) => {\n const t = e.target\n if (t && (t.tagName === 'IMG' || t.tagName === 'VIDEO' || t.tagName === 'IFRAME')) {\n scheduleRefresh()\n }\n }\n target.addEventListener('load', loadHandler, true)\n target.addEventListener('error', loadHandler, true)\n\n // 3) 字体就绪。stop 之后 session 变了,这次回调直接丢掉\n if (document.fonts && document.fonts.ready) {\n document.fonts.ready\n .then(() => {\n if (token !== session) return\n scheduleRefresh()\n })\n .catch(() => {})\n }\n\n // 4) 整页资源 load(缓存命中时可能已 complete)\n if (document.readyState === 'complete') {\n scheduleRefresh()\n } else {\n windowLoadHandler = () => scheduleRefresh()\n window.addEventListener('load', windowLoadHandler, { once: true })\n }\n\n // 5) 再等两帧,覆盖首屏同步布局抖动\n requestAnimationFrame(() => {\n requestAnimationFrame(() => scheduleRefresh())\n })\n }\n\n return currentScale\n }\n\n function stop() {\n session += 1\n if (resizeHandler) {\n window.removeEventListener('resize', resizeHandler)\n resizeHandler = null\n }\n if (loadHandler) {\n target.removeEventListener('load', loadHandler, true)\n target.removeEventListener('error', loadHandler, true)\n loadHandler = null\n }\n if (windowLoadHandler) {\n window.removeEventListener('load', windowLoadHandler)\n windowLoadHandler = null\n }\n if (ro) {\n ro.disconnect()\n ro = null\n }\n cancelAnimationFrame(rafId)\n cancelAnimationFrame(unlockRaf)\n rafId = 0\n unlockRaf = 0\n\n if (injectBaseStyles) {\n removeBaseStyles(target)\n }\n target.style.width = savedInline.width\n target.style.height = savedInline.height\n target.style.transform = savedInline.transform\n target.style.transformOrigin = savedInline.transformOrigin\n target.style.removeProperty('--one-screen-scale')\n target.style.removeProperty('--one-screen-inverse-scale')\n }\n\n return { start, stop, refresh, getScale: () => currentScale }\n}\n\nexport {\n applyBaseStyles,\n removeBaseStyles,\n applyCompensateStyles,\n removeCompensateStyles,\n ensureBaseStyleSheet,\n BASE_CLASS,\n} from './baseStyles.js'\n","/**\n * 组件级反缩放补偿(与业务 WinRateChart 手写公式一致):\n * transform: scale(inverse); width/height: 100% * pageScale; origin: top left\n *\n * 只抵消页面 v-fit-screen 的 scale;不处理浏览器 Ctrl+/-。\n */\n\nimport { SCALE_CHANGE_EVENT } from './core.js'\n\n/** 子树 canvas 需要重绘时抛出(挂在每个 <canvas> 上) */\nexport const CANVAS_RESIZE_EVENT = 'one-screen-scale-canvas-resize'\n\n/** @type {null | { getInstanceByDom?: (el: Element) => { resize: Function } | undefined }} */\nlet registeredEcharts = null\n\n/** 业务可注入 echarts 模块(避免插件硬依赖);供 resizeCanvas 探测 */\nexport function setCompensateEcharts(echarts) {\n registeredEcharts = echarts || null\n}\n\nfunction readCssVarScale(el) {\n if (!el || typeof getComputedStyle === 'undefined') return NaN\n const raw = getComputedStyle(el).getPropertyValue('--one-screen-scale').trim()\n if (!raw) return NaN\n const v = parseFloat(raw)\n return v > 0 ? v : NaN\n}\n\nfunction readTransformScale(el) {\n if (!el || typeof getComputedStyle === 'undefined') return NaN\n const t = getComputedStyle(el).transform\n if (!t || t === 'none') return NaN\n\n const m2 = t.match(/matrix\\(([^,]+),\\s*[^,]+,\\s*[^,]+,\\s*([^,]+)/)\n if (m2) return (parseFloat(m2[1]) + parseFloat(m2[2])) / 2\n\n const m3 = t.match(\n /matrix3d\\(([^,]+),[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,([^,]+)\\)/\n )\n if (m3) return (parseFloat(m3[1]) + parseFloat(m3[2])) / 2\n\n const sm = t.match(/scale\\(([^)]+)\\)/)\n if (sm) {\n const vals = sm[1].split(',').map((v) => parseFloat(v.trim()))\n return vals.length >= 2 ? (vals[0] + vals[1]) / 2 : vals[0]\n }\n return NaN\n}\n\n/** 从 fromEl 向上解析页面 scale(跳过已挂补偿的节点自身 transform) */\nexport function resolvePageScale(fromEl) {\n let node = fromEl\n while (node && node.nodeType === 1) {\n const fromVar = readCssVarScale(node)\n if (fromVar > 0) return fromVar\n node = node.parentElement\n }\n\n node = fromEl\n while (node && node.nodeType === 1) {\n if (!node.__oneScreenCompensate) {\n const fromTf = readTransformScale(node)\n if (fromTf > 0 && fromTf !== 1) return fromTf\n }\n node = node.parentElement\n }\n return 1\n}\n\n/**\n * 给槽位内层写入反缩放行内样式。父槽位需有明确宽高。\n * @returns {{ scale: number, inverseScale: number }}\n */\nexport function applyCompensateTransform(el) {\n if (!el) return { scale: 1, inverseScale: 1 }\n const scale = resolvePageScale(el)\n const inverseScale = scale > 0 ? 1 / scale : 1\n el.style.transform = `scale(${inverseScale})`\n el.style.transformOrigin = 'top left'\n el.style.width = `${100 * scale}%`\n el.style.height = `${100 * scale}%`\n el.style.overflow = 'visible'\n el.__oneScreenCompensate = true\n return { scale, inverseScale }\n}\n\nexport function clearCompensateTransform(el) {\n if (!el) return\n el.style.transform = ''\n el.style.transformOrigin = ''\n el.style.width = ''\n el.style.height = ''\n el.style.overflow = ''\n delete el.__oneScreenCompensate\n}\n\nfunction resolveEchartsLib(bindingEcharts) {\n return (\n bindingEcharts ||\n registeredEcharts ||\n (typeof globalThis !== 'undefined' ? globalThis.echarts : null) ||\n null\n )\n}\n\nfunction boxSize(node) {\n const w = Math.max(1, Math.round(node?.offsetWidth || 0))\n const h = Math.max(1, Math.round(node?.offsetHeight || 0))\n return { width: w, height: h }\n}\n\nfunction tryEchartsResize(node, getInst) {\n if (!node || typeof getInst !== 'function') return false\n let inst\n try {\n inst = getInst(node)\n } catch {\n return false\n }\n if (!inst || typeof inst.resize !== 'function') return false\n const { width, height } = boxSize(node)\n try {\n inst.resize({ width, height })\n return true\n } catch {\n return false\n }\n}\n\nfunction tryChartJsResize(canvas) {\n const Chart = typeof globalThis !== 'undefined' ? globalThis.Chart : null\n const getChart = Chart?.getChart\n if (typeof getChart !== 'function') return false\n let chart\n try {\n chart = getChart(canvas)\n } catch {\n return false\n }\n if (!chart || typeof chart.resize !== 'function') return false\n try {\n chart.resize()\n return true\n } catch {\n return false\n }\n}\n\n/**\n * 补偿后通知子树 canvas 重绘:\n * - 探测 ECharts / Chart.js(若已加载)\n * - 每个 <canvas> 派发 CANVAS_RESIZE_EVENT,业务可自行监听重绘\n * 量尺寸用 offsetWidth(勿用 getBoundingClientRect)\n *\n * @returns {number} 成功调用已知图表库 resize 的次数\n */\nexport function resizeCanvasUnder(el, echartsLib) {\n if (!el) return 0\n\n const echarts = resolveEchartsLib(echartsLib)\n const getInst = echarts?.getInstanceByDom\n let count = 0\n\n const canvases = el.querySelectorAll ? el.querySelectorAll('canvas') : []\n for (const canvas of canvases) {\n const host = canvas.parentElement || canvas\n const { width, height } = boxSize(host)\n\n if (tryEchartsResize(canvas, getInst)) count += 1\n else if (tryEchartsResize(host, getInst)) count += 1\n\n if (tryChartJsResize(canvas)) count += 1\n\n try {\n canvas.dispatchEvent(\n new CustomEvent(CANVAS_RESIZE_EVENT, {\n bubbles: true,\n detail: { width, height, canvas, el },\n })\n )\n } catch {\n /* ignore */\n }\n }\n\n // ECharts 常挂在 div 上(不一定已有 canvas)\n if (typeof getInst === 'function') {\n const nodes = [el, ...el.querySelectorAll('div')]\n for (const node of nodes) {\n if (tryEchartsResize(node, getInst)) count += 1\n }\n }\n\n return count\n}\n\n/** @deprecated 请用 resizeCanvasUnder */\nexport function resizeEchartsUnder(el, echartsLib) {\n return resizeCanvasUnder(el, echartsLib)\n}\n\nfunction wantsResizeCanvas(options = {}) {\n return Boolean(\n options.resizeCanvas ||\n options.echarts || // 兼容旧名\n options.echartsLib\n )\n}\n\nfunction resolveBoundEcharts(options = {}) {\n if (typeof options.echarts === 'object') return options.echarts\n if (options.echartsLib) return options.echartsLib\n return undefined\n}\n\n/** options 可以是对象,也可以是返回最新对象的函数(指令 / hook 传 getter 用) */\nfunction readLiveOptions(options) {\n const value = typeof options === 'function' ? options() : options\n return value && typeof value === 'object' ? value : {}\n}\n\n/**\n * @param {HTMLElement} el\n * @param {{\n * resizeCanvas?: boolean,\n * echarts?: boolean | object,\n * echartsLib?: object,\n * onRefresh?: Function\n * } | (() => object)} [options]\n */\nexport function createCompensate(el, options = {}) {\n if (!el) throw new Error('[one-screen-scale] compensate element required')\n\n const initial = readLiveOptions(options)\n const wantResize = wantsResizeCanvas(initial)\n let raf = 0\n let ro = null\n let mo = null\n let retryTimers = []\n let stopped = false\n\n const clearRetries = () => {\n retryTimers.forEach((id) => clearTimeout(id))\n retryTimers = []\n }\n\n const refresh = () => {\n if (stopped) return\n const live = readLiveOptions(options)\n const { scale, inverseScale } = applyCompensateTransform(el)\n if (typeof live.onRefresh === 'function') {\n try {\n live.onRefresh({ scale, inverseScale, el })\n } catch {\n /* user callback */\n }\n }\n if (wantsResizeCanvas(live)) {\n const lib = resolveBoundEcharts(live)\n const n = resizeCanvasUnder(el, lib)\n if (n === 0) {\n clearRetries()\n ;[50, 200].forEach((delay) => {\n const id = setTimeout(() => {\n if (stopped) return\n const next = readLiveOptions(options)\n resizeCanvasUnder(el, resolveBoundEcharts(next))\n }, delay)\n retryTimers.push(id)\n })\n }\n }\n }\n\n const schedule = () => {\n if (stopped) return\n cancelAnimationFrame(raf)\n raf = requestAnimationFrame(() => {\n raf = 0\n if (stopped) return\n refresh()\n })\n }\n\n refresh()\n\n if (typeof window !== 'undefined') {\n window.addEventListener(SCALE_CHANGE_EVENT, schedule)\n window.addEventListener('resize', schedule)\n }\n\n if (typeof ResizeObserver !== 'undefined') {\n ro = new ResizeObserver(schedule)\n if (el.parentElement) ro.observe(el.parentElement)\n ro.observe(el)\n }\n\n if (wantResize && typeof MutationObserver !== 'undefined') {\n mo = new MutationObserver(schedule)\n mo.observe(el, { childList: true, subtree: true })\n }\n\n const stop = () => {\n stopped = true\n cancelAnimationFrame(raf)\n clearRetries()\n raf = 0\n if (typeof window !== 'undefined') {\n window.removeEventListener(SCALE_CHANGE_EVENT, schedule)\n window.removeEventListener('resize', schedule)\n }\n ro?.disconnect()\n ro = null\n mo?.disconnect()\n mo = null\n clearCompensateTransform(el)\n }\n\n return { refresh, stop }\n}\n","/**\n * Vue 3 指令\n * v-fit-screen 页面级缩放\n * v-compensate 组件级反缩放补偿(ECharts / Element Plus 等)\n */\nimport { createScaler } from './core.js'\nimport { createCompensate } from './compensate.js'\n\nfunction readOptions(binding) {\n return binding.value && typeof binding.value === 'object' ? binding.value : {}\n}\n\nfunction mountScaler(el, binding) {\n const options = readOptions(binding)\n const scaler = createScaler(el, options)\n scaler.start()\n el.__fitScreenScaler = scaler\n el.__fitScreenOptionsKey = JSON.stringify({\n mode: options.mode || 'contain',\n visualWidth: options.visualWidth,\n origin: options.origin,\n autoResize: options.autoResize,\n injectBaseStyles: options.injectBaseStyles,\n observeContent: options.observeContent,\n })\n}\n\nfunction unmountScaler(el) {\n const scaler = el.__fitScreenScaler\n if (scaler) {\n scaler.stop()\n delete el.__fitScreenScaler\n delete el.__fitScreenOptionsKey\n }\n}\n\n// ---- v-fit-screen ----\n\nexport const vFitScreen = {\n mounted(el, binding) {\n mountScaler(el, binding)\n },\n\n updated(el, binding) {\n const options = readOptions(binding)\n const key = JSON.stringify({\n mode: options.mode || 'contain',\n visualWidth: options.visualWidth,\n origin: options.origin,\n autoResize: options.autoResize,\n injectBaseStyles: options.injectBaseStyles,\n observeContent: options.observeContent,\n })\n\n if (el.__fitScreenOptionsKey !== key) {\n unmountScaler(el)\n mountScaler(el, binding)\n return\n }\n\n el.__fitScreenScaler?.refresh()\n },\n\n unmounted(el) {\n unmountScaler(el)\n },\n}\n\nfunction readCompensateOptions(binding) {\n const value = binding?.value\n const modifiers = binding?.modifiers || {}\n const options = value && typeof value === 'object' ? { ...value } : {}\n // v-compensate.resize-canvas / .resizeCanvas / 旧名 .echarts\n if (\n modifiers.resizeCanvas ||\n modifiers['resize-canvas'] ||\n modifiers.echarts ||\n value === 'resize-canvas' ||\n value === 'resizeCanvas' ||\n value === 'echarts'\n ) {\n options.resizeCanvas = options.resizeCanvas || true\n }\n return options\n}\n\nfunction compensateOptionsKey(options) {\n return JSON.stringify({\n resizeCanvas: Boolean(options.resizeCanvas || options.echarts || options.echartsLib),\n hasLib: Boolean(\n (options.echarts && typeof options.echarts === 'object') || options.echartsLib\n ),\n hasOnRefresh: typeof options.onRefresh === 'function',\n })\n}\n\n/**\n * v-compensate — 挂在「被页面 scale 搞坏」的第三方组件外包一层。\n *\n * 原理与业务 WinRateChart 手写一致(JS 行内,非纯 CSS):\n * transform: scale(inverse); width/height: 100% * pageScale; origin: top left\n *\n * 用法:\n * <div class=\"slot\"><div v-compensate><Whatever /></div></div>\n * <div class=\"slot\"><div v-compensate.resize-canvas><Chart /></div></div>\n *\n * `.resize-canvas` / `{ resizeCanvas: true }`:补偿后通知子树 canvas 重绘\n * (探测 ECharts / Chart.js,并派发 one-screen-scale-canvas-resize)。\n */\nfunction mountCompensate(el) {\n const api = createCompensate(el, () => el.__oneScreenCompensateOptions || {})\n el.__oneScreenCompensateApi = api\n el.__oneScreenCompensateKey = compensateOptionsKey(el.__oneScreenCompensateOptions || {})\n}\n\nexport const vCompensate = {\n mounted(el, binding) {\n el.__oneScreenCompensateOptions = readCompensateOptions(binding)\n mountCompensate(el)\n },\n\n updated(el, binding) {\n const options = readCompensateOptions(binding)\n const key = compensateOptionsKey(options)\n el.__oneScreenCompensateOptions = options\n // resizeCanvas / 图表库变了才重建监听;onRefresh 每次 refresh 现读\n if (el.__oneScreenCompensateKey !== key) {\n el.__oneScreenCompensateApi?.stop()\n mountCompensate(el)\n return\n }\n el.__oneScreenCompensateApi?.refresh()\n },\n\n unmounted(el) {\n el.__oneScreenCompensateApi?.stop()\n delete el.__oneScreenCompensateApi\n delete el.__oneScreenCompensateKey\n delete el.__oneScreenCompensateOptions\n },\n}\n\n/** 别名,与早期注释里的命名一致 */\nexport const vFitCompensate = vCompensate\n","/**\r\n * Vue 3 Composable\r\n * useFitScreen(ref, options) → { scale, inverseScale, refresh }\r\n */\r\nimport { ref, onMounted, onUnmounted, watch } from 'vue'\r\nimport { createScaler, SCALE_CHANGE_EVENT } from './core.js'\r\n\r\nexport function useFitScreen(targetRef, options = {}) {\r\n const scale = ref(1)\r\n const inverseScale = ref(1)\r\n\r\n let scaler = null\r\n let onScale = null\r\n\r\n function setup(el) {\r\n if (!el) return\r\n scaler = createScaler(el, options)\r\n const s = scaler.start()\r\n scale.value = s\r\n inverseScale.value = s > 0 ? 1 / s : 1\r\n\r\n // 图片加载等导致的重算不经过 window.resize,跟页面缩放事件走\r\n onScale = (event) => {\r\n if (event.detail?.el !== el) return\r\n scale.value = event.detail.scale\r\n inverseScale.value = event.detail.inverseScale\r\n }\r\n window.addEventListener(SCALE_CHANGE_EVENT, onScale)\r\n }\r\n\r\n function teardown() {\r\n if (onScale) {\r\n window.removeEventListener(SCALE_CHANGE_EVENT, onScale)\r\n onScale = null\r\n }\r\n scaler?.stop()\r\n scaler = null\r\n }\r\n\r\n // 处理 ref 初始有值的情况\r\n onMounted(() => {\r\n const el = targetRef?.value ?? targetRef\r\n setup(el)\r\n })\r\n\r\n // 处理 ref 延迟赋值的情况(异步挂载)\r\n if (targetRef && typeof targetRef === 'object' && 'value' in targetRef) {\r\n watch(\r\n () => targetRef.value,\r\n (el) => {\r\n if (el && !scaler) setup(el)\r\n }\r\n )\r\n }\r\n\r\n onUnmounted(() => {\r\n teardown()\r\n })\r\n\r\n const refresh = () => {\r\n const el = targetRef?.value ?? targetRef\r\n if (!el || !scaler) return\r\n const s = scaler.refresh()\r\n scale.value = s\r\n inverseScale.value = s > 0 ? 1 / s : 1\r\n }\r\n\r\n return { scale, inverseScale, refresh }\r\n}\r\n"],"names":["STYLE_ELEMENT_ID","BASE_CLASS","contain","compensate","BASE_CSS","trim","ensureBaseStyleSheet","document","styleEl","getElementById","textContent","createElement","id","head","appendChild","applyBaseStyles","el","mode","classList","nextClass","forEach","cls","remove","add","removeBaseStyles","resolveEl","querySelector","HTMLElement","value","current","calculateScale","sourceWidth","sourceHeight","targetWidth","window","innerWidth","targetHeight","innerHeight","visualWidth","scale","sx","sy","Math","min","SCALE_CHANGE_EVENT","applyScale","origin","target","style","transform","transformOrigin","inv","setProperty","String","dispatchEvent","CustomEvent","detail","inverseScale","getPageScale","t","getComputedStyle","m2","match","parseFloat","m3","sm","vals","split","map","v","length","createScaler","options","Error","autoResize","injectBaseStyles","observeContent","currentScale","resizeHandler","loadHandler","windowLoadHandler","rafId","unlockRaf","ro","refreshing","lastMeasured","w","h","session","savedInline","width","height","refresh","next","sw","offsetWidth","sh","offsetHeight","tw","documentElement","clientWidth","th","compute","nextW","nextH","round","token","cancelAnimationFrame","requestAnimationFrame","scheduleRefresh","onWindowResize","start","addEventListener","ResizeObserver","observe","e","tagName","fonts","ready","then","catch","readyState","once","stop","removeEventListener","disconnect","removeProperty","getScale","CANVAS_RESIZE_EVENT","registeredEcharts","readCssVarScale","NaN","raw","getPropertyValue","readTransformScale","resolvePageScale","fromEl","node","nodeType","fromVar","parentElement","__oneScreenCompensate","fromTf","applyCompensateTransform","overflow","clearCompensateTransform","boxSize","max","tryEchartsResize","getInst","inst","resize","tryChartJsResize","canvas","Chart","globalThis","getChart","chart","resizeCanvasUnder","echartsLib","echarts","getInstanceByDom","count","canvases","querySelectorAll","host","bubbles","nodes","wantsResizeCanvas","Boolean","resizeCanvas","resolveBoundEcharts","readLiveOptions","createCompensate","wantResize","raf","mo","retryTimers","stopped","clearRetries","clearTimeout","live","onRefresh","lib","delay","setTimeout","push","schedule","MutationObserver","childList","subtree","readOptions","binding","mountScaler","scaler","__fitScreenScaler","__fitScreenOptionsKey","JSON","stringify","unmountScaler","vFitScreen","mounted","updated","key","unmounted","readCompensateOptions","modifiers","compensateOptionsKey","hasLib","hasOnRefresh","mountCompensate","api","__oneScreenCompensateOptions","__oneScreenCompensateApi","__oneScreenCompensateKey","vCompensate","vFitCompensate","s","targetRef","ref","onScale","setup","event","onMounted","watch","onUnmounted"],"mappings":"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"}