three-stdlib 2.19.0 → 2.20.0

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.
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("three");class t extends e.Mesh{constructor(t){const i=new o(t),s=new e.PlaneGeometry(.001*i.image.width,.001*i.image.height),r=new e.MeshBasicMaterial({map:i,toneMapped:!1,transparent:!0});function l(e){r.map.dispatchDOMEvent(e)}super(s,r),this.addEventListener("mousedown",l),this.addEventListener("mousemove",l),this.addEventListener("mouseup",l),this.addEventListener("click",l),this.dispose=function(){s.dispose(),r.dispose(),r.map.dispose(),n.delete(t),this.removeEventListener("mousedown",l),this.removeEventListener("mousemove",l),this.removeEventListener("mouseup",l),this.removeEventListener("click",l)}}}class o extends e.CanvasTexture{constructor(t){super(i(t)),this.dom=t,this.anisotropy=16,this.encoding=e.sRGBEncoding,this.minFilter=e.LinearFilter,this.magFilter=e.LinearFilter;const o=new MutationObserver((()=>{this.scheduleUpdate||(this.scheduleUpdate=setTimeout((()=>this.update()),16))}));o.observe(t,{attributes:!0,childList:!0,subtree:!0,characterData:!0}),this.observer=o}dispatchDOMEvent(e){e.data&&function(e,t,o,n){const i={clientX:o*e.offsetWidth+e.offsetLeft,clientY:n*e.offsetHeight+e.offsetTop,view:e.ownerDocument.defaultView};window.dispatchEvent(new MouseEvent(t,i));const s=e.getBoundingClientRect();function r(e){if(e.nodeType!==Node.TEXT_NODE&&e.nodeType!==Node.COMMENT_NODE){const s=e.getBoundingClientRect();if(o>s.left&&o<s.right&&n>s.top&&n<s.bottom&&(e.dispatchEvent(new MouseEvent(t,i)),e instanceof HTMLInputElement&&"range"===e.type&&("mousedown"===t||"click"===t))){const[t,n]=["min","max"].map((t=>parseFloat(e[t]))),i=s.width,r=(o-s.x)/i;e.value=t+(n-t)*r,e.dispatchEvent(new InputEvent("input",{bubbles:!0}))}for(let t=0;t<e.childNodes.length;t++)r(e.childNodes[t])}}o=o*s.width+s.left,n=n*s.height+s.top,r(e)}(this.dom,e.type,e.data.x,e.data.y)}update(){this.image=i(this.dom),this.needsUpdate=!0,this.scheduleUpdate=null}dispose(){this.observer&&this.observer.disconnect(),this.scheduleUpdate=clearTimeout(this.scheduleUpdate),super.dispose()}}const n=new WeakMap;function i(t){const o=document.createRange(),i=new e.Color;function s(e,t,o,n){""!==n&&("uppercase"===e.textTransform&&(n=n.toUpperCase()),c.font=e.fontWeight+" "+e.fontSize+" "+e.fontFamily,c.textBaseline="top",c.fillStyle=e.color,c.fillText(n,t,o+.1*parseFloat(e.fontSize)))}function r(e,t,o,n,i){o<2*i&&(i=o/2),n<2*i&&(i=n/2),c.beginPath(),c.moveTo(e+i,t),c.arcTo(e+o,t,e+o,t+n,i),c.arcTo(e+o,t+n,e,t+n,i),c.arcTo(e,t+n,e,t,i),c.arcTo(e,t,e+o,t,i),c.closePath()}function l(e,t,o,n,i,s){const r=e[t+"Width"],l=e[t+"Style"],d=e[t+"Color"];"0px"!==r&&"none"!==l&&"transparent"!==d&&"rgba(0, 0, 0, 0)"!==d&&(c.strokeStyle=d,c.lineWidth=parseFloat(r),c.beginPath(),c.moveTo(o,n),c.lineTo(o+i,n+s),c.stroke())}const d=t.getBoundingClientRect();let a=n.get(t);void 0===a&&(a=document.createElement("canvas"),a.width=d.width,a.height=d.height,n.set(t,a));const c=a.getContext("2d"),h=new function(e){const t=[];let o=!1;function n(){if(o&&(o=!1,e.restore()),0===t.length)return;let n=-1/0,i=-1/0,s=1/0,r=1/0;for(let e=0;e<t.length;e++){const o=t[e];n=Math.max(n,o.x),i=Math.max(i,o.y),s=Math.min(s,o.x+o.width),r=Math.min(r,o.y+o.height)}e.save(),e.beginPath(),e.rect(n,i,s-n,r-i),e.clip(),o=!0}return{add:function(e){t.push(e),n()},remove:function(){t.pop(),n()}}}(c);return function e(t,n){let a=0,p=0,f=0,u=0;if(t.nodeType===Node.TEXT_NODE){o.selectNode(t);const e=o.getBoundingClientRect();a=e.left-d.left-.5,p=e.top-d.top-.5,f=e.width,u=e.height,s(n,a,p,t.nodeValue.trim())}else{if(t.nodeType===Node.COMMENT_NODE)return;if(t instanceof HTMLCanvasElement){if("none"===t.style.display)return;c.save();const e=window.devicePixelRatio;c.scale(1/e,1/e),c.drawImage(t,0,0),c.restore()}else{if("none"===t.style.display)return;const e=t.getBoundingClientRect();a=e.left-d.left-.5,p=e.top-d.top-.5,f=e.width,u=e.height,n=window.getComputedStyle(t),r(a,p,f,u,parseFloat(n.borderRadius));const o=n.backgroundColor;"transparent"!==o&&"rgba(0, 0, 0, 0)"!==o&&(c.fillStyle=o,c.fill());const m=["borderTop","borderLeft","borderBottom","borderRight"];let g=!0,v=null;for(const e of m){if(null!==v&&(g=n[e+"Width"]===n[v+"Width"]&&n[e+"Color"]===n[v+"Color"]&&n[e+"Style"]===n[v+"Style"]),!1===g)break;v=e}if(!0===g){const e=parseFloat(n.borderTopWidth);"0px"!==n.borderTopWidth&&"none"!==n.borderTopStyle&&"transparent"!==n.borderTopColor&&"rgba(0, 0, 0, 0)"!==n.borderTopColor&&(c.strokeStyle=n.borderTopColor,c.lineWidth=e,c.stroke())}else l(n,"borderTop",a,p,f,0),l(n,"borderLeft",a,p,0,u),l(n,"borderBottom",a,p+u,f,0),l(n,"borderRight",a+f,p,0,u);if(t instanceof HTMLInputElement){let e=n.accentColor;void 0!==e&&"auto"!==e||(e=n.color),i.set(e);const o=Math.sqrt(.299*i.r**2+.587*i.g**2+.114*i.b**2)<.5?"white":"#111111";if("radio"===t.type&&(r(a,p,f,u,u),c.fillStyle="white",c.strokeStyle=e,c.lineWidth=1,c.fill(),c.stroke(),t.checked&&(r(a+2,p+2,f-4,u-4,u),c.fillStyle=e,c.strokeStyle=o,c.lineWidth=2,c.fill(),c.stroke())),"checkbox"===t.type&&(r(a,p,f,u,2),c.fillStyle=t.checked?e:"white",c.strokeStyle=t.checked?o:e,c.lineWidth=1,c.stroke(),c.fill(),t.checked)){const e=c.textAlign;c.textAlign="center";s({color:o,fontFamily:n.fontFamily,fontSize:u+"px",fontWeight:"bold"},a+f/2,p,"✔"),c.textAlign=e}if("range"===t.type){const[n,i,s]=["min","max","value"].map((e=>parseFloat(t[e]))),l=(s-n)/(i-n)*(f-u);r(a,p+u/4,f,u/2,u/4),c.fillStyle=o,c.strokeStyle=e,c.lineWidth=1,c.fill(),c.stroke(),r(a,p+u/4,l+u/2,u/2,u/4),c.fillStyle=e,c.fill(),r(a+l,p,u,u,u/2),c.fillStyle=e,c.fill()}"color"!==t.type&&"text"!==t.type&&"number"!==t.type||(h.add({x:a,y:p,width:f,height:u}),s(n,a+parseInt(n.paddingLeft),p+parseInt(n.paddingTop),t.value),h.remove())}}}const m="auto"===n.overflow||"hidden"===n.overflow;m&&h.add({x:a,y:p,width:f,height:u});for(let o=0;o<t.childNodes.length;o++)e(t.childNodes[o],n);m&&h.remove()}(t),a}exports.HTMLMesh=t;
@@ -0,0 +1,6 @@
1
+ import { Mesh } from 'three';
2
+
3
+ export class HTMLMesh extends Mesh {
4
+ constructor(dom: HTMLElement);
5
+ dispose(): void;
6
+ }
@@ -0,0 +1,405 @@
1
+ import { Mesh, PlaneGeometry, MeshBasicMaterial, CanvasTexture, sRGBEncoding, LinearFilter, Color } from 'three';
2
+
3
+ class HTMLMesh extends Mesh {
4
+ constructor(dom) {
5
+ const texture = new HTMLTexture(dom);
6
+ const geometry = new PlaneGeometry(texture.image.width * 0.001, texture.image.height * 0.001);
7
+ const material = new MeshBasicMaterial({
8
+ map: texture,
9
+ toneMapped: false,
10
+ transparent: true
11
+ });
12
+ super(geometry, material);
13
+
14
+ function onEvent(event) {
15
+ material.map.dispatchDOMEvent(event);
16
+ }
17
+
18
+ this.addEventListener('mousedown', onEvent);
19
+ this.addEventListener('mousemove', onEvent);
20
+ this.addEventListener('mouseup', onEvent);
21
+ this.addEventListener('click', onEvent);
22
+
23
+ this.dispose = function () {
24
+ geometry.dispose();
25
+ material.dispose();
26
+ material.map.dispose();
27
+ canvases.delete(dom);
28
+ this.removeEventListener('mousedown', onEvent);
29
+ this.removeEventListener('mousemove', onEvent);
30
+ this.removeEventListener('mouseup', onEvent);
31
+ this.removeEventListener('click', onEvent);
32
+ };
33
+ }
34
+
35
+ }
36
+
37
+ class HTMLTexture extends CanvasTexture {
38
+ constructor(dom) {
39
+ super(html2canvas(dom));
40
+ this.dom = dom;
41
+ this.anisotropy = 16;
42
+ this.encoding = sRGBEncoding;
43
+ this.minFilter = LinearFilter;
44
+ this.magFilter = LinearFilter; // Create an observer on the DOM, and run html2canvas update in the next loop
45
+
46
+ const observer = new MutationObserver(() => {
47
+ if (!this.scheduleUpdate) {
48
+ // ideally should use xr.requestAnimationFrame, here setTimeout to avoid passing the renderer
49
+ this.scheduleUpdate = setTimeout(() => this.update(), 16);
50
+ }
51
+ });
52
+ const config = {
53
+ attributes: true,
54
+ childList: true,
55
+ subtree: true,
56
+ characterData: true
57
+ };
58
+ observer.observe(dom, config);
59
+ this.observer = observer;
60
+ }
61
+
62
+ dispatchDOMEvent(event) {
63
+ if (event.data) {
64
+ htmlevent(this.dom, event.type, event.data.x, event.data.y);
65
+ }
66
+ }
67
+
68
+ update() {
69
+ this.image = html2canvas(this.dom);
70
+ this.needsUpdate = true;
71
+ this.scheduleUpdate = null;
72
+ }
73
+
74
+ dispose() {
75
+ if (this.observer) {
76
+ this.observer.disconnect();
77
+ }
78
+
79
+ this.scheduleUpdate = clearTimeout(this.scheduleUpdate);
80
+ super.dispose();
81
+ }
82
+
83
+ } //
84
+
85
+
86
+ const canvases = new WeakMap();
87
+
88
+ function html2canvas(element) {
89
+ const range = document.createRange();
90
+ const color = new Color();
91
+
92
+ function Clipper(context) {
93
+ const clips = [];
94
+ let isClipping = false;
95
+
96
+ function doClip() {
97
+ if (isClipping) {
98
+ isClipping = false;
99
+ context.restore();
100
+ }
101
+
102
+ if (clips.length === 0) return;
103
+ let minX = -Infinity,
104
+ minY = -Infinity;
105
+ let maxX = Infinity,
106
+ maxY = Infinity;
107
+
108
+ for (let i = 0; i < clips.length; i++) {
109
+ const clip = clips[i];
110
+ minX = Math.max(minX, clip.x);
111
+ minY = Math.max(minY, clip.y);
112
+ maxX = Math.min(maxX, clip.x + clip.width);
113
+ maxY = Math.min(maxY, clip.y + clip.height);
114
+ }
115
+
116
+ context.save();
117
+ context.beginPath();
118
+ context.rect(minX, minY, maxX - minX, maxY - minY);
119
+ context.clip();
120
+ isClipping = true;
121
+ }
122
+
123
+ return {
124
+ add: function (clip) {
125
+ clips.push(clip);
126
+ doClip();
127
+ },
128
+ remove: function () {
129
+ clips.pop();
130
+ doClip();
131
+ }
132
+ };
133
+ }
134
+
135
+ function drawText(style, x, y, string) {
136
+ if (string !== '') {
137
+ if (style.textTransform === 'uppercase') {
138
+ string = string.toUpperCase();
139
+ }
140
+
141
+ context.font = style.fontWeight + ' ' + style.fontSize + ' ' + style.fontFamily;
142
+ context.textBaseline = 'top';
143
+ context.fillStyle = style.color;
144
+ context.fillText(string, x, y + parseFloat(style.fontSize) * 0.1);
145
+ }
146
+ }
147
+
148
+ function buildRectPath(x, y, w, h, r) {
149
+ if (w < 2 * r) r = w / 2;
150
+ if (h < 2 * r) r = h / 2;
151
+ context.beginPath();
152
+ context.moveTo(x + r, y);
153
+ context.arcTo(x + w, y, x + w, y + h, r);
154
+ context.arcTo(x + w, y + h, x, y + h, r);
155
+ context.arcTo(x, y + h, x, y, r);
156
+ context.arcTo(x, y, x + w, y, r);
157
+ context.closePath();
158
+ }
159
+
160
+ function drawBorder(style, which, x, y, width, height) {
161
+ const borderWidth = style[which + 'Width'];
162
+ const borderStyle = style[which + 'Style'];
163
+ const borderColor = style[which + 'Color'];
164
+
165
+ if (borderWidth !== '0px' && borderStyle !== 'none' && borderColor !== 'transparent' && borderColor !== 'rgba(0, 0, 0, 0)') {
166
+ context.strokeStyle = borderColor;
167
+ context.lineWidth = parseFloat(borderWidth);
168
+ context.beginPath();
169
+ context.moveTo(x, y);
170
+ context.lineTo(x + width, y + height);
171
+ context.stroke();
172
+ }
173
+ }
174
+
175
+ function drawElement(element, style) {
176
+ let x = 0,
177
+ y = 0,
178
+ width = 0,
179
+ height = 0;
180
+
181
+ if (element.nodeType === Node.TEXT_NODE) {
182
+ // text
183
+ range.selectNode(element);
184
+ const rect = range.getBoundingClientRect();
185
+ x = rect.left - offset.left - 0.5;
186
+ y = rect.top - offset.top - 0.5;
187
+ width = rect.width;
188
+ height = rect.height;
189
+ drawText(style, x, y, element.nodeValue.trim());
190
+ } else if (element.nodeType === Node.COMMENT_NODE) {
191
+ return;
192
+ } else if (element instanceof HTMLCanvasElement) {
193
+ // Canvas element
194
+ if (element.style.display === 'none') return;
195
+ context.save();
196
+ const dpr = window.devicePixelRatio;
197
+ context.scale(1 / dpr, 1 / dpr);
198
+ context.drawImage(element, 0, 0);
199
+ context.restore();
200
+ } else {
201
+ if (element.style.display === 'none') return;
202
+ const rect = element.getBoundingClientRect();
203
+ x = rect.left - offset.left - 0.5;
204
+ y = rect.top - offset.top - 0.5;
205
+ width = rect.width;
206
+ height = rect.height;
207
+ style = window.getComputedStyle(element); // Get the border of the element used for fill and border
208
+
209
+ buildRectPath(x, y, width, height, parseFloat(style.borderRadius));
210
+ const backgroundColor = style.backgroundColor;
211
+
212
+ if (backgroundColor !== 'transparent' && backgroundColor !== 'rgba(0, 0, 0, 0)') {
213
+ context.fillStyle = backgroundColor;
214
+ context.fill();
215
+ } // If all the borders match then stroke the round rectangle
216
+
217
+
218
+ const borders = ['borderTop', 'borderLeft', 'borderBottom', 'borderRight'];
219
+ let match = true;
220
+ let prevBorder = null;
221
+
222
+ for (const border of borders) {
223
+ if (prevBorder !== null) {
224
+ match = style[border + 'Width'] === style[prevBorder + 'Width'] && style[border + 'Color'] === style[prevBorder + 'Color'] && style[border + 'Style'] === style[prevBorder + 'Style'];
225
+ }
226
+
227
+ if (match === false) break;
228
+ prevBorder = border;
229
+ }
230
+
231
+ if (match === true) {
232
+ // They all match so stroke the rectangle from before allows for border-radius
233
+ const width = parseFloat(style.borderTopWidth);
234
+
235
+ if (style.borderTopWidth !== '0px' && style.borderTopStyle !== 'none' && style.borderTopColor !== 'transparent' && style.borderTopColor !== 'rgba(0, 0, 0, 0)') {
236
+ context.strokeStyle = style.borderTopColor;
237
+ context.lineWidth = width;
238
+ context.stroke();
239
+ }
240
+ } else {
241
+ // Otherwise draw individual borders
242
+ drawBorder(style, 'borderTop', x, y, width, 0);
243
+ drawBorder(style, 'borderLeft', x, y, 0, height);
244
+ drawBorder(style, 'borderBottom', x, y + height, width, 0);
245
+ drawBorder(style, 'borderRight', x + width, y, 0, height);
246
+ }
247
+
248
+ if (element instanceof HTMLInputElement) {
249
+ let accentColor = style.accentColor;
250
+ if (accentColor === undefined || accentColor === 'auto') accentColor = style.color;
251
+ color.set(accentColor);
252
+ const luminance = Math.sqrt(0.299 * color.r ** 2 + 0.587 * color.g ** 2 + 0.114 * color.b ** 2);
253
+ const accentTextColor = luminance < 0.5 ? 'white' : '#111111';
254
+
255
+ if (element.type === 'radio') {
256
+ buildRectPath(x, y, width, height, height);
257
+ context.fillStyle = 'white';
258
+ context.strokeStyle = accentColor;
259
+ context.lineWidth = 1;
260
+ context.fill();
261
+ context.stroke();
262
+
263
+ if (element.checked) {
264
+ buildRectPath(x + 2, y + 2, width - 4, height - 4, height);
265
+ context.fillStyle = accentColor;
266
+ context.strokeStyle = accentTextColor;
267
+ context.lineWidth = 2;
268
+ context.fill();
269
+ context.stroke();
270
+ }
271
+ }
272
+
273
+ if (element.type === 'checkbox') {
274
+ buildRectPath(x, y, width, height, 2);
275
+ context.fillStyle = element.checked ? accentColor : 'white';
276
+ context.strokeStyle = element.checked ? accentTextColor : accentColor;
277
+ context.lineWidth = 1;
278
+ context.stroke();
279
+ context.fill();
280
+
281
+ if (element.checked) {
282
+ const currentTextAlign = context.textAlign;
283
+ context.textAlign = 'center';
284
+ const properties = {
285
+ color: accentTextColor,
286
+ fontFamily: style.fontFamily,
287
+ fontSize: height + 'px',
288
+ fontWeight: 'bold'
289
+ };
290
+ drawText(properties, x + width / 2, y, '✔');
291
+ context.textAlign = currentTextAlign;
292
+ }
293
+ }
294
+
295
+ if (element.type === 'range') {
296
+ const [min, max, value] = ['min', 'max', 'value'].map(property => parseFloat(element[property]));
297
+ const position = (value - min) / (max - min) * (width - height);
298
+ buildRectPath(x, y + height / 4, width, height / 2, height / 4);
299
+ context.fillStyle = accentTextColor;
300
+ context.strokeStyle = accentColor;
301
+ context.lineWidth = 1;
302
+ context.fill();
303
+ context.stroke();
304
+ buildRectPath(x, y + height / 4, position + height / 2, height / 2, height / 4);
305
+ context.fillStyle = accentColor;
306
+ context.fill();
307
+ buildRectPath(x + position, y, height, height, height / 2);
308
+ context.fillStyle = accentColor;
309
+ context.fill();
310
+ }
311
+
312
+ if (element.type === 'color' || element.type === 'text' || element.type === 'number') {
313
+ clipper.add({
314
+ x: x,
315
+ y: y,
316
+ width: width,
317
+ height: height
318
+ });
319
+ drawText(style, x + parseInt(style.paddingLeft), y + parseInt(style.paddingTop), element.value);
320
+ clipper.remove();
321
+ }
322
+ }
323
+ }
324
+ /*
325
+ // debug
326
+ context.strokeStyle = '#' + Math.random().toString( 16 ).slice( - 3 );
327
+ context.strokeRect( x - 0.5, y - 0.5, width + 1, height + 1 );
328
+ */
329
+
330
+
331
+ const isClipping = style.overflow === 'auto' || style.overflow === 'hidden';
332
+ if (isClipping) clipper.add({
333
+ x: x,
334
+ y: y,
335
+ width: width,
336
+ height: height
337
+ });
338
+
339
+ for (let i = 0; i < element.childNodes.length; i++) {
340
+ drawElement(element.childNodes[i], style);
341
+ }
342
+
343
+ if (isClipping) clipper.remove();
344
+ }
345
+
346
+ const offset = element.getBoundingClientRect();
347
+ let canvas = canvases.get(element);
348
+
349
+ if (canvas === undefined) {
350
+ canvas = document.createElement('canvas');
351
+ canvas.width = offset.width;
352
+ canvas.height = offset.height;
353
+ canvases.set(element, canvas);
354
+ }
355
+
356
+ const context = canvas.getContext('2d'
357
+ /*, { alpha: false }*/
358
+ );
359
+ const clipper = new Clipper(context); // console.time( 'drawElement' );
360
+
361
+ drawElement(element); // console.timeEnd( 'drawElement' );
362
+
363
+ return canvas;
364
+ }
365
+
366
+ function htmlevent(element, event, x, y) {
367
+ const mouseEventInit = {
368
+ clientX: x * element.offsetWidth + element.offsetLeft,
369
+ clientY: y * element.offsetHeight + element.offsetTop,
370
+ view: element.ownerDocument.defaultView
371
+ };
372
+ window.dispatchEvent(new MouseEvent(event, mouseEventInit));
373
+ const rect = element.getBoundingClientRect();
374
+ x = x * rect.width + rect.left;
375
+ y = y * rect.height + rect.top;
376
+
377
+ function traverse(element) {
378
+ if (element.nodeType !== Node.TEXT_NODE && element.nodeType !== Node.COMMENT_NODE) {
379
+ const rect = element.getBoundingClientRect();
380
+
381
+ if (x > rect.left && x < rect.right && y > rect.top && y < rect.bottom) {
382
+ element.dispatchEvent(new MouseEvent(event, mouseEventInit));
383
+
384
+ if (element instanceof HTMLInputElement && element.type === 'range' && (event === 'mousedown' || event === 'click')) {
385
+ const [min, max] = ['min', 'max'].map(property => parseFloat(element[property]));
386
+ const width = rect.width;
387
+ const offsetX = x - rect.x;
388
+ const proportion = offsetX / width;
389
+ element.value = min + (max - min) * proportion;
390
+ element.dispatchEvent(new InputEvent('input', {
391
+ bubbles: true
392
+ }));
393
+ }
394
+ }
395
+
396
+ for (let i = 0; i < element.childNodes.length; i++) {
397
+ traverse(element.childNodes[i]);
398
+ }
399
+ }
400
+ }
401
+
402
+ traverse(element);
403
+ }
404
+
405
+ export { HTMLMesh };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "three-stdlib",
3
- "version": "2.19.0",
3
+ "version": "2.20.0",
4
4
  "private": false,
5
5
  "description": "stand-alone library of threejs examples",
6
6
  "main": "index.cjs.js",