| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283 |
- /**
- * 单行长文本省略的**唯一一份契约**(票 37)。
- *
- * 维护者 2026-10-13 反馈:「文本过长显示不全,需要一个**共用方法**在所有类似位置统一处理
- * (溢出省略成 `…`,hover 显示完整)。」这句话里其实是两件事,各自只能有一处实现:
- *
- * ① **画省略标记** —— 归 CSS 的 `text-overflow: ellipsis`,声明在
- * `components/EllipsisText.vue` 的 `.ellipsis-text` 里(全仓面板文字仅此一份)。
- * 为什么**不**用 JS 按字符数预截:字符数 ≠ 像素宽度(中英文混排、等宽数字都不同),
- * 两份截断规则必然出现「JS 已截掉但 CSS 还能显示更多」或反过来的不一致 ——
- * 那正是本票要根除的「早晚不一致」。标记让平台按**真实宽度**画,永远只有一套。
- *
- * ② **留完整原文** —— 归本文件的 `ellipsisTitle()`:`title` 里放的是**未截断的原文**,
- * 所以无论列宽多窄,鼠标悬停都能读到全(这才是维护者要的「hover 显示完整」)。
- *
- * 两半合起来即「对超长文本给出省略标记、同时保留完整原文」:标记由平台画,
- * 原文由 title 承载,两者不会各自漂移。
- *
- * 本文件是纯函数层(票 05 的静态守卫:不 import service、不碰 DOM、不发请求)。
- */
- /** 省略标记字符(与 CSS `text-overflow: ellipsis` 画出的那一个一致,供断言与文案对齐)。 */
- export const ELLIPSIS_MARK = '…'
- /** 任意值 → 一行纯文本;`null`/`undefined` 回空串(绝不把 `null` 字面量画到界面上)。 */
- export function plainText(value) {
- if (value === null || value === undefined) return ''
- return String(value)
- }
- /**
- * `title` 的取值:**完整原文**,一个字符都不截。
- * 空文本回空串 —— 空 title 会让浏览器弹一个空提示框,那不是「显示完整」。
- */
- export function ellipsisTitle(value) {
- return plainText(value)
- }
- /**
- * 省略展示契约:`text` 是**显示串**(原样,省略标记归 CSS 按真实宽度画),
- * `title` 是**完整原文**(hover 读全)。两个字段同源,因此不会出现「显示的是甲、提示的是乙」。
- * @param {*} value 待显示文本(数字/字符串/空值都收)
- * @returns {{ text: string, title: string }}
- */
- export function ellipsisView(value) {
- const text = plainText(value)
- return { text, title: text }
- }
- /**
- * 地图标签的省略(批次 3 走查接通,2026-10-12)。
- *
- * 与上面 DOM 契约是**同一份语义**、不同渲染媒介:
- * · DOM 侧(`EllipsisText.vue`)—— 省略标记归 CSS `text-overflow`,title 归属性;
- * · Canvas 侧(Cesium billboard label)—— CSS 够不着画布内部,截断归
- * `services/cesiumEngine.js` 的估算字宽逻辑(`mapTextLabel` 的 `maxWidthPx`),
- * 完整原文归实体 properties(`pointName`/`deviceName`)+ mapService 的
- * hover tooltip(`data-map-marker-tooltip`)。
- * 两边共用 `ELLIPSIS_MARK`,保证省略标记字符全仓一致;任何一侧改省略字符都要过这里。
- *
- * @param {string} text 完整原文
- * @param {number} maxWidthPx 屏显限宽(px)
- * @param {number} fontSizePx 字号(估算字宽用:全角 ≈ fontSize、半角 ≈ 一半)
- * @returns {{ shown: string, truncated: boolean, title: string }} shown=截断显示串(含省略号)
- */
- export function ellipsisForMapLabel(text, maxWidthPx, fontSizePx = 12) {
- const full = plainText(text)
- if (!full || maxWidthPx <= 0) return { shown: full, truncated: false, title: full }
- const charW = (ch) => (ch.charCodeAt(0) > 0x2e7f ? fontSizePx : fontSizePx / 2)
- const ellipsisW = fontSizePx
- // 先量全文:放得下就不截(临界文本不被省略号预留宽度误伤)。
- let fullW = 0
- for (let i = 0; i < full.length; i++) fullW += charW(full[i])
- if (fullW <= maxWidthPx) return { shown: full, truncated: false, title: full }
- // 放不下:截到 (limit - 省略号宽) 再补 …
- let acc = 0
- let cut = 0
- for (let i = 0; i < full.length; i++) {
- acc += charW(full[i])
- if (acc > maxWidthPx - ellipsisW) { cut = i; break }
- }
- return { shown: `${full.slice(0, cut)}${ELLIPSIS_MARK}`, truncated: true, title: full }
- }
|