@antv/s2
Version:
effective spreadsheet render core lib
117 lines • 5.67 kB
JavaScript
// ==================== 通用工具函数 ====================
import { __awaiter } from "tslib";
import { get } from 'lodash';
import { CellType, S2Event, S2_PREFIX_CLS } from '../../../common/constant';
import { CellRendererType } from '../../../common/constant/renderer';
import { BaseEvent } from '../../../interaction/base-event';
import { asyncDrawImage, getPreparedText, } from '../../../utils/cell/customRenderer';
// 1. 创建蒙版层
const createPreviewOverlay = (overlayStyle) => {
const overlay = document.createElement('div');
Object.assign(overlay.style, Object.assign({ width: '100vw', height: '100vh', position: 'fixed', top: '0', left: '0', backgroundColor: 'rgba(30, 30, 30, 0.5)', display: 'flex', justifyContent: 'center', alignItems: 'center', overflow: 'hidden', zIndex: '9999', cursor: 'pointer', touchAction: 'none', backdropFilter: 'blur(2px)', pointerEvents: 'auto' }, overlayStyle));
overlay.className = `${S2_PREFIX_CLS}-preview-overlay`;
return overlay;
};
// 2. 通用媒体容器样式
const applyMediaContainerStyle = (element, mediaContainerStyle) => {
const isPortrait = window.matchMedia('(orientation: portrait)').matches;
// 根据横竖屏切换
const maxSize = isPortrait ? '90vw' : '90vh';
const minSize = isPortrait ? '60vw' : '60vh';
Object.assign(element.style, Object.assign({ maxWidth: maxSize, maxHeight: maxSize, minHeight: minSize, minWidth: minSize, objectFit: 'contain' }, mediaContainerStyle));
};
// ==================== 工厂函数 ====================
const createImageElement = (options) => __awaiter(void 0, void 0, void 0, function* () {
const { src, mediaContainerStyle, config } = options;
const img = yield asyncDrawImage({
src,
fallback: config === null || config === void 0 ? void 0 : config.fallback,
timeout: config === null || config === void 0 ? void 0 : config.timeout,
});
applyMediaContainerStyle(img, mediaContainerStyle);
img.alt = 'preview';
return img;
});
const createVideoElement = (src, mediaContainerStyle) => {
const video = document.createElement('video');
video.src = src;
video.controls = true;
video.preload = 'auto';
video.playsInline = true;
// iOS 兼容
video.setAttribute('webkit-playsinline', 'true');
video.setAttribute('playsinline', 'true');
applyMediaContainerStyle(video, mediaContainerStyle);
return video;
};
// ==================== 主逻辑 ====================
export const bindMediaClick = (cell) => __awaiter(void 0, void 0, void 0, function* () {
const renderer = cell.getRenderer();
const { type, prepareText } = renderer;
const src = yield getPreparedText(prepareText, cell.getFieldValue().toString());
if (renderer.clickToPreview === false ||
![CellRendererType.IMAGE, CellRendererType.VIDEO].includes(renderer.type)) {
return;
}
// 创建蒙版和媒体元素
const previewTheme = cell.getStyle('preview');
const overlay = createPreviewOverlay(previewTheme === null || previewTheme === void 0 ? void 0 : previewTheme.overlay);
const mediaElement = type === CellRendererType.IMAGE
? yield createImageElement({
src,
mediaContainerStyle: previewTheme === null || previewTheme === void 0 ? void 0 : previewTheme.mediaContainer,
config: renderer,
})
: createVideoElement(src, previewTheme === null || previewTheme === void 0 ? void 0 : previewTheme.mediaContainer);
// 统一事件处理(支持触控)
const handleClose = (e) => {
// 关键:阻止所有事件传播和默认行为
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
if (e.target === overlay) {
document.body.removeChild(overlay);
mediaElement.remove();
// 恢复滚动
document.body.style.overflow = 'auto';
}
};
// 避免移动端误触
setTimeout(() => {
['click', 'touchstart', 'touchend'].forEach((eventType) => {
overlay.addEventListener(eventType, handleClose, { passive: false });
});
}, 500);
// 禁止背景滚动
document.body.style.overflow = 'hidden';
overlay.appendChild(mediaElement);
document.body.appendChild(overlay);
});
export class PreviewClick extends BaseEvent {
bindEvents() {
const events = [
S2Event.DATA_CELL_CLICK,
S2Event.ROW_CELL_CLICK,
S2Event.COL_CELL_CLICK,
];
events.forEach((eventType) => {
this.spreadsheet.on(eventType, (event) => this.bindMediaCellClick(event));
});
}
bindMediaCellClick(event) {
var _a, _b, _c, _d;
const cell = this.spreadsheet.getCell(event.target);
const cellRendererType = (_b = (_a = cell === null || cell === void 0 ? void 0 : cell.getRenderer) === null || _a === void 0 ? void 0 : _a.call(cell)) === null || _b === void 0 ? void 0 : _b.type;
if (cellRendererType === CellRendererType.IMAGE &&
get(event.target, 'nodeName') !== 'image') {
// 如果点击的位置并不是图片,则不预览
return;
}
if (((_d = (_c = cell === null || cell === void 0 ? void 0 : cell.getRenderer) === null || _c === void 0 ? void 0 : _c.call(cell)) === null || _d === void 0 ? void 0 : _d.type) &&
(this.spreadsheet.isPivotMode() || cell.cellType !== CellType.COL_CELL)) {
this.spreadsheet.emit(S2Event.GLOBAL_PREVIEW_CLICK, event);
bindMediaClick(cell);
}
}
}
//# sourceMappingURL=preview-click.js.map