Skip to content
This repository has been archived by the owner on Apr 4, 2022. It is now read-only.

Commit

Permalink
Refactor args parsing (fixes #40)
Browse files Browse the repository at this point in the history
  • Loading branch information
hmans committed Jan 29, 2021
1 parent 717d21e commit badc9dc
Show file tree
Hide file tree
Showing 14 changed files with 143 additions and 29 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
<three-perspective-camera position="0, 5, -15" fov="45" active></three-perspective-camera>
```

- **New:** You no longer have to use valid JSON syntax for `arg` attributes -- just provide a list of comma-separated values:

```html
<three-fog args="#333333, 1, 1000"></three-fog>
```

The commas, in fact, are now purely optional. This will also work:

```html
<three-fog args="#333333 1 1000"></three-fog>
```

- **Changed:** When attributes on an element map to a non-existing property on the wrapped object, there will no longer be a warning logged to the console. (This is very useful when you're combining three-elements with other frameworks that make use of their own attribute names on your elements.)

- **Fixed:** When assigning attributes a value of "0", this will now correctly assign the parsed numerical value of 0 to the corresponding property, not a string representation of it. Programming, how does it work?
Expand Down
4 changes: 2 additions & 2 deletions examples/rectarealights.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@

<!-- torus knot -->
<three-mesh position.y="5" ontick="this.object.rotation.y = performance.now() / 1000">
<three-torus-knot-geometry args="[1.5, 0.5, 200, 16]"></three-torus-knot-geometry>
<three-torus-knot-geometry args="1.5, 0.5, 200, 16"></three-torus-knot-geometry>
<three-mesh-standard-material
color="#fff"
metalness="0"
Expand All @@ -40,7 +40,7 @@

<!-- floor -->
<three-mesh>
<three-box-geometry args="[2000, 0.1, 2000]"></three-box-geometry>
<three-box-geometry args="2000, 0.1, 2000"></three-box-geometry>
<three-mesh-standard-material
color="#808080"
metalness="0"
Expand Down
48 changes: 37 additions & 11 deletions examples/reusing-resources.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,50 @@
</head>
<body>
<three-game autorender>
<three-scene background-color="#222" ontick="this.object.rotateY(0.01)">
<three-scene background-color="#222">
<!-- Lights -->
<three-ambient-light intensity="0.2"></three-ambient-light>
<three-directional-light
intensity="0.8"
position="10, 40, 50"
cast-shadow
></three-directional-light>
<three-directional-light intensity="0.8" position="10, 40, 50"></three-directional-light>

<!-- resources we'll reuse -->
<three-box-buffer-geometry id="geometry"></three-box-buffer-geometry>
<three-box-buffer-geometry id="geometry" args="1, 5, 1"></three-box-buffer-geometry>
<three-mesh-standard-material id="material" color="#555"></three-mesh-standard-material>

<!-- Scene Contents -->
<three-mesh position="-2, 0, 0" geometry="#geometry" material="#material"></three-mesh>
<three-mesh position="0, 0, 0" geometry="#geometry" material="#material"></three-mesh>
<three-mesh position="2, 0, 0" geometry="#geometry" material="#material"></three-mesh>

<three-group ontick="this.object.rotateX(0.001); this.object.rotateY(0.002)">
<three-mesh
geometry="#geometry"
material="#material"
position="-3.5, 0, 0"
scale="0.7"
ontick="this.object.rotation.x = this.object.rotation.y += 0.03"
></three-mesh>
<three-mesh
position="-2, 0, 0"
geometry="#geometry"
material="#material"
ontick="this.object.rotation.x = this.object.rotation.y += 0.015"
></three-mesh>
<three-mesh
position="0, 0, 0"
geometry="#geometry"
material="#material"
scale="1.5"
></three-mesh>
<three-mesh
position="2, 0, 0"
geometry="#geometry"
material="#material"
ontick="this.object.rotation.x = this.object.rotation.y -= 0.015"
></three-mesh>
<three-mesh
position="3.5, 0, 0"
geometry="#geometry"
material="#material"
scale="0.7"
ontick="this.object.rotation.x = this.object.rotation.y -= 0.03"
></three-mesh>
</three-group>
<three-orbit-controls></three-orbit-controls>
</three-scene>
</three-game>
Expand Down
2 changes: 1 addition & 1 deletion examples/static.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

<!-- Scene Contents -->
<three-mesh rotation="-90deg, 0, 0" position.y="-8" receive-shadow>
<three-plane-buffer-geometry args="[1000, 1000]"></three-plane-buffer-geometry>
<three-plane-buffer-geometry args="1000, 1000"></three-plane-buffer-geometry>
<three-mesh-standard-material color="#ccc"></three-mesh-standard-material>
</three-mesh>

Expand Down
2 changes: 1 addition & 1 deletion examples/vr.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

<!-- Scene Contents -->
<three-mesh rotation="-90deg, 0, 0" position.y="-8" receive-shadow>
<three-plane-buffer-geometry args="[1000, 1000]"></three-plane-buffer-geometry>
<three-plane-buffer-geometry args="1000, 1000"></three-plane-buffer-geometry>
<three-mesh-standard-material color="#ccc"></three-mesh-standard-material>
</three-mesh>

Expand Down
4 changes: 2 additions & 2 deletions site/docs/guide/the-basics.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,8 @@ You can also use **dotty attributes** to set nested properties:

## Constructor Arguments

Every element will create its own instance of its corresponding class. The `args` attribute allows you to provide a list of constructor arguments as a JSON array.
Every element will create its own instance of its corresponding class. The `args` attribute allows you to provide a list of constructor arguments:

```html
<three-box-buffer-geometry args="[2, 1, 1]"></three-box-buffer-geometry>
<three-box-buffer-geometry args="2, 1, 1"></three-box-buffer-geometry>
```
4 changes: 2 additions & 2 deletions site/docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ footer: MIT Licensed | Copyright © 2021-present Hendrik Mans
</three-mesh>

<!-- A floor. We like shadows. Shadows good! -->
<three-mesh rotation="[-1.5707, 0, 0]" position.y="-7" receive-shadow>
<three-mesh rotation="-1.5707, 0, 0" position.y="-7" receive-shadow>
<three-plane-buffer-geometry
args="[1000, 1000, 32]"
args="1000, 1000, 32"
></three-plane-buffer-geometry>
<three-mesh-standard-material color="#888"></three-mesh-standard-material>
</three-mesh>
Expand Down
5 changes: 3 additions & 2 deletions src/ThreeElement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as THREE from "three"
import { BaseElement } from "./BaseElement"
import { IConstructable, isDisposable } from "./types"
import { applyProps } from "./util/applyProps"
import { attributeValueToArray } from "./util/attributeValueToArray"

export class ThreeElement<T = any> extends BaseElement {
/** Constructor that will instantiate our object. */
Expand All @@ -27,9 +28,9 @@ export class ThreeElement<T = any> extends BaseElement {

/* Create managed object */
const args = this.getAttribute("args")

if (args) {
const parsed = JSON.parse(args)
object = new constructor(...(Array.isArray(parsed) ? parsed : [parsed]))
object = new constructor(...attributeValueToArray(args))
} else {
object = new constructor()
}
Expand Down
10 changes: 3 additions & 7 deletions src/util/applyProps.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { IStringIndexable } from "../types"
import { camelize } from "./camelize"
import { MathUtils } from "three"
import { getThreeObjectBySelector } from "./getThreeObjectBySelector"
import { attributeValueToArray } from "./attributeValueToArray"
import { parseDeg } from "./parseDeg"

const IGNORED_KEYS = ["id"]

Expand Down Expand Up @@ -58,7 +59,7 @@ export const applyProps = (object: IStringIndexable, props: IStringIndexable) =>
}

/* Otherwise, set the original string value, but split by commas */
const list = value.split(",").map((el: string) => parseJson(el) ?? parseDeg(el) ?? el)
const list = attributeValueToArray(value)
object[key].set(...list)
return
}
Expand Down Expand Up @@ -96,8 +97,3 @@ const parseJson = (value: string) => {

return parsed
}

const parseDeg = (value: string) => {
const r = value.trim().match(/^([0-9\.\- ]+)deg$/)
if (r) return MathUtils.degToRad(parseFloat(r[1]))
}
12 changes: 12 additions & 0 deletions src/util/attributeValueToArray.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { parseDeg } from "./parseDeg"

export const attributeValueToArray = (value: string) =>
value
.split(/[, ]+/)
.map((s) => s.trim())
.map((s) => parseDeg(s) ?? floatOrNot(s))

const floatOrNot = (s: string) => {
const f = parseFloat(s)
return f || f === 0 ? f : s
}
6 changes: 6 additions & 0 deletions src/util/parseDeg.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { MathUtils } from "three"

export const parseDeg = (value: string) => {
const r = value.trim().match(/^([0-9\.\- ]+)deg$/)
if (r) return MathUtils.degToRad(parseFloat(r[1]))
}
25 changes: 25 additions & 0 deletions test/args.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { expect, fixture, html, nextFrame } from "@open-wc/testing"
import "../src"
import { ThreeElement } from "../src/ThreeElement"

describe("the args attribute", () => {
const render = () =>
fixture(html`
<three-game>
<three-scene>
<three-mesh>
<three-fog args="#333333, 1, 1000"></three-fog>
</three-mesh>
</three-scene>
</three-game>
`)

it("provides the arguments for the Three.js constructor", async () => {
const game = await render()
const fog = game.querySelector("three-fog") as ThreeElement

await nextFrame()

expect(fog.object.color.getHexString()).to.equal("333333")
})
})
2 changes: 1 addition & 1 deletion test/util/applyProps.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ describe("applyProps", () => {
const object = {
foo: new THREE.Vector3()
}
applyProps(object, { foo: "90deg, 1.23, -90deg" })
applyProps(object, { foo: "90deg 1.23 -90deg" })
expect(object.foo.x).to.equal(Math.PI / 2)
expect(object.foo.y).to.equal(1.23)
expect(object.foo.z).to.equal(Math.PI / -2)
Expand Down
36 changes: 36 additions & 0 deletions test/util/attributeValueToArray.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { expect } from "@open-wc/testing"
import { attributeValueToArray } from "../../src/util/attributeValueToArray"

describe("attributeValueToArray", () => {
it("parses a singular string value to an array containing the string", () => {
expect(attributeValueToArray("foo")).to.eql(["foo"])
})

it("parses a singular numerical value to an array containing the number", () => {
expect(attributeValueToArray("123")).to.eql([123])
})

it("parses a '0' to the number 0", () => {
expect(attributeValueToArray("0")).to.eql([0])
})

it("parses a list of numerical values to an array containing those numbers", () => {
expect(attributeValueToArray("123, 0, -123")).to.eql([123, 0, -123])
})

it("parses a list of strings to an array containing those strings", () => {
expect(attributeValueToArray("foo, bar")).to.eql(["foo", "bar"])
})

it("parses a list of mixed value types to an array containing the correct values", () => {
expect(attributeValueToArray("foo, 0, 1, bar")).to.eql(["foo", 0, 1, "bar"])
})

it("also works without a comma", () => {
expect(attributeValueToArray("foo 0 1 bar")).to.eql(["foo", 0, 1, "bar"])
})

it("also works with floating point values", () => {
expect(attributeValueToArray("-0.5 +0.5")).to.eql([-0.5, 0.5])
})
})

0 comments on commit badc9dc

Please sign in to comment.