/*! * @antv/g-plugin-html-renderer * @description A G plugin for rendering HTML * @version 2.1.27 * @date 7/30/2025, 1:35:48 PM * @author AntVis * @docs https://g.antv.antgroup.com/ */ 'use strict'; var _classCallCheck = require('@babel/runtime/helpers/classCallCheck'); var _createClass = require('@babel/runtime/helpers/createClass'); var _callSuper = require('@babel/runtime/helpers/callSuper'); var _inherits = require('@babel/runtime/helpers/inherits'); var gLite = require('@antv/g-lite'); var util = require('@antv/util'); var CANVAS_CAMERA_ID = 'g-canvas-camera'; var HTMLRenderingPlugin = /*#__PURE__*/function () { function HTMLRenderingPlugin() { _classCallCheck(this, HTMLRenderingPlugin); this.displayObjectHTMLElementMap = new WeakMap(); } return _createClass(HTMLRenderingPlugin, [{ key: "joinTransformMatrix", value: /** * ! The reason for adding `offset` is that the `transform-origin` coordinate system of DOM is the local coordinate system of the element, while the `transform-origin` coordinate system of canvas drawing is the local coordinate system of the element's parent element. At the same time, the `transform` attribute value of the DOM element does not include `transform-origin`. */ function joinTransformMatrix(matrix) { var offset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [0, 0, 0]; return "matrix(".concat([matrix[0], matrix[1], matrix[4], matrix[5], matrix[12] + offset[0], matrix[13] + offset[1]].join(','), ")"); } }, { key: "apply", value: function apply(context, runtime) { var _this = this; var camera = context.camera, renderingContext = context.renderingContext, renderingService = context.renderingService; this.context = context; var canvas = renderingContext.root.ownerDocument.defaultView; var nativeHTMLMap = canvas.context.eventService.nativeHTMLMap; var setTransform = function setTransform(object, $el) { $el.style.transform = _this.joinTransformMatrix(object.getWorldTransform(), object.getOrigin()); }; var handleMounted = function handleMounted(e) { var object = e.target; if (object.nodeName === gLite.Shape.HTML) { if (!_this.$camera) { _this.$camera = _this.createCamera(camera); } // create DOM element var $el = _this.getOrCreateEl(object); _this.$camera.appendChild($el); Object.keys(object.attributes).forEach(function (name) { _this.updateAttribute(name, object); }); setTransform(object, $el); nativeHTMLMap.set($el, object); } }; var handleUnmounted = function handleUnmounted(e) { var object = e.target; if (object.nodeName === gLite.Shape.HTML && _this.$camera) { var $el = _this.getOrCreateEl(object); if ($el) { $el.remove(); nativeHTMLMap["delete"]($el); } } }; var handleAttributeChanged = function handleAttributeChanged(e) { var object = e.target; if (object.nodeName === gLite.Shape.HTML) { var attrName = e.attrName; _this.updateAttribute(attrName, object); } }; var handleBoundsChanged = function handleBoundsChanged(e) { var object = e.target; var nodes = object.nodeName === gLite.Shape.FRAGMENT ? object.childNodes : [object]; nodes.forEach(function (node) { if (node.nodeName === gLite.Shape.HTML) { var $el = _this.getOrCreateEl(node); setTransform(node, $el); } }); }; var handleCanvasResize = function handleCanvasResize() { if (_this.$camera) { var _this$context$config = _this.context.config, width = _this$context$config.width, height = _this$context$config.height; _this.$camera.parentElement.style.width = "".concat(width || 0, "px"); _this.$camera.parentElement.style.height = "".concat(height || 0, "px"); } }; renderingService.hooks.init.tap(HTMLRenderingPlugin.tag, function () { canvas.addEventListener(gLite.CanvasEvent.RESIZE, handleCanvasResize); canvas.addEventListener(gLite.ElementEvent.MOUNTED, handleMounted); canvas.addEventListener(gLite.ElementEvent.UNMOUNTED, handleUnmounted); canvas.addEventListener(gLite.ElementEvent.ATTR_MODIFIED, handleAttributeChanged); canvas.addEventListener(gLite.ElementEvent.BOUNDS_CHANGED, handleBoundsChanged); }); renderingService.hooks.endFrame.tap(HTMLRenderingPlugin.tag, function () { if (_this.$camera && renderingContext.renderReasons.has(gLite.RenderReason.CAMERA_CHANGED)) { _this.$camera.style.transform = _this.joinTransformMatrix(camera.getOrthoMatrix()); } }); renderingService.hooks.destroy.tap(HTMLRenderingPlugin.tag, function () { // remove camera if (_this.$camera) { _this.$camera.remove(); } canvas.removeEventListener(gLite.CanvasEvent.RESIZE, handleCanvasResize); canvas.removeEventListener(gLite.ElementEvent.MOUNTED, handleMounted); canvas.removeEventListener(gLite.ElementEvent.UNMOUNTED, handleUnmounted); canvas.removeEventListener(gLite.ElementEvent.ATTR_MODIFIED, handleAttributeChanged); canvas.removeEventListener(gLite.ElementEvent.BOUNDS_CHANGED, handleBoundsChanged); }); } }, { key: "createCamera", value: function createCamera(camera) { var _this$context$config2 = this.context.config, doc = _this$context$config2.document, width = _this$context$config2.width, height = _this$context$config2.height; var $canvas = this.context.contextService.getDomElement(); var $container = $canvas.parentNode; if ($container) { var cameraId = CANVAS_CAMERA_ID; var $existedCamera = $container.querySelector("#".concat(cameraId)); if (!$existedCamera) { // fix @see https://github.com/antvis/G/issues/1702 var $cameraContainer = (doc || document).createElement('div'); // HTML elements should not overflow with canvas @see https://github.com/antvis/G/issues/1163 $cameraContainer.style.overflow = 'hidden'; $cameraContainer.style.pointerEvents = 'none'; $cameraContainer.style.position = 'absolute'; $cameraContainer.style.left = "0px"; $cameraContainer.style.top = "0px"; $cameraContainer.style.width = "".concat(width || 0, "px"); $cameraContainer.style.height = "".concat(height || 0, "px"); var $camera = (doc || document).createElement('div'); $existedCamera = $camera; $camera.id = cameraId; // use absolute position $camera.style.position = 'absolute'; // account for DOM element's offset @see https://github.com/antvis/G/issues/1150 $camera.style.left = "".concat($canvas.offsetLeft || 0, "px"); $camera.style.top = "".concat($canvas.offsetTop || 0, "px"); $camera.style.transformOrigin = 'left top'; $camera.style.transform = this.joinTransformMatrix(camera.getOrthoMatrix()); $camera.style.pointerEvents = 'none'; $camera.style.width = "100%"; $camera.style.height = "100%"; $cameraContainer.appendChild($camera); $container.appendChild($cameraContainer); } return $existedCamera; } return null; } }, { key: "getOrCreateEl", value: function getOrCreateEl(object) { var doc = this.context.config.document; var $existedElement = this.displayObjectHTMLElementMap.get(object); if (!$existedElement) { $existedElement = (doc || document).createElement('div'); object.parsedStyle.$el = $existedElement; this.displayObjectHTMLElementMap.set(object, $existedElement); if (object.id) { $existedElement.id = object.id; } if (object.name) { $existedElement.setAttribute('name', object.name); } if (object.className) { $existedElement.className = object.className; } // use absolute position $existedElement.style.position = 'absolute'; // @see https://github.com/antvis/G/issues/1150 $existedElement.style['will-change'] = 'transform'; $existedElement.style.transform = this.joinTransformMatrix(object.getWorldTransform(), object.getOrigin()); } return $existedElement; } }, { key: "updateAttribute", value: function updateAttribute(name, object) { var $el = this.getOrCreateEl(object); switch (name) { case 'innerHTML': var innerHTML = object.parsedStyle.innerHTML; if (util.isString(innerHTML)) { $el.innerHTML = innerHTML; } else { $el.innerHTML = ''; $el.appendChild(innerHTML); } break; case 'x': $el.style.left = "".concat(object.parsedStyle.x, "px"); break; case 'y': $el.style.top = "".concat(object.parsedStyle.y, "px"); break; case 'transformOrigin': var transformOrigin = object.parsedStyle.transformOrigin; $el.style['transform-origin'] = "".concat(transformOrigin[0].buildCSSText(null, null, ''), " ").concat(transformOrigin[1].buildCSSText(null, null, '')); break; case 'width': var width = object.parsedStyle.width; $el.style.width = util.isNumber(width) ? "".concat(width, "px") : width.toString(); break; case 'height': var height = object.parsedStyle.height; $el.style.height = util.isNumber(height) ? "".concat(height, "px") : height.toString(); break; case 'zIndex': var zIndex = object.parsedStyle.zIndex; $el.style['z-index'] = "".concat(zIndex); break; case 'visibility': var visibility = object.parsedStyle.visibility; $el.style.visibility = visibility; break; case 'pointerEvents': var _object$parsedStyle$p = object.parsedStyle.pointerEvents, pointerEvents = _object$parsedStyle$p === void 0 ? 'auto' : _object$parsedStyle$p; $el.style.pointerEvents = pointerEvents; break; case 'opacity': var opacity = object.parsedStyle.opacity; $el.style.opacity = "".concat(opacity); break; case 'fill': var fill = object.parsedStyle.fill; var color = ''; if (gLite.isCSSRGB(fill)) { if (fill.isNone) { color = 'transparent'; } else { color = object.getAttribute('fill'); } } else if (Array.isArray(fill)) { color = object.getAttribute('fill'); } else if (gLite.isPattern(fill)) ; $el.style.background = color; break; case 'stroke': var stroke = object.parsedStyle.stroke; var borderColor = ''; if (gLite.isCSSRGB(stroke)) { if (stroke.isNone) { borderColor = 'transparent'; } else { borderColor = object.getAttribute('stroke'); } } else if (Array.isArray(stroke)) { borderColor = object.getAttribute('stroke'); } else if (gLite.isPattern(stroke)) ; $el.style['border-color'] = borderColor; $el.style['border-style'] = 'solid'; break; case 'lineWidth': var lineWidth = object.parsedStyle.lineWidth; $el.style['border-width'] = "".concat(lineWidth || 0, "px"); break; case 'lineDash': $el.style['border-style'] = 'dashed'; break; case 'filter': var filter = object.style.filter; $el.style.filter = filter; break; default: if (!util.isNil(object.style[name]) && object.style[name] !== '') { $el.style[name] = object.style[name]; } } } }]); }(); HTMLRenderingPlugin.tag = 'HTMLRendering'; var Plugin = /*#__PURE__*/function (_AbstractRendererPlug) { function Plugin() { var _this; _classCallCheck(this, Plugin); for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _callSuper(this, Plugin, [].concat(args)); _this.name = 'html-renderer'; return _this; } _inherits(Plugin, _AbstractRendererPlug); return _createClass(Plugin, [{ key: "init", value: function init() { this.addRenderingPlugin(new HTMLRenderingPlugin()); } }, { key: "destroy", value: function destroy() { this.removeAllRenderingPlugins(); } }]); }(gLite.AbstractRendererPlugin); exports.Plugin = Plugin; //# sourceMappingURL=index.js.map