ThreeJS 实现精灵标签方法
最近开发一个功能,在3D楼层模型上显示房间名称,方案选型有 CSS3DSprite、ToolTip、Sprite有三种。CSS3DSprite、ToolTip属于插入DIV元素,实现简单,但缩放及界面尺寸变化时标签和房间相对位置发生改变,放弃。Sprite 精灵模型是 ThreeJS 3D 一种对象,优点是缩放时定位精准,缺点是精灵模型不能设置长宽、Canvas 文本失真、文本长度不能根据文字长度自适应。
通过实践发现,Sprite 的缺点可以完美解决。Sprite可以设置缩放,其长宽缩放比和Canvas长宽保持一致,即能实现自适应文本长度且不失真。具体实现代码如下:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115import * as THREE from 'three';
/**
* 创建精灵标签
* @param {*} text 标签名称
* @param {*} position 标签位置
* @param {*} options 标签配置
* @returns
*/
export default function createSpriteLabel(text, position = [0, 0, 0], options = {}) {
// 默认配置
const defaultOptions = {
zoom: true,
// 标签
font: '500 48px microsoft yahei',
color: 'white',
TextHeight: 80,
textPadding: 12, // 左右 padding
backgroundColor: 'rgba(21, 23, 30, 0.8)',
// 包角线
cornerLineColor: '#24cdff',
cornerLineWidth: 8,
cornerLineLenghtScale: 0.3,
};
// eslint-disable-next-line no-param-reassign
options = Object.assign(defaultOptions, options);
if (!options.scale) {
options.scale = options.zoom ? 5 : 0.04;
}
// 创建画布并设置宽高
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
ctx.font = options.font;
const textWidth = ctx.measureText(text).width;
const width = textWidth + options.textPadding * 2;
const height = options.TextHeight;
canvas.width = width;
canvas.height = height;
// 设置标签背景
ctx.fillStyle = options.backgroundColor;
ctx.fillRect(0, 0, width, height);
// 设置背景包角线
let len = (width * options.cornerLineLenghtScale) / (width / height);
ctx.strokeStyle = options.cornerLineColor;
ctx.lineWidth = options.cornerLineWidth;
const lines = [
// 左上顶点
[
[0, 0],
[0, 0 + len],
],
[
[0, 0],
[len, 0],
],
// 右下顶点
[
[width, height],
[width, height - len],
],
[
[width, height],
[width - len, height],
],
// 右上顶点
[
[width, 0],
[width, len],
],
[
[width - len, 0],
[width, 0],
],
// 左下顶点
[
[0, height],
[len, height],
],
[
[0, height],
[0, height - len],
],
];
const drawLine = (ctx, [startX, startY], [endX, endY]) => {
ctx.beginPath();
ctx.moveTo(startX, startY);
ctx.lineTo(endX, endY);
ctx.stroke();
};
lines.map((it) => {
drawLine(ctx, it[0], it[1]);
});
// 设置标签(居中)
ctx.font = options.font;
ctx.fillStyle = options.color;
ctx.textBaseline = 'middle';
ctx.textAlign = 'center';
ctx.fillText(text, width / 2, height / 2 + 4);
// 创建精灵
const texture = new THREE.Texture(canvas);
texture.needsUpdate = true;
const material = new THREE.SpriteMaterial({ map: texture });
material.sizeAttenuation = options.zoom; // 控制标签缩放
const sprite = new THREE.Sprite(material);
sprite.scale.set(options.scale * (width / height), options.scale, 1);
sprite.position.set(...position);
return sprite;
}
实现效果如下:
JavaScript 代码整洁
雪花 loading 实现归档
评论
即可发布评论!
文章29
分类13
标签7
博客之家
一个优雅的写作平台
一个优雅的写作平台