Avoiding label overlap with JavaScript

I've mapped a textured image onto a sphere and added labels to it, but some of the labels are overlapping. I'm looking for ways to separate them without altering the "lon" and "lat" values. Could someone please advise me on how to achieve this or suggest methods for repositioning the labels? Additionally, I have provided a link to the uploaded image and the complete code. Any help with this issue would be greatly appreciated.

The CSS code used in this program:

div.spritelabel {
position:absolute;
top:0px;
left:0px;
color:#0000FF;
font-family: 'Trebuchet MS', sans-serif;
font-size:15px;
font-weight:normal;
line-height:15px;
text-align: left;
padding:5px;

-webkit-box-shadow: 0px 4px 8px -3px rgba(0,0,0,0.75);
-moz-box-shadow: 0px 4px 8px -3px rgba(0,0,0,0.75);
box-shadow: 0px 4px 8px -5px rgba(0,0,0,0.75);
background:rgba( 255, 255, 255, 0.8 );
}
a:link {color: brown; background-color: transparent; text-decoration: none;}
a:visited{color: green; background-color: transparent; text-decoration: none;}
a:hover{color: red; background-color: transparent; text-decoration: underline;} 
a:active {color: yellow; background-color: transparent; text-decoration: underline;}

Javascript code:

function createsphere() 
{
var spriteboxes = [];
var sprite,controls,scene,camera,renderer;
var spritearray = [];
spritearray[0] = {"name": "North", "lat":0, "lon": 10};
spritearray[1] = {"name": "south", "lat":0, "lon": 20};
spritearray[2] = {"name": "East", "lat":0, "lon": 30};
spritearray[3] = {"name": "west", "lat":0, "lon": 40};
spritearray[4] = {"name": "North-west", "lat":0, "lon": 45};
spritearray[5] = {"name": "North-east", "lat":0, "lon": 47};
spritearray[6] = {"name": "south-east", "lat":0, "lon": 50};

// Function to convert lat lon to Vector3
function convertlatlonToVec3(lat, lon)
{
    lat = lat * Math.PI / 180.0;
    lon = -lon * Math.PI /180.0;
    return new THREE.Vector3(
        Math.cos(lat)* Math.sin(lon),
        Math.sin(lat)* Math.sin(lon),
        Math.cos(lat));

}

// Constructor function for labelBox
function labelBox(Ncardinal, radius, domElement)
{
    this.screenVector = new THREE.Vector3(0, 0, 0);
    this.position = convertlatlonToVec3(Ncardinal.lat,Ncardinal.lon).multiplyScalar(radius);
    this.box = document.createElement('div');
    a = document.createElement('a');
    a.innerHTML = Ncardinal.name;
    a.href ='http://www.google.de';
    this.box.className = "spritelabel";
    this.box.appendChild(a);

    this.domElement = domElement;
    this.domElement.appendChild(this.box);
}

labelBox.prototype.update = function()
{
this.screenVector.copy(this.position);  
this.screenVector.project(camera);

var posx = Math.round((this.screenVector.x + 1)* this.domElement.offsetWidth/2);
var posy = Math.round((1 - this.screenVector.y)* this.domElement.offsetHeight/2);

var boundingRect = this.box.getBoundingClientRect();

// Update the box overlays position
this.box.style.left = (posx - boundingRect.width) + 'px';
this.box.style.top = posy + 'px';

};

// Initialization function
function init() 
{
    // starting scene setup
}

// Animation function
function animate() {

// Update each label box
spriteboxes.forEach(function(e) { e.update()} );
sprite.update();
requestAnimationFrame(animate); 
controls.update();
renderer.render(scene, camera);
}

init();
animate();
}

Answer №1

Since the labels in question are not actual 3D objects, this inquiry is unrelated to three-dimensional aspects. The solution lies in a practical algorithm that can be optimized for handling a larger quantity of labels:

  • 1.) Determine the precise dimensions of each label and save them (by utilizing element.offsetWidth/Height)
  • 2.) Calculate the anchor position for each label on the screen
  • 3.) Arrange all labels using the steps below:
    • a) Estimate the space occupied by the label at its anchor position (represented as a box with top/left, bottom/right coordinates - possibly leverage the THREE.Box2 class)
    • b) Check for overlaps with already positioned boxes on screen (utilize box.intersectsBox(otherBox))
    • c) If there are no overlaps, proceed with placing the label; if overlaps exist, attempt to adjust the position by moving it slightly in various directions until finding a suitable spot. However, set a limit on attempts and skip the label if placement cannot be achieved.

It may not always be feasible to accommodate every label, so prioritizing them beforehand is advisable before attempting insertion.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The controller is unable to retrieve the posted value

Whenever I try to retrieve the post value from my controller, it always returns null. Even though I can see that there is a post value present when I check, for some reason, I am not able to access that value in my controller. Does anyone know what the p ...

Adjust the spacing of a div based on the fluctuating height of another dynamically changing div

Is it possible to dynamically adjust the margin of a div using jQuery or JS? Currently, I have set a margin on a div by calculating the height of a container that includes images. var articleImageHeight = $('.slides_control').height(); $(' ...

Gathering the output from every function within an array of functions

I've searched extensively for a solution to this dilemma, but have had no luck so far. Therefore, I am turning to the community for help. Please feel free to direct me to any existing similar queries. My challenge involves working with an array of fu ...

What is the best way to find out which tab is currently active?

Struggling with Bootstrap 5, I found it challenging to retrieve the activated tab. Even after consulting their documentation, I only managed to obtain the ID of the first button and nothing more. var tabEl = document.querySelector('button[data-bs-t ...

transform the outcome of a $lookup operation into an object rather than an array

When performing a $lookup from a _id, the result is always 1 document. This means that I would like the result to be an object instead of an array with one item. let query = mongoose.model('Discipline').aggregate([ { $match: { ...

Unable to upload gathered email to Mailchimp mailing list through Nodejs and express API

Seeking guidance on integrating data collection with Mailchimp in a Nodejs backend project. I am currently working on an email signup list page where users input their first name, last name, and email. The HTML file contains fields named firstName, lastN ...

AngularJS form submission with and without page refresh

Looking to implement an AngularJS form directive where, if on /home page, redirect to /search/term and if already on /search page, submit without refreshing the page by simply changing the location. I am able to do both separately, but struggling to writ ...

Exploring the combination of Tailwind CSS variants with Framer Motion capabilities

Is it possible to integrate tailwind css classes with framer motion objects effectively? const variant = { hidden: { 'w-0' }, visible: { width: 400, transition: { type: 'spring', stiffness: ...

Is it possible to verify if each value satisfies a condition within a Javascript function?

I am currently working on a project using Vue.js and Laravel where I have a data list named "questions." My goal is to iterate through this list and check if the answer value for each question is not null. If any question has a null answer, I want to preve ...

Arranging the properties of an object following the reduction process

I am currently working on replicating the functionality of an Outlook mailbox by organizing a list of Outlook emails based on their conversation ID. However, I am facing the challenge of needing to sort my list twice - once to order the emails in each grou ...

Having trouble with your jQuery animation on a div?

Check out this jsFiddle example: http://jsfiddle.net/uM68j/ After clicking on one of the links in the demo, the bar is supposed to smoothly slide to the top. However, instead of animating, it immediately jumps to the top. How can I modify the code to ac ...

Sending a variable to a VueJS component

I'm looking to pass a variable down to a component in my current setup. Here's the structure: Main: Meet.vue <html> <div class="carousel-cell"> <Category :searchTerm="woman"></Category> </div> <div cla ...

Looking to update table content dynamically using jQuery ajax?

I need assistance in creating a dynamic table that can update its content based on the company selected from a dropdown menu. The data should be fetched using AJAX and only display information related to the chosen company. Furthermore, I would like to imp ...

Choosing the right CSS selectors for elements within other elements

I'm trying to add a stagger effect to the fade-in animations of images within a gallery. After looking over my code, I believe the issue lies in how I am setting the animation-delay in the CSS selector. I am not sure if SCSS is supported in this snipp ...

How can I turn off a state property?

My goal is to detect if the user is using a device with a screen width smaller than 768px, and if they are, I want to set isTop to false. However, I am encountering some difficulties. Everything seems fine, but I keep receiving this error: TypeError: _t ...

Adjusting the size of images in real time

Currently, I am in the process of creating a Fluid grid style website and I am looking to decrease the size of all images by 75% when the screen is below 1280px, 50% at 800px, and so forth. Is there a way to achieve this using the IMG tag? My attempt so ...

Issue with inheritance from Angular ModalCtrl to ServiceCtrl not functioning as expected

I've been working on linking models to services in order to update global models throughout my app, but it doesn't seem to be functioning as expected. Recently, I delved into AngularJS and I suspect that I may have misunderstood my code. From wh ...

Retrieve the URL of the image from an XML document

Figuring out how to extract the image URL from XML files in Android Studio can be challenging. After analyzing 30 RSS Feed XMLs, I discovered that 95% of them contain ".jpg" images with links starting with "http," not "www." Therefore, I am working on a co ...

Typescript is throwing an error when trying to use MUI-base componentType props within a custom component that is nested within another component

I need help customizing the InputUnstyled component from MUI-base. Everything works fine during runtime, but I am encountering a Typescript error when trying to access the maxLength attribute within componentProps for my custom input created with InputUnst ...

Select a random class from an array of classes in JavaScript

I have a collection of Classes: possibleEnemies: [ Slime, (currently only one available) ], I am trying to randomly pick one of them and assign it to a variable like this (all classes are derived from the Enemy class): this.enemy = new this.possibleEn ...