UNPKG

@antv/s2

Version:

effective spreadsheet render core lib

144 lines 5.72 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.GuiIcon = void 0; /** * @description: 请严格要求 svg 的 viewBox,若设计产出的 svg 不是此规格,请叫其修改为 '0 0 1024 1024' */ const g_1 = require("@antv/g"); const lodash_1 = require("lodash"); const engine_1 = require("../../engine"); const debug_1 = require("../debug"); const factory_1 = require("./factory"); const STYLE_PLACEHOLDER = '<svg'; const SVG_CONTENT_TYPE = 'data:image/svg+xml'; // Image 缓存 const ImageCache = {}; /** * 使用 iconfont 上的 svg 来创建 Icon */ class GuiIcon extends g_1.Group { constructor(cfg) { super({ name: cfg.name }); /** * 1. https://xxx.svg * 2. http://xxx.svg * 3. //xxx.svg */ this.isOnlineLink = (src) => /^(?:https?:)?(?:\/\/)/.test(src); this.cfg = cfg; this.render(); } getCfg() { return this.cfg; } // 获取 Image 实例,使用缓存,以避免滚动时因重复的 new Image() 耗时导致的闪烁问题 /* 异步获取 image 实例 */ getImage(name, cacheKey, fill) { return new Promise((resolve, reject) => { let svg = (0, factory_1.getIcon)(name); if (!svg) { return; } const img = new Image(); img.onload = () => { ImageCache[cacheKey] = img; resolve(img); }; img.onerror = reject; /* * 兼容三种情况 * 1、base 64 * 2、svg本地文件(兼容老方式,可以改颜色) * 3、线上支持的图片地址 */ if (svg && (svg.includes(SVG_CONTENT_TYPE) || this.isOnlineLink(svg))) { /* * 传入 base64 字符串 * 或者 online 链接 */ img.src = svg; // https://github.com/antvis/S2/issues/2513 img.crossOrigin = 'anonymous'; } else { // 传入 svg 字符串(支持颜色fill) if (fill) { /* * 如果有fill,移除原来的 fill * 这里有一个潜在的问题,不同的svg里面的schema不尽相同,导致这个正则考虑不全 * 1、fill='' 2、fill 3、fill-***(不需要处理) */ // 移除 fill="red|#fff" // eslint-disable-next-line no-useless-escape svg = svg.replace(/fill=[\'\"]#?\w+[\'\"]/g, ''); // fill> 替换为 > svg = svg.replace(/fill>/g, '>'); } svg = svg.replace(STYLE_PLACEHOLDER, `${STYLE_PLACEHOLDER} fill="${fill}"`); /** * 兼容 Firefox: https://github.com/antvis/S2/issues/1571 https://stackoverflow.com/questions/30733607/svg-data-image-not-working-as-a-background-image-in-a-pseudo-element/30733736#30733736 * https://www.chromestatus.com/features/5656049583390720 */ img.src = `${SVG_CONTENT_TYPE};utf-8,${encodeURIComponent(svg)}`; } }); } render() { const { name, fill } = this.cfg; const attrs = (0, lodash_1.clone)(this.cfg); const image = new engine_1.CustomImage(GuiIcon.type, { style: (0, lodash_1.omit)(attrs, 'fill'), }); this.iconImageShape = image; this.setImageAttrs({ name, fill }); } setImageAttrs(attrs) { let { name, fill } = attrs; const { iconImageShape: image } = this; // 保证 name 和 fill 都有值 name = name || this.cfg.name; fill = fill || this.cfg.fill; const cacheKey = `${name}-${fill}`; const imgCache = ImageCache[cacheKey]; if (imgCache) { // already in cache image.attr('src', imgCache); this.appendChild(image); } else { this.getImage(name, cacheKey, fill) .then((img) => { // 异步加载完成后,当前 Cell 可能已经销毁了 if (this.destroyed) { debug_1.DebuggerUtil.getInstance().logger(`GuiIcon ${name} destroyed.`); return; } image.attr('src', img); this.appendChild(image); }) .catch((event) => { // 如果是 TypeError, 则是 G 底层渲染有问题, 其他场景才报加载异常的错误 if (event instanceof TypeError) { // eslint-disable-next-line no-console console.warn(`GuiIcon ${name} destroyed:`, event); return; } // eslint-disable-next-line no-console console.error(`GuiIcon ${name} load failed:`, event); }); } } /** * https://github.com/antvis/S2/issues/2772 * G 6.0 如果是多图层, 需要手动全部隐藏, 直接隐藏父容器 Group 还不行, 或者使用 icon.show() * https://github.com/antvis/G/blob/277abff24936ef6f7c43407a16c5bc9260992511/packages/g-lite/src/display-objects/DisplayObject.ts#L853 */ toggleVisibility(visible) { const status = visible ? 'visible' : 'hidden'; this.setAttribute('visibility', status); this.iconImageShape.setAttribute('visibility', status); } } exports.GuiIcon = GuiIcon; GuiIcon.type = '__GUI_ICON__'; //# sourceMappingURL=gui-icon.js.map