【问题标题】:Preventing overlapping of labels using JavaScript使用 JavaScript 防止标签重叠
【发布时间】:2017-02-04 19:23:03
【问题描述】:

我已将图像纹理化为球体并在图像上附加了标签,但有些标签重叠,我 想要分离标签,而不改变“lon”和“lat”的值。我需要知道如何分隔标签或 如何重新定位标签。而且我已经上传了图片(链接)。而且我已经上传了完整的代码。 请帮我解决这个问题。

本程序使用的css代码

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 代码

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 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));

}

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';



};





function init() 
        {
            scene = new THREE.Scene();
            camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
            camera.position.y = 1;
            camera.position.z = 5;

            var width = window.innerWidth;
            var height = window.innerHeight;
            renderer = new THREE.WebGLRenderer( {antialias:true} );
            renderer.setSize(width, height);
            document.body.appendChild(renderer.domElement);
            var radius = 2.5;
            var spheregeometry = new THREE.SphereGeometry(radius, 20, 20, 0, -6.283, 1, 1);
            var texture =  THREE.ImageUtils.loadTexture ('Sample Images/rbi00000083.jpg');
            texture.minFilter = THREE.NearestFilter;
            var spherematerial = new THREE.MeshBasicMaterial({map: texture});
            var sphere = new THREE.Mesh(spheregeometry, spherematerial);

            scene.add(sphere);
            scene.add(camera);
            scene.autoUpdate = true;

            controls = new THREE.OrbitControls(camera, renderer.domElement);
            controls.minPolarAngle = Math.PI/4;
            controls.maxPolarAngle = 3*Math.PI/4;

            for(var i = 0; i< spritearray.length;i++)
            {
                var Ncardinal = spritearray[i];
                sprite =  new labelBox(Ncardinal, radius, document.body);
                //this.marker = new THREE.Mesh(new THREE.SphereGeometry(0.05, 30, 30));
                //this.marker.position.copy(sprite.position);
                //scene.add(marker);
                spriteboxes.push(sprite);
            }

            //var Ncardinal = {"name": "North", "lat":0, "lon": 10};
            //sprite =  new labelBox(Ncardinal, radius, document.body);


        }
    function animate() {

    spriteboxes.forEach(function(e) { e.update()} );
    sprite.update();
    requestAnimationFrame(animate); 
    controls.update();
    renderer.render(scene, camera);
            }
init();
animate();
}

【问题讨论】:

标签: javascript css math three.js


【解决方案1】:

由于您的标签实际上不是 3d 对象,因此这个问题实际上与 3d 无关。您需要做的是(这是一种可行的简单算法。当然可以针对大量标签等进行优化):

  • 1.) 找出每个标签的确切标签尺寸,将它们存储在某个地方(使用 element.offsetWidth/Height
  • 2.) 计算每个标签的“锚位置”,即屏幕位置
  • 3.) 使用以下算法放置所有标签:
    • a) 计算该标签所占据的区域,如果放置在它的锚点位置(就 Box 而言,即顶部/左侧、底部/右侧 - 您可以使用 THREE.Box2-class 来存储该信息)
    • b) 测试与屏幕上已放置的所有框的交叉点(即box.intersectsBox(otherBox))。
    • c) 如果没有交叉点,我们有一个放置这个框的位置,可以继续下一个框
    • d) 如果存在交叉点,请找到可以放置标签的位置,我会根据标签的相对位置再次尝试上/下/左/右一些像素并再次测试,使如果您在多次尝试后仍找不到有效的展示位置,请务必中止(并简单地跳过标签)。

并非总是可以为每个标签找到一个位置,因此在开始插入它们之前按优先级排序是有意义的。

【讨论】:

    猜你喜欢
    • 2017-02-01
    • 2013-01-15
    • 2017-06-03
    • 2015-09-13
    • 1970-01-01
    • 2012-11-11
    • 1970-01-01
    • 2022-01-09
    • 2015-09-21
    相关资源
    最近更新 更多