x_ite 8.6.2 → 8.6.4

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.
Files changed (54) hide show
  1. package/.vscode/settings.json +7 -7
  2. package/dist/assets/components/Annotation.js +13 -13
  3. package/dist/assets/components/Annotation.min.js +1 -1
  4. package/dist/assets/components/CADGeometry.js +13 -13
  5. package/dist/assets/components/CADGeometry.min.js +1 -1
  6. package/dist/assets/components/CubeMapTexturing.js +25 -25
  7. package/dist/assets/components/CubeMapTexturing.min.js +1 -1
  8. package/dist/assets/components/DIS.js +13 -13
  9. package/dist/assets/components/DIS.min.js +1 -1
  10. package/dist/assets/components/EventUtilities.js +9 -9
  11. package/dist/assets/components/EventUtilities.min.js +1 -1
  12. package/dist/assets/components/Geometry2D.js +19 -19
  13. package/dist/assets/components/Geometry2D.min.js +1 -1
  14. package/dist/assets/components/Geospatial.js +33 -33
  15. package/dist/assets/components/Geospatial.min.js +1 -1
  16. package/dist/assets/components/HAnim.js +18 -18
  17. package/dist/assets/components/HAnim.min.js +1 -1
  18. package/dist/assets/components/KeyDeviceSensor.js +8 -8
  19. package/dist/assets/components/KeyDeviceSensor.min.js +1 -1
  20. package/dist/assets/components/Layout.js +27 -27
  21. package/dist/assets/components/Layout.min.js +1 -1
  22. package/dist/assets/components/NURBS.js +24 -24
  23. package/dist/assets/components/NURBS.min.js +1 -1
  24. package/dist/assets/components/ParticleSystems.js +23 -23
  25. package/dist/assets/components/ParticleSystems.min.js +1 -1
  26. package/dist/assets/components/Picking.js +19 -19
  27. package/dist/assets/components/Picking.min.js +1 -1
  28. package/dist/assets/components/RigidBodyPhysics.js +18 -18
  29. package/dist/assets/components/RigidBodyPhysics.min.js +1 -1
  30. package/dist/assets/components/Scripting.js +28 -28
  31. package/dist/assets/components/Scripting.min.js +1 -1
  32. package/dist/assets/components/Text.js +24 -24
  33. package/dist/assets/components/Text.min.js +1 -1
  34. package/dist/assets/components/TextureProjector.js +14 -14
  35. package/dist/assets/components/TextureProjector.min.js +1 -1
  36. package/dist/assets/components/Texturing3D.js +32 -32
  37. package/dist/assets/components/Texturing3D.min.js +1 -1
  38. package/dist/assets/components/VolumeRendering.js +19 -19
  39. package/dist/assets/components/VolumeRendering.min.js +1 -1
  40. package/dist/assets/components/X_ITE.js +9 -9
  41. package/dist/assets/components/X_ITE.min.js +1 -1
  42. package/dist/x_ite.css +1 -1
  43. package/dist/x_ite.js +225 -139
  44. package/dist/x_ite.min.js +1 -1
  45. package/dist/x_ite.zip +0 -0
  46. package/docs/_config.yml +1 -1
  47. package/docs/_posts/getting-started.md +1 -1
  48. package/docs/_posts/laboratory/x3d-file-converter.md +12 -7
  49. package/docs/_tabs/laboratory.md +6 -0
  50. package/package.json +1 -1
  51. package/src/x_ite/Browser/VERSION.js +1 -1
  52. package/src/x_ite/Parser/OBJParser.js +29 -22
  53. package/src/x_ite/Parser/SVGParser.js +138 -60
  54. package/src/x_ite/Parser/X3DParser.js +3 -2
package/dist/x_ite.zip CHANGED
Binary file
package/docs/_config.yml CHANGED
@@ -20,7 +20,7 @@ timezone:
20
20
  # ↓ --------------------------
21
21
 
22
22
  title: X_ITE X3D Browser # the main title
23
- version: 8.6.2 # x_ite latest version
23
+ version: 8.6.4 # x_ite latest version
24
24
  size: 287 # size in kb
25
25
  x3d_latest_version: 4.0 # x3d latest version
26
26
 
@@ -645,7 +645,7 @@ X_ITE can load several file formats, either directly as the source of the \<x3d-
645
645
  >**Tip:** All files can be compressed using GZip compression. This saves bandwidth and speeds up download time.
646
646
  {: .prompt-tip }
647
647
 
648
- For more information see [How to Configure Your Web Server](how-to-configure-your-web-server).
648
+ If you have an own web-server see [How to Configure Your Web Server](how-to-configure-your-web-server). If you are looking for an online X3D file format converter [see here](laboratory/x3d-file-converter).
649
649
 
650
650
  ### Fallback Content
651
651
 
@@ -37,13 +37,12 @@ x_ite: true
37
37
  #drop-zone select {
38
38
  color: unset;
39
39
  position: relative;
40
- top: -8px;
40
+ top: -6px;
41
41
  }
42
42
  </style>
43
43
 
44
- <script defer="" src="https://create3000.github.io/media/laboratory/l-system/FileSaver.js-2.0.0/dist/FileSaver.min.js"></script>
45
-
46
- <script defer="">
44
+ <script defer src="https://create3000.github.io/media/laboratory/l-system/FileSaver.js-2.0.0/dist/FileSaver.min.js"></script>
45
+ <script defer>
47
46
  $(() =>
48
47
  {
49
48
  $("#drop-zone") .on ("dragover", event =>
@@ -118,7 +117,7 @@ $(() =>
118
117
 
119
118
  await Browser .loadURL (new X3D .MFString (url));
120
119
 
121
- link (mimeType, file .name + extension, Browser .currentScene [toString] ());
120
+ link (mimeType, file .name .replace (/\.[^.]+$/, "") + extension, Browser .currentScene [toString] ());
122
121
  }
123
122
  catch (error)
124
123
  {
@@ -151,7 +150,9 @@ $(() =>
151
150
  });
152
151
  </script>
153
152
 
154
- <p>Convert X3D, VRML, glTF, GLB, OBJ, STL, and SVG to a X3D format.</p>
153
+ ## Upload and Convert
154
+
155
+ Convert **X3D, VRML, glTF (GLB), OBJ, STL,** and **SVG** to a X3D format of your choice.
155
156
 
156
157
  <div id="drop-zone">
157
158
  <p id="open-files" class="center">
@@ -171,8 +172,12 @@ $(() =>
171
172
  </p>
172
173
  </div>
173
174
 
174
- ## Converted Files
175
+ ### Converted Files
175
176
 
176
177
  Your converted files will appear here.
177
178
 
178
179
  <ul id="download-links"></ul>
180
+
181
+ ## Command Line Tool
182
+
183
+ If you are looking for a command line tool to convert files, have a look at [x3d-tidy](https://www.npmjs.com/package/x3d-tidy){:target="_blank"}. It is a [Node](https://nodejs.org/) program and it can be run via `npx x3d-tidy`.
@@ -41,6 +41,12 @@ table.examples td {
41
41
  </tr>
42
42
  </table>
43
43
 
44
+ Also have a look at the [Online X3D File Format Converter](x3d-file-converter).
45
+
46
+ ## X3D-Tidy
47
+
48
+ [x3d-tidy](https://www.npmjs.com/package/x3d-tidy){:target="_blank"} is a command line X3D file format converter, compressor and beautifier and available on NPM.
49
+
44
50
  ## D3-X3D
45
51
 
46
52
  [D3-X3D](https://github.com/jamesleesaunders/d3-x3d#d3-x3d){:target="_blank"} is an external JavaScript library that combines the power of **D3.js** with X3D and can be found on GitHub.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "x_ite",
3
- "version": "8.6.2",
3
+ "version": "8.6.4",
4
4
  "description": "X_ITE X3D Browser, view and manipulate X3D and VRML scenes in HTML.",
5
5
  "homepage": "https://create3000.github.io/x_ite/",
6
6
  "author": "Holger Seelig <holger.seelig@gmail.com>",
@@ -45,4 +45,4 @@
45
45
  *
46
46
  ******************************************************************************/
47
47
 
48
- export default "8.6.2";
48
+ export default "8.6.4";
@@ -272,37 +272,44 @@ OBJParser .prototype = Object .assign (Object .create (X3DParser .prototype),
272
272
  },
273
273
  mtllib: async function (path)
274
274
  {
275
- const
276
- scene = this .getExecutionContext (),
277
- url = new URL (path, scene .getWorldURL ());
275
+ try
276
+ {
277
+ const
278
+ scene = this .getExecutionContext (),
279
+ url = new URL (path, scene .getWorldURL ());
278
280
 
279
- const input = await fetch (url)
280
- .then (response => response .arrayBuffer ())
281
- .then (arrayBuffer => $.decodeText ($.ungzip (arrayBuffer)))
282
- .catch (Function .prototype);
281
+ const input = await fetch (url)
282
+ .then (response => response .arrayBuffer ())
283
+ .then (arrayBuffer => $.decodeText ($.ungzip (arrayBuffer)))
284
+ .catch (Function .prototype);
283
285
 
284
- const parser = new MaterialParser (scene, input);
286
+ const parser = new MaterialParser (scene, input);
285
287
 
286
- parser .parse ();
288
+ parser .parse ();
287
289
 
288
- for (const [name, material] of parser .materials)
289
- {
290
- const nodeName = this .sanitizeName (name);
290
+ for (const [name, material] of parser .materials)
291
+ {
292
+ const nodeName = this .sanitizeName (name);
291
293
 
292
- if (nodeName)
293
- scene .addNamedNode (scene .getUniqueName (nodeName), material);
294
+ if (nodeName)
295
+ scene .addNamedNode (scene .getUniqueName (nodeName), material);
294
296
 
295
- this .materials .set (name, material);
296
- }
297
+ this .materials .set (name, material);
298
+ }
297
299
 
298
- for (const [name, texture] of parser .textures)
299
- {
300
- const nodeName = this .sanitizeName (name);
300
+ for (const [name, texture] of parser .textures)
301
+ {
302
+ const nodeName = this .sanitizeName (name);
301
303
 
302
- if (nodeName)
303
- scene .addNamedNode (scene .getUniqueName (nodeName), texture);
304
+ if (nodeName)
305
+ scene .addNamedNode (scene .getUniqueName (nodeName), texture);
304
306
 
305
- this .textures .set (name, texture);
307
+ this .textures .set (name, texture);
308
+ }
309
+ }
310
+ catch (error)
311
+ {
312
+ console .warn (error);
306
313
  }
307
314
  },
308
315
  usemtl: function ()
@@ -143,7 +143,7 @@ function SVGParser (scene)
143
143
  fillURL: "",
144
144
  fillOpacity: 1,
145
145
  fillRule: "nonzero",
146
- strokeType: "NONE",
146
+ strokeType: "none",
147
147
  strokeColor: Color4 .Black,
148
148
  strokeURL: "",
149
149
  strokeOpacity: 1,
@@ -151,6 +151,7 @@ function SVGParser (scene)
151
151
  opacity: 1,
152
152
  stopColor: Color4 .Black,
153
153
  stopOpacity: 1,
154
+ vectorEffect: "none",
154
155
  }];
155
156
  }
156
157
 
@@ -260,14 +261,31 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
260
261
  // Get attributes of svg element.
261
262
 
262
263
  const
263
- viewBox = this .viewBoxAttribute (xmlElement .getAttribute ("viewBox"), new Vector4 (0, 0, 100, 100)),
264
- width = this .lengthAttribute (xmlElement .getAttribute ("width", viewBox [2])),
265
- height = this .lengthAttribute (xmlElement .getAttribute ("height", viewBox [3]));
264
+ defaultWidth = this .lengthAttribute (xmlElement .getAttribute ("width"), 300),
265
+ defaultHeight = this .lengthAttribute (xmlElement .getAttribute ("height"), 150),
266
+ defaultViewBox = new Vector4 (0, 0, defaultWidth, defaultHeight),
267
+ viewBox = this .viewBoxAttribute (xmlElement .getAttribute ("viewBox"), defaultViewBox),
268
+ width = this .lengthAttribute (xmlElement .getAttribute ("width"), viewBox [2]),
269
+ height = this .lengthAttribute (xmlElement .getAttribute ("height"), viewBox [3]);
270
+
271
+ if (true) // default
272
+ {
273
+ // preserveAspectRatio="xMidYMid meet"
274
+
275
+ const
276
+ r = width / height,
277
+ rv = viewBox [2] / viewBox [3];
278
+
279
+ if (rv > r)
280
+ viewBox [3] += viewBox [2] / r - viewBox [3];
281
+ else
282
+ viewBox [2] += viewBox [3] * r - viewBox [2];
283
+ }
266
284
 
267
285
  // Create viewpoint.
268
286
 
269
287
  const
270
- viewpoint = scene .createNode ("OrthoViewpoint",),
288
+ viewpoint = scene .createNode ("OrthoViewpoint"),
271
289
  x = (viewBox .x + width / 2) * PIXEL,
272
290
  y = -(viewBox .y + height / 2) * PIXEL;
273
291
 
@@ -509,7 +527,7 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
509
527
 
510
528
  // Create nodes.
511
529
 
512
- if (this .style .fillType !== "NONE")
530
+ if (this .style .fillType !== "none")
513
531
  {
514
532
  const
515
533
  shapeNode = scene .createNode ("Shape"),
@@ -523,7 +541,7 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
523
541
  transformNode .children .push (shapeNode);
524
542
  }
525
543
 
526
- if (this .style .strokeType !== "NONE")
544
+ if (this .style .strokeType !== "none")
527
545
  {
528
546
  const
529
547
  shapeNode = scene .createNode ("Shape"),
@@ -571,7 +589,7 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
571
589
 
572
590
  // Create nodes.
573
591
 
574
- if (this .style .fillType !== "NONE")
592
+ if (this .style .fillType !== "none")
575
593
  {
576
594
  const
577
595
  shapeNode = scene .createNode ("Shape"),
@@ -585,7 +603,7 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
585
603
  transformNode .children .push (shapeNode);
586
604
  }
587
605
 
588
- if (this .style .strokeType !== "NONE")
606
+ if (this .style .strokeType !== "none")
589
607
  {
590
608
  const
591
609
  shapeNode = scene .createNode ("Shape"),
@@ -628,7 +646,7 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
628
646
 
629
647
  // Create nodes.
630
648
 
631
- if (this .style .fillType !== "NONE")
649
+ if (this .style .fillType !== "none")
632
650
  {
633
651
  const
634
652
  shapeNode = scene .createNode ("Shape"),
@@ -642,7 +660,7 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
642
660
  transformNode .children .push (shapeNode);
643
661
  }
644
662
 
645
- if (this .style .strokeType !== "NONE")
663
+ if (this .style .strokeType !== "none")
646
664
  {
647
665
  const
648
666
  shapeNode = scene .createNode ("Shape"),
@@ -729,7 +747,7 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
729
747
 
730
748
  coordinateNode .point .push (... points);
731
749
 
732
- if (this .style .fillType !== "NONE")
750
+ if (this .style .fillType !== "none")
733
751
  {
734
752
  const
735
753
  shapeNode = scene .createNode ("Shape"),
@@ -745,7 +763,7 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
745
763
  transformNode .children .push (shapeNode);
746
764
  }
747
765
 
748
- if (this .style .strokeType !== "NONE")
766
+ if (this .style .strokeType !== "none")
749
767
  {
750
768
  const
751
769
  shapeNode = scene .createNode ("Shape"),
@@ -801,7 +819,7 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
801
819
  for (const points of contours)
802
820
  coordinateNode .point .push (... points);
803
821
 
804
- if (this .style .fillType !== "NONE")
822
+ if (this .style .fillType !== "none")
805
823
  {
806
824
  const
807
825
  shapeNode = scene .createNode ("Shape"),
@@ -817,7 +835,7 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
817
835
  transformNode .children .push (shapeNode);
818
836
  }
819
837
 
820
- if (this .style .strokeType !== "NONE")
838
+ if (this .style .strokeType !== "none")
821
839
  {
822
840
  const
823
841
  shapeNode = scene .createNode ("Shape"),
@@ -855,7 +873,7 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
855
873
  for (const [o, c, a] of g .stops)
856
874
  gradient .addColorStop (o, `rgba(${c .r * 255},${c .g * 255},${c .b * 255},${a})`);
857
875
 
858
- return this .drawGradient (gradient, g .transform, bbox);
876
+ return this .drawGradient (gradient, g, bbox);
859
877
  },
860
878
  linearGradientElement: function (xmlElement, gradient)
861
879
  {
@@ -873,9 +891,9 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
873
891
 
874
892
  gradient .x1 = this .lengthAttribute (xmlElement .getAttribute ("x1"), gradient .x1 || 0);
875
893
  gradient .y1 = this .lengthAttribute (xmlElement .getAttribute ("y1"), gradient .y1 || 0);
876
- gradient .x2 = this .lengthAttribute (xmlElement .getAttribute ("x2"), gradient .x2 || 0);
894
+ gradient .x2 = this .lengthAttribute (xmlElement .getAttribute ("x2"), gradient .x2 || 1);
877
895
  gradient .y2 = this .lengthAttribute (xmlElement .getAttribute ("y2"), gradient .y2 || 0);
878
- gradient .units = xmlElement .getAttribute ("gradientUnits");
896
+ gradient .units = xmlElement .getAttribute ("gradientUnits") || "objectBoundingBox";
879
897
  gradient .transform = this .transformAttribute (xmlElement .getAttribute ("gradientTransform"));
880
898
 
881
899
  // Stops
@@ -889,12 +907,12 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
889
907
  {
890
908
  const
891
909
  g = this .radialGradientElement (xmlElement, { stops: [ ] }),
892
- gradient = this .context .createRadialGradient (g .fx, g .fy, 0, g .cx, g .cy, g .r);
910
+ gradient = this .context .createRadialGradient (g .fx, g .fy, g. fr, g .cx, g .cy, g .r);
893
911
 
894
912
  for (const [o, c, a] of g .stops)
895
913
  gradient .addColorStop (o, `rgba(${c .r * 255},${c .g * 255},${c .b * 255},${a})`);
896
914
 
897
- return this .drawGradient (gradient, g .transform, bbox);
915
+ return this .drawGradient (gradient, g, bbox);
898
916
  },
899
917
  radialGradientElement: function (xmlElement, gradient)
900
918
  {
@@ -907,14 +925,13 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
907
925
 
908
926
  // Attributes
909
927
 
910
- gradient .cx = this .lengthAttribute (xmlElement .getAttribute ("cx"), gradient .cx || 0),
911
- gradient .cy = this .lengthAttribute (xmlElement .getAttribute ("cy"), gradient .cy || 0),
912
- gradient .x2 = this .lengthAttribute (xmlElement .getAttribute ("x2"), gradient .x2 || 0),
913
- gradient .y2 = this .lengthAttribute (xmlElement .getAttribute ("y2"), gradient .y2 || 0),
914
- gradient .r = this .lengthAttribute (xmlElement .getAttribute ("r"), gradient .cx),
915
- gradient .fx = this .lengthAttribute (xmlElement .getAttribute ("fx"), gradient .cx),
916
- gradient .fy = this .lengthAttribute (xmlElement .getAttribute ("fy"), gradient .cy),
917
- gradient .units = xmlElement .getAttribute ("gradientUnits");
928
+ gradient .cx = this .lengthAttribute (xmlElement .getAttribute ("cx"), gradient .cx || 0.5),
929
+ gradient .cy = this .lengthAttribute (xmlElement .getAttribute ("cy"), gradient .cy || 0.5),
930
+ gradient .r = this .lengthAttribute (xmlElement .getAttribute ("r"), gradient .r || 0.5),
931
+ gradient .fx = this .lengthAttribute (xmlElement .getAttribute ("fx"), gradient .fx || gradient .cx),
932
+ gradient .fy = this .lengthAttribute (xmlElement .getAttribute ("fy"), gradient .fy || gradient .cy),
933
+ gradient .fr = this .lengthAttribute (xmlElement .getAttribute ("fr"), gradient .fr || 0),
934
+ gradient .units = xmlElement .getAttribute ("gradientUnits") || "objectBoundingBox";
918
935
  gradient .spreadMethod = xmlElement .getAttribute ("spreadMethod");
919
936
  gradient .transform = this .transformAttribute (xmlElement .getAttribute ("gradientTransform"));
920
937
 
@@ -956,15 +973,20 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
956
973
 
957
974
  this .styles .pop ();
958
975
  },
959
- drawGradient: function (gradient, transform, bbox)
976
+ drawGradient: function (gradient, g, bbox)
960
977
  {
961
978
  const m = new Matrix3 ();
962
979
 
963
980
  m .scale (new Vector2 (GRADIENT_SIZE / 2, GRADIENT_SIZE / 2));
964
981
  m .translate (Vector2 .One);
965
982
  m .scale (new Vector2 (1, -1));
966
- m .multLeft (Matrix3 .inverse (bbox .matrix));
967
- m .multLeft (transform);
983
+
984
+ if (g .units === "userSpaceOnUse")
985
+ m .multLeft (Matrix3 .inverse (bbox .matrix));
986
+ else
987
+ m .multLeft (new Matrix3 (2, 0, 0, 0, 2, 0, -1, -1, 1));
988
+
989
+ m .multLeft (g .transform);
968
990
 
969
991
  // Paint.
970
992
 
@@ -1028,7 +1050,7 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
1028
1050
  {
1029
1051
  if (!attribute)
1030
1052
  return;
1031
-
1053
+
1032
1054
  const
1033
1055
  scene = this .getExecutionContext (),
1034
1056
  hash = new URL (attribute, scene .getWorldURL ()) .hash .slice (1);
@@ -1535,14 +1557,14 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
1535
1557
  case 'S':
1536
1558
  case 's':
1537
1559
  {
1538
- x1 = ax + (ax - px);
1539
- y1 = ay + (ay - py);
1560
+ var x1 = ax + (ax - px);
1561
+ var y1 = ay + (ay - py);
1540
1562
  break;
1541
1563
  }
1542
1564
  default:
1543
1565
  {
1544
- x1 = ax;
1545
- y1 = ay;
1566
+ var x1 = ax;
1567
+ var y1 = ay;
1546
1568
  break;
1547
1569
  }
1548
1570
  }
@@ -1757,16 +1779,20 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
1757
1779
  {
1758
1780
  if (this .double ())
1759
1781
  {
1760
- const ty = this .value;
1782
+ var ty = this .value;
1783
+ }
1784
+ }
1785
+ else
1786
+ {
1787
+ var ty = 0;
1788
+ }
1761
1789
 
1762
- this .whitespaces ();
1790
+ this .whitespaces ();
1763
1791
 
1764
- if (Grammar .closeParenthesis .parse (this))
1765
- {
1766
- matrix .translate (new Vector2 (tx, ty));
1767
- continue;
1768
- }
1769
- }
1792
+ if (Grammar .closeParenthesis .parse (this))
1793
+ {
1794
+ matrix .translate (new Vector2 (tx, ty));
1795
+ continue;
1770
1796
  }
1771
1797
  }
1772
1798
  }
@@ -1833,16 +1859,20 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
1833
1859
  {
1834
1860
  if (this .double ())
1835
1861
  {
1836
- const sy = this .value;
1862
+ var sy = this .value;
1863
+ }
1864
+ }
1865
+ else
1866
+ {
1867
+ var sy = sx;
1868
+ }
1837
1869
 
1838
- this .whitespaces ();
1870
+ this .whitespaces ();
1839
1871
 
1840
- if (Grammar .closeParenthesis .parse (this))
1841
- {
1842
- matrix .scale (new Vector2 (sx, sy));
1843
- continue;
1844
- }
1845
- }
1872
+ if (Grammar .closeParenthesis .parse (this))
1873
+ {
1874
+ matrix .scale (new Vector2 (sx, sy));
1875
+ continue;
1846
1876
  }
1847
1877
  }
1848
1878
  }
@@ -1906,6 +1936,7 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
1906
1936
  "opacity",
1907
1937
  "stop-color",
1908
1938
  "stop-opacity",
1939
+ "vector-effect",
1909
1940
  ];
1910
1941
 
1911
1942
  return function (xmlElement)
@@ -1984,6 +2015,9 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
1984
2015
  case "stop-opacity":
1985
2016
  this .stopOpacityStyle (value);
1986
2017
  break;
2018
+ case "vector-effect":
2019
+ this .vectorEffectStyle (value);
2020
+ break;
1987
2021
  }
1988
2022
  },
1989
2023
  displayStyle: function (value)
@@ -2013,13 +2047,13 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
2013
2047
 
2014
2048
  if (value === "transparent")
2015
2049
  {
2016
- this .style .fillType = "NONE";
2050
+ this .style .fillType = "none";
2017
2051
  return;
2018
2052
  }
2019
2053
 
2020
2054
  if (value === "none")
2021
2055
  {
2022
- this .style .fillType ="NONE";
2056
+ this .style .fillType ="none";
2023
2057
  return;
2024
2058
  }
2025
2059
 
@@ -2072,13 +2106,13 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
2072
2106
 
2073
2107
  if (value === "transparent")
2074
2108
  {
2075
- this .style .strokeType = "NONE";
2109
+ this .style .strokeType = "none";
2076
2110
  return;
2077
2111
  }
2078
2112
 
2079
2113
  if (value === "none")
2080
2114
  {
2081
- this .style .strokeType ="NONE";
2115
+ this .style .strokeType ="none";
2082
2116
  return;
2083
2117
  }
2084
2118
 
@@ -2120,7 +2154,7 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
2120
2154
  {
2121
2155
  if (this .double ())
2122
2156
  {
2123
- this .style .strokeWidth = this .value / (1000 * PIXEL);
2157
+ this .style .strokeWidth = this .lengthAttribute (this .value);
2124
2158
  return;
2125
2159
  }
2126
2160
 
@@ -2170,6 +2204,18 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
2170
2204
  return;
2171
2205
  }
2172
2206
  },
2207
+ vectorEffectStyle: function (value)
2208
+ {
2209
+ if (value !== "inherit")
2210
+ {
2211
+ this .style .vectorEffect = value;
2212
+ return;
2213
+ }
2214
+
2215
+ // inherit
2216
+
2217
+ this .style .vectorEffect = this .styles .at (-1) .vectorEffect;
2218
+ },
2173
2219
  parseValue: function (value)
2174
2220
  {
2175
2221
  this .input = value;
@@ -2284,7 +2330,7 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
2284
2330
 
2285
2331
  switch (this .style .fillType)
2286
2332
  {
2287
- case "NONE":
2333
+ case "none":
2288
2334
  {
2289
2335
  return null;
2290
2336
  }
@@ -2349,16 +2395,28 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
2349
2395
  materialNode .emissiveColor = new Color3 (... this .style .strokeColor);
2350
2396
  materialNode .transparency = 1 - this .style .strokeOpacity * this .style .opacity;
2351
2397
 
2352
- if (this .style .strokeWidth !== 1)
2398
+ const strokeWidth = this .vectorEffect === "non-scaling-stroke"
2399
+ ? this .style .strokeWidth
2400
+ : this .getStokeWidth ();
2401
+
2402
+ if (strokeWidth > 1)
2353
2403
  {
2354
2404
  const lineProperties = scene .createNode ("LineProperties");
2355
2405
 
2356
2406
  appearanceNode .lineProperties = lineProperties;
2357
- lineProperties .linewidthScaleFactor = this .style .strokeWidth;
2407
+ lineProperties .linewidthScaleFactor = strokeWidth;
2358
2408
  }
2359
2409
 
2360
2410
  return appearanceNode;
2361
2411
  },
2412
+ getStokeWidth: function ()
2413
+ {
2414
+ const
2415
+ modelMatrix = this .getModelMatrix (),
2416
+ strokeWidth = modelMatrix .multDirMatrix (new Vector3 (this .style .strokeWidth, this .style .strokeWidth, 0));
2417
+
2418
+ return (strokeWidth .x + strokeWidth .y) / 2;
2419
+ },
2362
2420
  createTextureProperties: function ()
2363
2421
  {
2364
2422
  const
@@ -2387,6 +2445,26 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
2387
2445
 
2388
2446
  return texCoordNode;
2389
2447
  },
2448
+ getModelMatrix: function ()
2449
+ {
2450
+ const modelMatrix = new Matrix4 ();
2451
+
2452
+ for (let i = 1; i < this .groupNodes .length; ++ i)
2453
+ {
2454
+ const
2455
+ node = this .groupNodes [i],
2456
+ matrix = new Matrix4 ();
2457
+
2458
+ matrix .set (node .translation .getValue (),
2459
+ node .rotation .getValue (),
2460
+ node .scale .getValue (),
2461
+ node .scaleOrientation .getValue ());
2462
+
2463
+ modelMatrix .multLeft (matrix);
2464
+ }
2465
+
2466
+ return modelMatrix;
2467
+ },
2390
2468
  createTesselator: function ()
2391
2469
  {
2392
2470
  // Function called for each vertex of tessellator output.
@@ -142,11 +142,12 @@ X3DParser .prototype = {
142
142
  convertColor: function (value)
143
143
  {
144
144
  const
145
- div = $("<div></div>") .hide () .css ("color", value) .appendTo ($("body")),
145
+ wrap = $("<div></div>") .hide () .css ("color", "black") .appendTo ($("body")),
146
+ div = $("<div></div>").css ("color", value) .appendTo (wrap),
146
147
  rgb = window .getComputedStyle (div [0]) .color,
147
148
  values = rgb .replace (/^rgba?\(|\)$/g, "") .split (/[\s,]+/) .map (s => parseFloat (s));
148
149
 
149
- div .remove ();
150
+ wrap .remove ();
150
151
 
151
152
  values [0] /= 255;
152
153
  values [1] /= 255;