Loading...
有时我们需要在画布上增加一些 HUD(Head-Up Display),例如 Tooltip。此时用 HTML + CSS 展现相比使用基础图形绘制有以下优势:
<input>
<select>
HTML 内容以及宽高为必填项,其中 HTML 内容可以为字符串或者 HTMLElement:
const html = new HTML({style: {x: 0,y: 0,width: 100,height: 100,innerHTML: '<h1>This is Title</h1>',},});canvas.appendChild(html);
之所以一定要指定宽高(至少是初始宽高),是由于 SVG 的 <foreignObject> 元素必须指定否则无法显示。
在实现中 g-canvas/webgl 会将 HTML 内容包裹在 <div>
中,以 <canvas>
的兄弟节点放在容器内。而在 g-svg 中使用 <foreignObject>
包裹内容:
// g-canvas/webgl 的 DOM 结构<div id="container"><canvas></canvas><div name="容器元素"><!-- content --></div></div>// g-svg 的 DOM 结构<div id="container"><svg><foreignObject name="容器元素"><!-- content --></foreignObject></svg></div>
其中的 id,name,className 如果传入都会被应用在容器元素上,因此有两种方式获取到容器元素:
getElementById
这样的 DOM API 获取其他样式属性通过 CSS 应用。
对应 CSS background 属性。
对应 CSS border-color 属性。
对应 CSS border-width 属性。
对应 CSS border-style 属性。
使用 dashed
值,但无法精确控制 dash
和 gap
的长度。
对应 CSS opacity 属性。
对应 CSS visibility 属性。
对应 CSS pointer-events 属性。
当我们在实现类似 tooltip 这样的需求时,可以让鼠标事件穿透它,示例:
const tooltip = new HTML({style: {x: 0,y: 0,innerHTML: 'Tooltip',fill: 'white',stroke: 'black',lineWidth: 6,width: 100,height: 30,pointerEvents: 'none', // 让事件穿透它visibility: 'hidden',},});
对应 CSS transform 属性。
使用生成全局坐标系下的 matrix 字符串形式。
对应 CSS transform-origin 属性。
局部坐标系下,容器左上角顶点的 x 轴坐标。
https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute/x
初始值 | 适用元素 | 是否可继承 | 是否支持动画 | 计算值 |
---|---|---|---|---|
'0' | - | 否 | 是 | <percentage> <length> |
局部坐标系下,容器左上角顶点的 y 轴坐标。
https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute/y
初始值 | 适用元素 | 是否可继承 | 是否支持动画 | 计算值 |
---|---|---|---|---|
'0' | - | 否 | 是 | <percentage> <length> |
类型: string | HTMLElement
默认值:无
是否必须:true
说明:HTML 内容,可以为字符串或者 HTMLElement
const html = new HTML({style: {width: 100,height: 100,innerHTML: '<h1>This is Title</h1>',// innerHTML: 'content',// innerHTML: document.createElement('div'),},});html.style.innerHTML = '<h1>This is Title</h1>';
容器宽度,默认值为 'auto'
。
https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute/width
初始值 | 适用元素 | 是否可继承 | 是否支持动画 | 计算值 |
---|---|---|---|---|
'0' | - | 否 | 是 | <percentage> <length> |
容器宽度,默认值为 'auto'
。
https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute/height
初始值 | 适用元素 | 是否可继承 | 是否支持动画 | 计算值 |
---|---|---|---|---|
'0' | - | 否 | 是 | <percentage> <length> |
CSS 属性将被透传并直接应用到 DOM 容器的 style 上,在下面的示例中,fontSize
textAlign
color
等 CSS 属性将直接体现在样式上:
const html = new HTML({style: {x: 200,y: 100,width: 200,height: 200,innerHTML: 'p1',// The followin will override the CSS properties.fontSize: '20px',textAlign: 'center',color: 'red',},});
获取容器元素,例如在 g-canvas/webgl 中会得到 <div>
,而在 g-svg 中会得到 <foreignObject>
:
// g-canvas/webglconst $div = html.getDomElement(); // HTMLDivElement// g-svgconst $foreignObject = html.getDomElement(); // <foreignObject>
绝大部分场景图能力都可以在 HTML 上使用,例如变换操作:
html.translate(100, 0); // 平移html.scale(2); // 缩放html.rotate(30); // 旋转
在获取包围盒时,我们会使用原生 DOM API getBoundingClientRect,因此在首次渲染完成之前调用会得到不正确的结果。
对于 HTML 元素,添加其他基础图形作为它的子元素意义不大。此时可以使用 getDomElement 获取容器元素后再进行后续的 DOM 操作,例如添加子节点:
const $div = document.createElement('div');// wronghtml.appendChild($div);// correcthtml.getDomElement().appendChild($div);
隐藏展示都可以正常使用:
html.show();html.style.visibility = 'visible';html.hide();html.style.visibility = 'hidden';
但是在通过 z-index 指定渲染顺序时,受限于具体实现,仅在各个 HTML 内容间生效。在下面的例子中,html1 无法在 circle1 和 circle2 之间展示:
// 在 <canvas> 中渲染的两个 circlecircle1.style.zIndex = 1;circle2.style.zIndex = 3;html1.style.zIndex = 2;html2.style.zIndex = 100;
由于 foreignObject 需要指定宽高才能渲染,在创建时指定后也可以进行修改:
html.style.width = 100;html.style.height = 100;
目前其他基础图形动画都是通过 Keyframe 插值后重绘完成。对于 HTML 图形,理想状况显然是直接使用 CSS Animation。