vasturiano / globe.gl

UI component for Globe Data Visualization using ThreeJS/WebGL
https://vasturiano.github.io/globe.gl/example/world-population/
MIT License
2.03k stars 301 forks source link

Continuous use of pointsData() wipes labels set via labelsData() #52

Closed snshn closed 3 years ago

snshn commented 3 years ago

Describe the bug Calling .pointsData() on an already rendered globe causes it to lose its labels previously set via .labelsData().

To Reproduce Steps to reproduce the behavior: 1.

<head>
  <script src="//unpkg.com/globe.gl"></script>
</head>
<body style="margin:0">
  <div id="viewport"></div>
</body>

2.

// Gen random data
const N = 300;
const gData = [...Array(N).keys()].map(() => ({
  lat: (Math.random() - 0.5) * 180,
  lng: (Math.random() - 0.5) * 360,
  size: Math.random() / 3,
  color: ['red', 'white', 'blue', 'green'][Math.round(Math.random() * 3)]
}));

const globe = Globe()
  .globeImageUrl('//unpkg.com/three-globe/example/img/earth-night.jpg')
  .pointsData(gData)
  .labelsData(gData)
  .labelText(() => "Text")
  .labelSize(2)
  .pointAltitude('size')
  .pointColor('color')
  (document.getElementById('viewport'));

setTimeout(() => {
  globe.pointsData(gData);
  // globe.labelsData(gData);
}, 5000);

Expected behavior Labels should not disappear.

Screenshots N/A

Desktop (please complete the following information):

Smartphone (please complete the following information):

Additional context Calling .labelsData() right after .pointsData() seems to be bringing back labels and render them again after a second or two, but it's definitely a bug that points data interferes with labels data.

vasturiano commented 3 years ago

@snshn thanks for reaching out.

The real issue is the sharing of data objects between layers. Each layer will associate some meta attributes to the data arrays passed onto it, and these are required for proper functioning. If you pass the exact same object reference to multiple layers it is very possible that they will conflict, and doing this is disadvised.

You can simply solve this by cloning the data structure, for instance:

const labelData = gData.map(d => Object.assign({}, d));
snshn commented 3 years ago

@vasturiano

that makes sense, thank you for the explanation and code snippet. I assumed the supplied data was cloned internally by default.