three-base 2.0.1 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ApngTexture.d.ts +13 -0
- package/ApngTexture.js +61 -0
- package/ApngTexture.ts +91 -0
- package/ApngTextureManage.d.ts +18 -0
- package/ApngTextureManage.js +87 -0
- package/ApngTextureManage.ts +130 -0
- package/EventMesh.d.ts +18 -0
- package/EventMesh.js +59 -0
- package/EventMesh.ts +79 -0
- package/ExtrudeMesh.d.ts +111 -0
- package/ExtrudeMesh.js +363 -0
- package/ExtrudeMesh.ts +571 -0
- package/FPScontrol.d.ts +44 -0
- package/FPScontrol.js +170 -0
- package/FPScontrol.ts +209 -0
- package/InstancedGroupMesh.d.ts +10 -0
- package/InstancedGroupMesh.js +63 -0
- package/InstancedGroupMesh.ts +80 -0
- package/KeyFrameAnimation.d.ts +25 -0
- package/KeyFrameAnimation.js +78 -0
- package/KeyFrameAnimation.ts +122 -0
- package/PlaneModal1/PlaneModal1.d.ts +31 -0
- package/PlaneModal1/PlaneModal1.js +105 -0
- package/PlaneModal1/PlaneModal1.ts +151 -0
- package/PlaneModal1/index.d.ts +1 -0
- package/PlaneModal1/index.js +1 -0
- package/PlaneModal1/index.ts +1 -0
- package/PlaneModal1/planeModal.png +0 -0
- package/PlaneText.d.ts +37 -0
- package/PlaneText.js +30 -0
- package/PlaneText.ts +58 -0
- package/PlaneWithHtml.d.ts +11 -0
- package/PlaneWithHtml.js +67 -0
- package/PlaneWithHtml.ts +84 -0
- package/PointLight/PointLight.d.ts +13 -0
- package/PointLight/PointLight.js +63 -0
- package/PointLight/PointLight.ts +74 -0
- package/PointLight/index.d.ts +1 -0
- package/PointLight/index.js +1 -0
- package/PointLight/index.ts +1 -0
- package/PointLight/pointLight_map.png +0 -0
- package/Sky/Sky.d.ts +13 -0
- package/Sky/Sky.js +28 -0
- package/Sky/Sky.ts +36 -0
- package/Sky/bluesky.jpg +0 -0
- package/Sky/index.d.ts +1 -0
- package/Sky/index.js +1 -0
- package/Sky/index.ts +1 -0
- package/SpriteModal1/SpriteModal1.d.ts +30 -0
- package/SpriteModal1/SpriteModal1.js +110 -0
- package/SpriteModal1/SpriteModal1.ts +160 -0
- package/SpriteModal1/index.d.ts +1 -0
- package/SpriteModal1/index.js +1 -0
- package/SpriteModal1/index.ts +1 -0
- package/SpriteModal1/spriteModal1.png +0 -0
- package/SpriteText.d.ts +45 -0
- package/SpriteText.js +162 -0
- package/SpriteText.ts +189 -0
- package/SpriteText2.d.ts +47 -0
- package/SpriteText2.js +197 -0
- package/SpriteText2.ts +236 -0
- package/Text3D/Text3D.d.ts +20 -0
- package/Text3D/Text3D.js +62 -0
- package/Text3D/Text3D.ts +93 -0
- package/Text3D/fontController.d.ts +59 -0
- package/Text3D/fontController.js +200 -0
- package/Text3D/fontController.ts +285 -0
- package/Text3D/gentilis.json +811 -0
- package/Text3D/index.d.ts +1 -0
- package/Text3D/index.js +1 -0
- package/Text3D/index.ts +1 -0
- package/ThreeBase.d.ts +61 -0
- package/ThreeBase.js +401 -0
- package/ThreeBase.ts +482 -0
- package/ThreeMouse.d.ts +39 -0
- package/ThreeMouse.js +359 -0
- package/ThreeMouse.ts +465 -0
- package/Transition.d.ts +43 -0
- package/Transition.js +196 -0
- package/Transition.ts +268 -0
- package/index.d.ts +1 -0
- package/keyContorls.d.ts +25 -0
- package/keyContorls.js +98 -0
- package/keyContorls.ts +127 -0
- package/package.json +15 -20
- package/pass/FullScreenQuad.d.ts +7 -0
- package/pass/FullScreenQuad.js +25 -0
- package/pass/FullScreenQuad.ts +33 -0
- package/pass/stroke_pass.d.ts +2 -0
- package/pass/stroke_pass.js +190 -0
- package/pass/stroke_pass.ts +211 -0
- package/shaders.d.ts +17 -0
- package/shaders.js +245 -0
- package/shaders.ts +264 -0
- package/threeLoader.d.ts +20 -0
- package/threeLoader.js +118 -0
- package/threeLoader.ts +147 -0
- package/threeUtils.d.ts +44 -0
- package/threeUtils.js +233 -0
- package/threeUtils.ts +271 -0
- package/tsconfig.json +39 -0
package/SpriteText2.ts
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @Author: xiaosihan
|
|
3
|
+
* @Date: 2023-04-24 15:31:02
|
|
4
|
+
* @Last Modified by: xiaosihan
|
|
5
|
+
* @Last Modified time: 2023-04-24 16:18:47
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
import { Intersection, LinearFilter, Raycaster, Sprite, SpriteMaterial, Texture } from 'three';
|
|
10
|
+
|
|
11
|
+
// 带箭头的精灵文字
|
|
12
|
+
export default class SpriteText2 extends Sprite {
|
|
13
|
+
constructor(text = '', textHeight = 10, color: `rgb(${string})` | `rgba(${string})` | `#${string}` = 'rgba(255, 255, 255, 1)') {
|
|
14
|
+
super();
|
|
15
|
+
|
|
16
|
+
this._text = `${text}`;
|
|
17
|
+
this._textHeight = textHeight;
|
|
18
|
+
this._color = color;
|
|
19
|
+
this._backgroundColor = false; // no background color
|
|
20
|
+
|
|
21
|
+
this._padding = 0;
|
|
22
|
+
this._borderWidth = 0;
|
|
23
|
+
this._borderRadius = 0;
|
|
24
|
+
this._borderColor = 'white';
|
|
25
|
+
|
|
26
|
+
this._strokeWidth = 0;
|
|
27
|
+
this._strokeColor = 'white';
|
|
28
|
+
|
|
29
|
+
this._fontFace = 'Arial';
|
|
30
|
+
this._fontSize = 90; // defines text resolution
|
|
31
|
+
this._fontWeight = 'normal';
|
|
32
|
+
|
|
33
|
+
this._genCanvas();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
_text = "";
|
|
37
|
+
_textHeight = 0;
|
|
38
|
+
_color: `rgb(${string})` | `rgba(${string})` | `#${string}` = "#ffffff";
|
|
39
|
+
_backgroundColor: `rgb(${string})` | `rgba(${string})` | `#${string}` | false = false; // no background color
|
|
40
|
+
|
|
41
|
+
_padding = 0;
|
|
42
|
+
_borderWidth = 0;
|
|
43
|
+
_borderRadius = 0;
|
|
44
|
+
_borderColor = 'white';
|
|
45
|
+
|
|
46
|
+
_strokeWidth = 0;
|
|
47
|
+
_strokeColor = 'white';
|
|
48
|
+
|
|
49
|
+
_fontFace = 'Arial';
|
|
50
|
+
_fontSize = 90; // defines text resolution
|
|
51
|
+
_fontWeight = 'normal';
|
|
52
|
+
_canvas = document.createElement('canvas');
|
|
53
|
+
|
|
54
|
+
get text() { return this._text; }
|
|
55
|
+
set text(text) { this._text = text; this._genCanvas(); }
|
|
56
|
+
get textHeight() { return this._textHeight; }
|
|
57
|
+
set textHeight(textHeight) { this._textHeight = textHeight; this._genCanvas(); }
|
|
58
|
+
get color() { return this._color; }
|
|
59
|
+
set color(color) { this._color = color; this._genCanvas(); }
|
|
60
|
+
get backgroundColor() { return this._backgroundColor; }
|
|
61
|
+
set backgroundColor(color) { this._backgroundColor = color; this._genCanvas(); }
|
|
62
|
+
get padding() { return this._padding; }
|
|
63
|
+
set padding(padding) { this._padding = padding; this._genCanvas(); }
|
|
64
|
+
get borderWidth() { return this._borderWidth; }
|
|
65
|
+
set borderWidth(borderWidth) { this._borderWidth = borderWidth; this._genCanvas(); }
|
|
66
|
+
get borderRadius() { return this._borderRadius; }
|
|
67
|
+
set borderRadius(borderRadius) { this._borderRadius = borderRadius; this._genCanvas(); }
|
|
68
|
+
get borderColor() { return this._borderColor; }
|
|
69
|
+
set borderColor(borderColor) { this._borderColor = borderColor; this._genCanvas(); }
|
|
70
|
+
get fontFace() { return this._fontFace; }
|
|
71
|
+
set fontFace(fontFace) { this._fontFace = fontFace; this._genCanvas(); }
|
|
72
|
+
get fontSize() { return this._fontSize; }
|
|
73
|
+
set fontSize(fontSize) { this._fontSize = fontSize; this._genCanvas(); }
|
|
74
|
+
get fontWeight() { return this._fontWeight; }
|
|
75
|
+
set fontWeight(fontWeight) { this._fontWeight = fontWeight; this._genCanvas(); }
|
|
76
|
+
get strokeWidth() { return this._strokeWidth; }
|
|
77
|
+
set strokeWidth(strokeWidth) { this._strokeWidth = strokeWidth; this._genCanvas(); }
|
|
78
|
+
get strokeColor() { return this._strokeColor; }
|
|
79
|
+
set strokeColor(strokeColor) { this._strokeColor = strokeColor; this._genCanvas(); }
|
|
80
|
+
|
|
81
|
+
_genCanvas() {
|
|
82
|
+
const canvas = this._canvas;
|
|
83
|
+
const ctx = canvas.getContext('2d')!;
|
|
84
|
+
|
|
85
|
+
const border = Array.isArray(this.borderWidth) ? this.borderWidth : [this.borderWidth, this.borderWidth]; // x,y border
|
|
86
|
+
const relBorder: number[] = border.map(b => b * this.fontSize * 0.1); // border in canvas units
|
|
87
|
+
|
|
88
|
+
const borderRadius = Array.isArray(this.borderRadius) ? this.borderRadius : [this.borderRadius, this.borderRadius, this.borderRadius, this.borderRadius]; // tl tr br bl corners
|
|
89
|
+
const relBorderRadius = borderRadius.map(b => b * this.fontSize * 0.1); // border radius in canvas units
|
|
90
|
+
|
|
91
|
+
const padding = Array.isArray(this.padding) ? this.padding : [this.padding, this.padding]; // x,y padding
|
|
92
|
+
const relPadding = padding.map(p => p * this.fontSize * 0.1); // padding in canvas units
|
|
93
|
+
|
|
94
|
+
const lines = this.text.split('\n');
|
|
95
|
+
const font = `${this.fontWeight} ${this.fontSize}px ${this.fontFace}`;
|
|
96
|
+
|
|
97
|
+
ctx.font = font; // measure canvas with appropriate font
|
|
98
|
+
const innerWidth = Math.max(...lines.map(line => ctx.measureText(line).width));
|
|
99
|
+
const innerHeight = this.fontSize * lines.length;
|
|
100
|
+
canvas.width = innerWidth + relBorder[0] * 2 + relPadding[0] * 2;
|
|
101
|
+
canvas.height = (innerHeight + relBorder[1] * 2 + relPadding[1] * 2) * 2 + 40;
|
|
102
|
+
|
|
103
|
+
// paint border
|
|
104
|
+
if (this.borderWidth) {
|
|
105
|
+
ctx.strokeStyle = this.borderColor;
|
|
106
|
+
|
|
107
|
+
if (relBorder[0]) { // left + right borders
|
|
108
|
+
const hb = relBorder[0] / 2;
|
|
109
|
+
ctx.lineWidth = relBorder[0];
|
|
110
|
+
ctx.beginPath();
|
|
111
|
+
ctx.moveTo(hb, relBorderRadius[0]);
|
|
112
|
+
ctx.lineTo(hb, ((canvas.height - 40) / 2) - relBorderRadius[3]);
|
|
113
|
+
ctx.moveTo(canvas.width - hb, relBorderRadius[1]);
|
|
114
|
+
ctx.lineTo(canvas.width - hb, ((canvas.height - 40) / 2) - relBorderRadius[2]);
|
|
115
|
+
ctx.stroke();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (relBorder[1]) { // top + bottom borders
|
|
119
|
+
const hb = relBorder[1] / 2;
|
|
120
|
+
ctx.lineWidth = relBorder[1];
|
|
121
|
+
ctx.beginPath();
|
|
122
|
+
ctx.moveTo(Math.max(relBorder[0], relBorderRadius[0]), hb);
|
|
123
|
+
ctx.lineTo(canvas.width - Math.max(relBorder[0], relBorderRadius[1]), hb);
|
|
124
|
+
ctx.moveTo(Math.max(relBorder[0], relBorderRadius[3]), ((canvas.height - 40) / 2) - hb);
|
|
125
|
+
|
|
126
|
+
ctx.lineTo((canvas.width / 2 - 20), ((canvas.height - 40) / 2) - hb);
|
|
127
|
+
ctx.lineTo((canvas.width / 2), ((canvas.height - 40) / 2) + 20 - hb);
|
|
128
|
+
ctx.lineTo((canvas.width / 2 + 20), ((canvas.height - 40) / 2) - hb);
|
|
129
|
+
|
|
130
|
+
ctx.lineTo(canvas.width - Math.max(relBorder[0], relBorderRadius[2]), ((canvas.height - 40) / 2) - hb);
|
|
131
|
+
ctx.stroke();
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (this.borderRadius) { // strike rounded corners
|
|
135
|
+
const cornerWidth = Math.max(...relBorder);
|
|
136
|
+
const hb = cornerWidth / 2;
|
|
137
|
+
ctx.lineWidth = cornerWidth;
|
|
138
|
+
ctx.beginPath();
|
|
139
|
+
([
|
|
140
|
+
!!relBorderRadius[0] && [relBorderRadius[0], hb, hb, relBorderRadius[0]],
|
|
141
|
+
!!relBorderRadius[1] && [canvas.width - relBorderRadius[1], canvas.width - hb, hb, relBorderRadius[1]],
|
|
142
|
+
!!relBorderRadius[2] && [canvas.width - relBorderRadius[2], canvas.width - hb, ((canvas.height - 40) / 2) - hb, ((canvas.height - 40) / 2) - relBorderRadius[2]],
|
|
143
|
+
!!relBorderRadius[3] && [relBorderRadius[3], hb, ((canvas.height - 40) / 2) - hb, ((canvas.height - 40) / 2) - relBorderRadius[3]]
|
|
144
|
+
].filter(d => d) as [number, number, number, number][]).forEach(([x0, x1, y0, y1]) => {
|
|
145
|
+
ctx.moveTo(x0, y0);
|
|
146
|
+
ctx.quadraticCurveTo(x1, y0, x1, y1);
|
|
147
|
+
});
|
|
148
|
+
ctx.stroke();
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// paint background
|
|
153
|
+
if (this.backgroundColor) {
|
|
154
|
+
ctx.fillStyle = this.backgroundColor;
|
|
155
|
+
if (!this.borderRadius) {
|
|
156
|
+
ctx.fillRect(relBorder[0], relBorder[1], canvas.width - relBorder[0] * 2, ((canvas.height - 40) / 2) - relBorder[1] * 2);
|
|
157
|
+
} else { // fill with rounded corners
|
|
158
|
+
ctx.beginPath();
|
|
159
|
+
ctx.moveTo(relBorder[0], relBorderRadius[0]);
|
|
160
|
+
|
|
161
|
+
ctx.quadraticCurveTo(relBorder[0], relBorder[1], relBorderRadius[0], relBorder[1]);
|
|
162
|
+
ctx.lineTo(canvas.width - relBorderRadius[1], relBorder[1]);
|
|
163
|
+
ctx.quadraticCurveTo(canvas.width - relBorder[0], relBorder[1], canvas.width - relBorder[0], relBorderRadius[1]);
|
|
164
|
+
ctx.lineTo(canvas.width - relBorder[0], ((canvas.height - 40) / 2) - relBorderRadius[2]);
|
|
165
|
+
ctx.quadraticCurveTo(canvas.width - relBorder[0], ((canvas.height - 40) / 2) - relBorder[1], canvas.width - relBorderRadius[2], ((canvas.height - 40) / 2) - relBorder[1]);
|
|
166
|
+
|
|
167
|
+
ctx.lineTo((canvas.width / 2 + 20), ((canvas.height - 40) / 2) - relBorder[1]);
|
|
168
|
+
ctx.lineTo((canvas.width / 2), ((canvas.height - 40) / 2) + 20 - relBorder[1]);
|
|
169
|
+
ctx.lineTo((canvas.width / 2 - 20), ((canvas.height - 40) / 2) - relBorder[1]);
|
|
170
|
+
|
|
171
|
+
ctx.lineTo(relBorderRadius[3], ((canvas.height - 40) / 2) - relBorder[1]);
|
|
172
|
+
ctx.quadraticCurveTo(relBorder[0], ((canvas.height - 40) / 2) - relBorder[1], relBorder[0], ((canvas.height - 40) / 2) - relBorderRadius[3]);
|
|
173
|
+
|
|
174
|
+
ctx.closePath();
|
|
175
|
+
ctx.fill();
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
ctx.translate(relBorder[0], relBorder[1]);
|
|
180
|
+
ctx.translate(relPadding[0], relPadding[0]);
|
|
181
|
+
|
|
182
|
+
// paint text
|
|
183
|
+
ctx.font = font; // Set font again after canvas is resized, as context properties are reset
|
|
184
|
+
ctx.fillStyle = this.color;
|
|
185
|
+
ctx.textBaseline = 'bottom';
|
|
186
|
+
|
|
187
|
+
const drawTextStroke = this.strokeWidth > 0;
|
|
188
|
+
if (drawTextStroke) {
|
|
189
|
+
ctx.lineWidth = this.strokeWidth * this.fontSize / 10;
|
|
190
|
+
ctx.strokeStyle = this.strokeColor;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
lines.forEach((line, index) => {
|
|
194
|
+
const lineX = (innerWidth - ctx.measureText(line).width) / 2;
|
|
195
|
+
const lineY = (index + 1) * this.fontSize;
|
|
196
|
+
|
|
197
|
+
drawTextStroke && ctx.strokeText(line, lineX, lineY);
|
|
198
|
+
ctx.fillText(line, lineX, lineY);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
// Inject canvas into sprite
|
|
202
|
+
if (this.material.map) this.material.map.dispose(); // gc previous texture
|
|
203
|
+
const texture = this.material.map = new Texture(canvas);
|
|
204
|
+
texture.minFilter = LinearFilter;
|
|
205
|
+
texture.needsUpdate = true;
|
|
206
|
+
|
|
207
|
+
const yScale = this.textHeight * lines.length + border[1] * 2 + padding[1] * 2;
|
|
208
|
+
this.scale.set(yScale * canvas.width / canvas.height, yScale, 0);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
//鼠标拾取计算
|
|
212
|
+
raycast(raycaster: Raycaster, intersects: Intersection[]) {
|
|
213
|
+
|
|
214
|
+
let intersect: Intersection[] = [];
|
|
215
|
+
super.raycast(raycaster, intersect);
|
|
216
|
+
let inte = intersect[0];
|
|
217
|
+
if (inte && (inte.uv!.y > 0.55)) {
|
|
218
|
+
intersects.push(inte);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
copy(source: SpriteText2) {
|
|
224
|
+
this.color = source.color;
|
|
225
|
+
this.backgroundColor = source.backgroundColor;
|
|
226
|
+
this.padding = source.padding;
|
|
227
|
+
this.borderWidth = source.borderWidth;
|
|
228
|
+
this.borderColor = source.borderColor;
|
|
229
|
+
this.fontFace = source.fontFace;
|
|
230
|
+
this.fontSize = source.fontSize;
|
|
231
|
+
this.fontWeight = source.fontWeight;
|
|
232
|
+
this.strokeWidth = source.strokeWidth;
|
|
233
|
+
this.strokeColor = source.strokeColor;
|
|
234
|
+
return this;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Mesh, MeshStandardMaterial } from "three";
|
|
2
|
+
export type Text3DProps = {
|
|
3
|
+
text?: string;
|
|
4
|
+
fontType?: string;
|
|
5
|
+
size?: number | undefined;
|
|
6
|
+
height?: number | undefined;
|
|
7
|
+
curveSegments?: number | undefined;
|
|
8
|
+
bevelEnabled?: boolean | undefined;
|
|
9
|
+
bevelThickness?: number | undefined;
|
|
10
|
+
bevelSize?: number | undefined;
|
|
11
|
+
bevelOffset?: number | undefined;
|
|
12
|
+
bevelSegments?: number | undefined;
|
|
13
|
+
};
|
|
14
|
+
export default class Text3D extends Mesh {
|
|
15
|
+
constructor(text?: string);
|
|
16
|
+
static path: string;
|
|
17
|
+
material: MeshStandardMaterial;
|
|
18
|
+
_config: Text3DProps;
|
|
19
|
+
setText(text3DProps: Text3DProps): void;
|
|
20
|
+
}
|
package/Text3D/Text3D.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @Author: xiaosihan
|
|
3
|
+
* @Date: 2022-06-14 09:48:00
|
|
4
|
+
* @Last Modified by: xiaosihan
|
|
5
|
+
* @Last Modified time: 2023-04-07 21:52:03
|
|
6
|
+
*/
|
|
7
|
+
import { TextGeometry } from 'three/examples/jsm/geometries/TextGeometry.js';
|
|
8
|
+
import { Mesh, MeshStandardMaterial } from "three";
|
|
9
|
+
import fontContorller from "./fontController";
|
|
10
|
+
// 3D文字模型
|
|
11
|
+
export default class Text3D extends Mesh {
|
|
12
|
+
constructor(text = "new Text3D()") {
|
|
13
|
+
super();
|
|
14
|
+
this.setText({ text });
|
|
15
|
+
}
|
|
16
|
+
// 字体的存储路径 例如 : "http://drm.gitee.io/three-base-font/simhei/字.js"
|
|
17
|
+
static path = "//drm.gitee.io/three-base-font/";
|
|
18
|
+
material = new MeshStandardMaterial({
|
|
19
|
+
metalness: 1,
|
|
20
|
+
roughness: 0.5, // 粗糙度,值为0到1
|
|
21
|
+
});
|
|
22
|
+
// 配置
|
|
23
|
+
_config = {
|
|
24
|
+
text: "",
|
|
25
|
+
fontType: "simhei",
|
|
26
|
+
size: 1,
|
|
27
|
+
curveSegments: 10,
|
|
28
|
+
height: 0.1,
|
|
29
|
+
bevelEnabled: true,
|
|
30
|
+
bevelThickness: 0.02,
|
|
31
|
+
bevelSize: 0.015,
|
|
32
|
+
bevelOffset: 0,
|
|
33
|
+
bevelSegments: 3, //斜角分段
|
|
34
|
+
};
|
|
35
|
+
// 设置文字
|
|
36
|
+
setText(text3DProps) {
|
|
37
|
+
if (Object.keys(text3DProps).some(key => text3DProps[key] !== this._config[key])) {
|
|
38
|
+
Object.assign(this._config, text3DProps);
|
|
39
|
+
fontContorller.loadText({
|
|
40
|
+
fontBasePath: Text3D.path,
|
|
41
|
+
text: this._config.text,
|
|
42
|
+
fontType: this._config.fontType,
|
|
43
|
+
callback: THREEFont => {
|
|
44
|
+
this.geometry.dispose();
|
|
45
|
+
this.geometry = new TextGeometry(this._config.text || "", {
|
|
46
|
+
font: THREEFont,
|
|
47
|
+
size: this._config.size,
|
|
48
|
+
curveSegments: this._config.curveSegments,
|
|
49
|
+
height: this._config.height,
|
|
50
|
+
bevelEnabled: this._config.bevelEnabled,
|
|
51
|
+
bevelThickness: this._config.bevelThickness,
|
|
52
|
+
bevelSize: this._config.bevelSize,
|
|
53
|
+
bevelOffset: this._config.bevelOffset,
|
|
54
|
+
bevelSegments: this._config.bevelSegments, //斜角分段
|
|
55
|
+
});
|
|
56
|
+
this.geometry.center();
|
|
57
|
+
this.dispatchEvent({ type: "loaded" });
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
package/Text3D/Text3D.ts
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @Author: xiaosihan
|
|
3
|
+
* @Date: 2022-06-14 09:48:00
|
|
4
|
+
* @Last Modified by: xiaosihan
|
|
5
|
+
* @Last Modified time: 2023-04-07 21:52:03
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { TextGeometry, TextGeometryParameters } from 'three/examples/jsm/geometries/TextGeometry.js';
|
|
9
|
+
import { Mesh, MeshStandardMaterial } from "three";
|
|
10
|
+
import fontContorller from "./fontController";
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
export type Text3DProps = {
|
|
15
|
+
text?: string,
|
|
16
|
+
fontType?: string,
|
|
17
|
+
size?: number | undefined;
|
|
18
|
+
height?: number | undefined;
|
|
19
|
+
curveSegments?: number | undefined;
|
|
20
|
+
bevelEnabled?: boolean | undefined;
|
|
21
|
+
bevelThickness?: number | undefined;
|
|
22
|
+
bevelSize?: number | undefined;
|
|
23
|
+
bevelOffset?: number | undefined;
|
|
24
|
+
bevelSegments?: number | undefined;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
// 3D文字模型
|
|
29
|
+
export default class Text3D extends Mesh {
|
|
30
|
+
|
|
31
|
+
constructor(text: string = "new Text3D()") {
|
|
32
|
+
super();
|
|
33
|
+
this.setText({ text });
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// 字体的存储路径 例如 : "http://drm.gitee.io/three-base-font/simhei/字.js"
|
|
37
|
+
static path = "//drm.gitee.io/three-base-font/";
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
material = new MeshStandardMaterial({
|
|
41
|
+
metalness: 1, // 金属度,值为0到1
|
|
42
|
+
roughness: 0.5, // 粗糙度,值为0到1
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// 配置
|
|
46
|
+
_config: Text3DProps = {
|
|
47
|
+
text: "",
|
|
48
|
+
fontType: "simhei",
|
|
49
|
+
size: 1,
|
|
50
|
+
curveSegments: 10,
|
|
51
|
+
height: 0.1, // 文字的厚度
|
|
52
|
+
bevelEnabled: true, // 斜角开启
|
|
53
|
+
bevelThickness: 0.02, // 斜角厚度
|
|
54
|
+
bevelSize: 0.015, // 斜角大小
|
|
55
|
+
bevelOffset: 0,// 斜角偏移
|
|
56
|
+
bevelSegments: 3,//斜角分段
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// 设置文字
|
|
60
|
+
setText(text3DProps: Text3DProps) {
|
|
61
|
+
|
|
62
|
+
if (Object.keys(text3DProps).some(key => text3DProps[key as keyof typeof text3DProps] !== this._config[key as keyof typeof this._config])) {
|
|
63
|
+
|
|
64
|
+
Object.assign(this._config, text3DProps);
|
|
65
|
+
|
|
66
|
+
fontContorller.loadText({
|
|
67
|
+
fontBasePath: Text3D.path,
|
|
68
|
+
text: this._config.text,
|
|
69
|
+
fontType: this._config.fontType,
|
|
70
|
+
callback: THREEFont => {
|
|
71
|
+
this.geometry.dispose();
|
|
72
|
+
this.geometry = new TextGeometry(this._config.text || "", {
|
|
73
|
+
font: THREEFont,
|
|
74
|
+
size: this._config.size,
|
|
75
|
+
curveSegments: this._config.curveSegments,
|
|
76
|
+
height: this._config.height, // 文字的厚度
|
|
77
|
+
bevelEnabled: this._config.bevelEnabled, // 斜角开启
|
|
78
|
+
bevelThickness: this._config.bevelThickness, // 斜角厚度
|
|
79
|
+
bevelSize: this._config.bevelSize, // 斜角大小
|
|
80
|
+
bevelOffset: this._config.bevelOffset,// 斜角偏移
|
|
81
|
+
bevelSegments: this._config.bevelSegments,//斜角分段
|
|
82
|
+
});
|
|
83
|
+
this.geometry.center();
|
|
84
|
+
this.dispatchEvent({ type: "loaded" });
|
|
85
|
+
}
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import Dexie, { Table } from "dexie";
|
|
2
|
+
import { Font } from "three/examples/jsm/loaders/FontLoader.js";
|
|
3
|
+
export type saveFontParam = {
|
|
4
|
+
fontType?: string;
|
|
5
|
+
fontName: string;
|
|
6
|
+
fontJson: any;
|
|
7
|
+
};
|
|
8
|
+
export type addFontFamilyParam = {
|
|
9
|
+
fontType?: string;
|
|
10
|
+
fontFamilyJson: any;
|
|
11
|
+
};
|
|
12
|
+
export type getFontParam = {
|
|
13
|
+
fontType?: string;
|
|
14
|
+
fontName: string;
|
|
15
|
+
};
|
|
16
|
+
export type loadTextParam = {
|
|
17
|
+
fontBasePath: string;
|
|
18
|
+
fontType?: string;
|
|
19
|
+
text?: string;
|
|
20
|
+
callback?: (font: Font) => void;
|
|
21
|
+
};
|
|
22
|
+
declare class indexBD extends Dexie {
|
|
23
|
+
constructor(dbName: string);
|
|
24
|
+
threeFont: Table;
|
|
25
|
+
}
|
|
26
|
+
declare class fontContorl {
|
|
27
|
+
constructor();
|
|
28
|
+
THREEFontMap: Map<string, Font>;
|
|
29
|
+
fontBD: indexBD;
|
|
30
|
+
/**
|
|
31
|
+
* 保存 字体json到本地数据库中
|
|
32
|
+
* @param {saveFontParam} { fontType = "simhei", fontName, fontJson }
|
|
33
|
+
* @memberof fontContorl
|
|
34
|
+
*/
|
|
35
|
+
saveFont({ fontType, fontName, fontJson }: saveFontParam): Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* 通过 fontType 和 fontName 查询 fontJson
|
|
38
|
+
* @param {getFontParam} { fontType = "simhei", fontName }
|
|
39
|
+
* @returns
|
|
40
|
+
* @memberof fontContorl
|
|
41
|
+
*/
|
|
42
|
+
getFont({ fontType, fontName }: getFontParam): Promise<any>;
|
|
43
|
+
_loadTextCall: Map<string, Array<() => void>>;
|
|
44
|
+
loadText({ fontType, text, fontBasePath, callback }: loadTextParam): Promise<void>;
|
|
45
|
+
_loadFontIndexJson({ fontType, fontBasePath }: loadTextParam): Promise<void>;
|
|
46
|
+
_loadFontJson({ fontType, fontName, fontBasePath }: {
|
|
47
|
+
fontType: string;
|
|
48
|
+
fontName: string;
|
|
49
|
+
fontBasePath: string;
|
|
50
|
+
}): Promise<void>;
|
|
51
|
+
hasFont({ fontType, fontName }: {
|
|
52
|
+
fontType: string;
|
|
53
|
+
fontName: string;
|
|
54
|
+
}): boolean;
|
|
55
|
+
addFont({ fontType, fontName, fontJson }: saveFontParam): void;
|
|
56
|
+
addFontFamily({ fontType, fontFamilyJson }: addFontFamilyParam): void;
|
|
57
|
+
}
|
|
58
|
+
declare const fontContorller: fontContorl;
|
|
59
|
+
export default fontContorller;
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @Author: xiaosihan
|
|
3
|
+
* @Date: 2021-04-15 00:34:44
|
|
4
|
+
* @Last Modified by: xiaosihan
|
|
5
|
+
* @Last Modified time: 2022-06-08 14:33:45
|
|
6
|
+
*/
|
|
7
|
+
import Dexie from "dexie";
|
|
8
|
+
import { filter, first, isEmpty } from "lodash";
|
|
9
|
+
import { Font } from "three/examples/jsm/loaders/FontLoader.js";
|
|
10
|
+
import threeUtils from "../threeUtils";
|
|
11
|
+
import gentilisJSON from "./gentilis.json";
|
|
12
|
+
class indexBD extends Dexie {
|
|
13
|
+
constructor(dbName) {
|
|
14
|
+
super(dbName);
|
|
15
|
+
}
|
|
16
|
+
threeFont;
|
|
17
|
+
}
|
|
18
|
+
// 字体加载器
|
|
19
|
+
class fontContorl {
|
|
20
|
+
constructor() { }
|
|
21
|
+
THREEFontMap = new Map();
|
|
22
|
+
// 专门存储字体的数据库
|
|
23
|
+
fontBD = (() => {
|
|
24
|
+
let fontDB = new indexBD("three-base-font");
|
|
25
|
+
fontDB.version(1).stores({ threeFont: "++KeyPath,fontType,fontName,fontJson" });
|
|
26
|
+
return fontDB;
|
|
27
|
+
})();
|
|
28
|
+
/**
|
|
29
|
+
* 保存 字体json到本地数据库中
|
|
30
|
+
* @param {saveFontParam} { fontType = "simhei", fontName, fontJson }
|
|
31
|
+
* @memberof fontContorl
|
|
32
|
+
*/
|
|
33
|
+
async saveFont({ fontType = "simhei", fontName, fontJson = "" }) {
|
|
34
|
+
let findResult = await this.getFont({ fontType, fontName });
|
|
35
|
+
if (isEmpty(findResult)) {
|
|
36
|
+
await this.fontBD.threeFont.add({ fontType, fontName, fontJson });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* 通过 fontType 和 fontName 查询 fontJson
|
|
41
|
+
* @param {getFontParam} { fontType = "simhei", fontName }
|
|
42
|
+
* @returns
|
|
43
|
+
* @memberof fontContorl
|
|
44
|
+
*/
|
|
45
|
+
async getFont({ fontType = "simhei", fontName }) {
|
|
46
|
+
let fondResult = await this.fontBD.threeFont
|
|
47
|
+
.filter(d => (d.fontType === fontType && d.fontName === fontName))
|
|
48
|
+
.toArray();
|
|
49
|
+
if (isEmpty(fondResult)) {
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
return first(fondResult).fontJson;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// 加载字体的回调函数们
|
|
57
|
+
_loadTextCall = new Map();
|
|
58
|
+
// 加载文字 提供给需要创建字体模型的方法使用 以节流的形式调用 回调函数
|
|
59
|
+
async loadText({ fontType = "simhei", text = "", fontBasePath, callback }) {
|
|
60
|
+
// 加载字体容器
|
|
61
|
+
await this._loadFontIndexJson({ fontType, fontBasePath });
|
|
62
|
+
let newCallback = () => {
|
|
63
|
+
let fontFamily = this.THREEFontMap.get(fontType);
|
|
64
|
+
if (callback && fontFamily) {
|
|
65
|
+
callback(fontFamily);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
// 遍历文本
|
|
69
|
+
filter(text).map(fontName => {
|
|
70
|
+
// 没有的就去加载
|
|
71
|
+
if (!this.hasFont({ fontType, fontName })) {
|
|
72
|
+
// 添加文字的默认模型 避免报错
|
|
73
|
+
let fontFamily = this.THREEFontMap.get(fontType);
|
|
74
|
+
// 创建 three 字体对象
|
|
75
|
+
if (fontFamily) {
|
|
76
|
+
//@ts-ignore
|
|
77
|
+
fontFamily.data.glyphs[fontName] = { "ha": 1389, "x_min": 477, "x_max": 949, "o": "m 700 901 q 906 770 830 906 q 770 477 949 618 q 711 288 711 412 l 613 288 q 781 608 613 494 q 819 722 825 651 q 700 808 808 803 l 684 808 q 581 673 575 803 l 477 673 q 613 884 477 836 q 700 901 629 901 m 732 184 l 732 71 l 591 71 l 591 184 l 732 184 z " };
|
|
78
|
+
}
|
|
79
|
+
this._loadFontJson({ fontType, fontName, fontBasePath });
|
|
80
|
+
}
|
|
81
|
+
// 加入待执行的回调
|
|
82
|
+
let origin_callbacks = this._loadTextCall.get(`${fontType}_${fontName}`) || [];
|
|
83
|
+
if (newCallback) {
|
|
84
|
+
this._loadTextCall.set(`${fontType}_${fontName}`, [...origin_callbacks, newCallback]);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
// 执行任务队列
|
|
88
|
+
threeUtils.addWork(newCallback);
|
|
89
|
+
}
|
|
90
|
+
// 加载字体
|
|
91
|
+
async _loadFontIndexJson({ fontType = "simhei", fontBasePath }) {
|
|
92
|
+
let fontFamily = this.THREEFontMap.get(fontType);
|
|
93
|
+
// 创建 three 字体对象
|
|
94
|
+
if (!fontFamily) {
|
|
95
|
+
// 初始字体结构
|
|
96
|
+
fontFamily = new Font({
|
|
97
|
+
"underlineThickness": 69,
|
|
98
|
+
"underlinePosition": -174,
|
|
99
|
+
"resolution": 1000,
|
|
100
|
+
"original_font_information": {},
|
|
101
|
+
"familyName": "Source Han Sans CN Normal",
|
|
102
|
+
"descender": -167,
|
|
103
|
+
"cssFontWeight": "normal",
|
|
104
|
+
"cssFontStyle": "normal",
|
|
105
|
+
"boundingBox": {
|
|
106
|
+
"yMin": -700,
|
|
107
|
+
"xMin": -1389,
|
|
108
|
+
"yMax": 700,
|
|
109
|
+
"xMax": 4067
|
|
110
|
+
},
|
|
111
|
+
"glyphs": {}
|
|
112
|
+
});
|
|
113
|
+
this.THREEFontMap.set(fontType, fontFamily);
|
|
114
|
+
// 读取本地数据库中的字体初始结构文件
|
|
115
|
+
let fontFamilyIndexJson = await this.getFont({ fontType, fontName: "index" });
|
|
116
|
+
// 加载外部字体初始结构文件
|
|
117
|
+
if (!fontFamilyIndexJson) {
|
|
118
|
+
this._loadFontJson({ fontType, fontName: "index", fontBasePath });
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// 加载外部字体.js
|
|
123
|
+
async _loadFontJson({ fontType = "simhei", fontName, fontBasePath }) {
|
|
124
|
+
let fontJson = await this.getFont({ fontType, fontName });
|
|
125
|
+
if (!fontJson) {
|
|
126
|
+
fontJson = gentilisJSON.glyphs[fontName];
|
|
127
|
+
}
|
|
128
|
+
// 数据库中没有 就去加载字体js
|
|
129
|
+
if (!fontJson) {
|
|
130
|
+
// 加载字体js
|
|
131
|
+
await new Promise(resolve => {
|
|
132
|
+
let script = document.createElement("script");
|
|
133
|
+
Object.assign(script, {
|
|
134
|
+
type: "text/javascript",
|
|
135
|
+
src: `${fontBasePath}${fontType}/${fontName}.js`,
|
|
136
|
+
async: true,
|
|
137
|
+
onload: () => {
|
|
138
|
+
script.remove();
|
|
139
|
+
resolve();
|
|
140
|
+
},
|
|
141
|
+
onerror: () => {
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
document.head.appendChild(script);
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
// 数据库或者默认字体中 有就加入字体文件中
|
|
149
|
+
let fontFamily = this.THREEFontMap.get(fontType);
|
|
150
|
+
// 创建 three 字体对象
|
|
151
|
+
if (fontFamily) {
|
|
152
|
+
//@ts-ignore
|
|
153
|
+
fontFamily.data.glyphs[fontName] = fontJson;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
// 执行相应的回调函数
|
|
157
|
+
let origin_callbacks = this._loadTextCall.get(`${fontType}_${fontName}`) || [];
|
|
158
|
+
// // 删除待执行的回调
|
|
159
|
+
this._loadTextCall.delete(`${fontType}_${fontName}`);
|
|
160
|
+
origin_callbacks.map(callback => {
|
|
161
|
+
// 执行任务队列
|
|
162
|
+
threeUtils.addWork(callback);
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
// 判断是否有这个文字
|
|
166
|
+
hasFont({ fontType, fontName }) {
|
|
167
|
+
return !isEmpty(this.THREEFontMap.get(fontType) &&
|
|
168
|
+
//@ts-ignore
|
|
169
|
+
this.THREEFontMap.get(fontType).data.glyphs[fontName]);
|
|
170
|
+
}
|
|
171
|
+
// 这个方法是提供给外部字体文件调用的
|
|
172
|
+
addFont({ fontType = "simhei", fontName, fontJson }) {
|
|
173
|
+
// 保存字体json到本地数据中
|
|
174
|
+
this.saveFont({ fontType, fontName, fontJson });
|
|
175
|
+
let fontFamily = this.THREEFontMap.get(fontType);
|
|
176
|
+
// 创建 three 字体对象
|
|
177
|
+
if (fontFamily) {
|
|
178
|
+
//@ts-ignore
|
|
179
|
+
fontFamily.data.glyphs[fontName] = fontJson;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
// 这个方法是提供给外部字体文件调用的
|
|
183
|
+
addFontFamily({ fontType = "simhei", fontFamilyJson }) {
|
|
184
|
+
// 保存字体初始结构到数据库中
|
|
185
|
+
this.saveFont({ fontType, fontName: "index", fontJson: fontFamilyJson });
|
|
186
|
+
let fontFamily = this.THREEFontMap.get(fontType);
|
|
187
|
+
// 创建 three 字体对象
|
|
188
|
+
if (fontFamily) {
|
|
189
|
+
//@ts-ignore
|
|
190
|
+
fontFamily.data = {
|
|
191
|
+
...fontFamilyJson,
|
|
192
|
+
//@ts-ignore
|
|
193
|
+
glyphs: fontFamily.data.glyphs
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
const fontContorller = new fontContorl();
|
|
199
|
+
Object.assign(window, { fontContorller });
|
|
200
|
+
export default fontContorller;
|