You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
319 lines
13 KiB
319 lines
13 KiB
/*!
|
|
* @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
|
|
|