Viewer, apply multiple colors at once

Hi,
I’m updating the Speckle Viewer on my project from 2.2.8 to the latest version. So far I’m loving all of the changes so much (especially all of the types and interfaces!). But I’ve run into an issue.

In the old version I was using the applyFilter method to change the color of the objects on the model. I’ve switched to using the setUserObjectColors method now as that seems to have replaced it (when specifying which color to make which object id’s). But I would like to set different id’s to different colors (eg, make the object with id: “6a4a95c31a754e0c” blue and the object with id: “6e8e8f29” red).

As far as I can tell the interface for the setUserObjectColors method only takes in one set of id’s and one color, so I tried just running setUserObjectColors multiple times, once for each set of id’s/color. But it seems like every time I run that function it resets all of the objects that had already been colored.

My current attempt at a solution that doesn’t work:

// groups = [{ objectIds: string[]; color: string;}][]

groups.forEach(async (group) => {
    await this.viewer.setUserObjectColors(group);
})

Is it possible to set multiple different colors at once with the new viewer without having to start directly changing the Threejs objects? Or is this not currently available? Or am I not understanding something right (the most likely option haha)?

Thanks!

1 Like

Hey @Exilliar, and welcome to the community! The setUserObjectColors method takes an array of objects that look like { objectIds: string[]; color: string;}.

Example usage:

viewer.setUserObjectColors([
  {
    objectIds: [
      'fb70810f971a483d4fb5fb682e82d93b',
      'b3ecedd447c4cf5a316a2012aa0203f9',
      'e464fd34c72c23decd13daca9c480d70',
      '8cb410758876a45500cb66bead31b848'
    ],
    color: '#8b5cf6'
  },
  {
    objectIds: [
      'df0fb33a36920574d871bdfc61a293b8',
      '97fa793822624ef179532882a8bba3bd',
      '02b2d39c2fb75ce241ba87a60d1cefba',
      '06986d19d8e7d6280decee2137f816c8',
      '831f0d944d62fa0aadcee1426a5a4c3a',
      'd5915a54844b30db08a28fb609a2e43f',
      '6b3a510fa659961393f2cdc8170a4577',
      '3270b43a4bb93384cdac235d05f2454b',
      '0a45db8e5cba3e8eb243438b1bde0f01',
      'df54b6545bc1d923caf8d2a4d75572f5',
      'f034f2e68483249324e71292332f178b'
    ],
    color: '#f472b6'
  }
])

Dim/viewer 1201 by didimitrie · Pull Request #1205 · specklesystems/speckle-server · GitHub. I’ve also noticed i need to follow up on the original thread :smiley:

1 Like

Hi @dimitrie , Awesome, thanks!

I guess I was right lol.

I’m using typescript and passing in an array of those objects any larger than one was throwing up some errors which I think is where the confusion came in for me.

I think it’s the difference between

{ objectIds: string[]; color: string; }[] // allows multiple items in the array

and

[{ objectIds: string[]; color: string; }] // allows a single item in the array

that was causing the error on my side (or I’m not understanding the error I got right, also very likely).

I’m a typescript novice too. Afaik

{ objectIds: string[]; color: string; }[]

means of an array of { objectIds: string[]; color: string; } objects that can be empty, ie pass in simply []

whereas the latter:

[{ objectIds: string[]; color: string; }]

means of an array of { objectIds: string[]; color: string; } objects that cannot be empty, ie you cannot pass in [], you’d need to pass in [{etc}]

I might totally be off the mark. I’m still getting bitten by TS quite often :sweat_smile:

Ah, yeah. I think that it actually works a little different.

If you put the [] after the type then that type becomes an array of the type before the []. But if you surround the type in the [] then typescript sees that as an array with only one element, and that element is of the type you chose.

This is so that you can do stuff like make arrays with a type of [string, number]. That would define an array with two elements, where the first is of type string, and the second of type number.

To make typescript require that the array has at least one value is a little tricky afaik. The way I usually try to do it is to just have the first line of the function check that the array has a value. So something like:

function someFunc(arr: string[]) {
    if (arr.length === 0) return; // or throw an error
    // else do some stuff
}

The issue with that though is that it’ll only show the error at runtime, which kinda defeats the point of typescript a little bit? But it’s also easier and eloquent enough (imo).

There is also this stackoverflow which shows a couple ways to make typescript force the array to have at least one entry. The second one seems to be pretty good.

I wrote up some examples of this into this typescript playground which hopefully works.

1 Like