如何使用先前的跨度顶部和左侧位置放置其他跨度,以便它们不会相互重叠?

时间:2016-03-07 21:58:33

标签: javascript jquery html css

我需要使用Javascript从特定的硬编码单词制作标签云。

所以对于这个非常轻量级的简单HTML代码:

<body>
    <article></article>
</body>

这个CSS很少:

article {
    width: 750px;
    height: 750px;
    border: 1px solid red;

}
article span {
    position: absolute;
}

这些硬编码数据:

var motsHorizontaux = [
    'prix',
    'transmission',
    // ...
    'valeur',
    'fiscal'
];

var colors = [
    'MediumPurple',
    'MediumSeaGreen',
    // ...
    'PaleGreen',
    'PaleTurquoise',
];

var fonts = [
    'Arial',
    'Helvetica',
    // ...
    'Courrier New',
    'Lucida Console'
];

这些Javascript声明:

var random = function(min, max) {
    return Math.round(Math.random() * (max - min) + min, 0);
}
Number.prototype.between = function(a, b) {
    var min = Math.min.apply(Math, [a, b]),
        max = Math.max.apply(Math, [a, b])
    ;
    return this > min && this < max;
};

我想出了这个jQuery代码:

jQuery(function($) {

    var $area = $('article')
        , minSize = 21
        , maxSize = 48
    ; 
    for(var i = 0; i < colors.length; i++) {

        var $mot = $('<span/>').text(motsHorizontaux[i]).css({
            'color': colors[i],
            'font-family': fonts[i],
            'font-size': random(minSize, maxSize)
        });
        $mot.appendTo('article');

        var topMaxPosition = $area.height() - $mot.height();
        var leftMaxPosition = $area.width() - $mot.width();

        $mot.css({
            'top': random($area.position().top, topMaxPosition),
            'left': random($area.position().left, leftMaxPosition)
        }); 

        // ...
    }    

});

所有这些代码输出:

enter image description here

正如你所看到的,话语很好。只有一个缺点,其中一些是相互重叠的。所以为了纠正这个问题,我做了一个尝试,并设法用以下代码将所有单词坐标存储在两个数组中:

$mots = $area.find('> span');
$mots.each(function(j, el) {
    var $el = $(el);
    var previousTop = $el.position().top;
    var previousLeft = $el.position().left;
    var previousBottom = previousTop + $el.height();
    var previousRight = previousLeft + $el.width();

    while(true) {
        var newPositionTop = random($area.position().top, topMaxPosition);
        var newPositionLeft = random($area.position().left, leftMaxPosition);
        var newPositionBottom = newPositionTop + $mot.height();
        var newPositionRight = newPositionLeft + $mot.width();
        if(
            !newPositionTop.between(previousTop, previousBottom) &&
            !newPositionBottom.between(previousTop, previousBottom) &&
            !newPositionLeft.between(previousLeft, previousRight) &&
            !newPositionRight.between(previousLeft, previousRight)
        ) {
            $mot.css({
                'top': newPositionTop,
                'left': newPositionLeft
            });
            break;

        }
    }
});

(此代码段嵌套在外部for() {}循环中)

但是这仍然使得这些词语相互重叠(即使我不得不承认,也比以前少了)。我认为我有一个误解,因为while(true) {}循环仅适用于前一个单词($el),因此删除了之前所有单词的检查(循环中的if( && && && ) {})。有人可以帮我修改我的代码吗?

我也为此做了JSFiddle(随意反复运行)。

感谢你们给我的问题带来的关注。

2 个答案:

答案 0 :(得分:1)

如果您对云标记使用position:relative,则可能更容易在流程中和流体框内进行管理。

更像是个人意见,而不是建议,以及对js的可怕和快速解决方法。

&#13;
&#13;
jQuery(function($) {
  var random = function(min, max) {
    return Math.round(Math.random() * (max - min) + min, 0);
  }
  Number.prototype.between = function(a, b) {
    var min = Math.min.apply(Math, [a, b]),
      max = Math.max.apply(Math, [a, b]);
    return this > min && this < max;
  };

  var motsHorizontaux = [
    'prix',
    'transmission',
    'finances',
    'administratif',
    'process',
    'évaluation',
    'performance',
    'dirigeant',
    'prévisionnel',
    'anticipation',
    'adaptation',
    'suivi',
    'contrôle',
    'écarts',
    'clignotant',
    'budget',
    'assistance',
    'statut',
    'social',
    'optimisation',
    'projet',
    'valeur',
    'fiscal'
  ];

  var colors = [
    'MediumPurple',
    'MediumSeaGreen',
    'MediumSlateBlue',
    'MediumSpringGreen',
    'MediumTurquoise',
    'SpringGreen',
    'SteelBlue',
    'Tan',
    'Teal',
    'Thistle',
    'Tomato',
    'Turquoise',
    'Violet',
    'Navy',
    'OldLace',
    'Olive',
    'OliveDrab',
    'Orange',
    'OrangeRed',
    'Orchid',
    'PaleGoldenRod',
    'PaleGreen',
    'PaleTurquoise',
  ];

  var fonts = [
    'Arial',
    'Helvetica',
    'Arial Black',
    'Comic Sans MS',
    'Impact',
    'Charcoal',
    'Lucida Sans Unicode',
    'Lucida Grande',
    'Tahoma',
    'Geneva',
    'Trebuchet MS',
    'Verdana',
    'Courrier New',
    'Lucida Console'
  ];

  var $area = $('article'),
    minSize = 21,
    maxSize = 36;
  for (var i = 0; i < colors.length; i++) {

    var $mot = $('<span/>').text(motsHorizontaux[i]).css({
      'color': colors[i],
      'font-family': fonts[i],
      'font-size': random(minSize, maxSize)
    });
    $mot.appendTo('article');

    var topPosition = $area.height() / 4 - $mot.height();
    var leftPosition = $mot.width() /3;

    $mot.css({
      'top': random(0, topPosition),
      'left': random('0', leftPosition)
    });

  }

  var $mots = $area.find('span');
  var leftPositions = [];
  var topPositions = [];
  $mots.each(function(i, el) {

    var $el = $(el);
    var previousTop = 0;
    var previousLeft = 0;
    var previousBottom = 0;
    var previousRight = 0;

    leftPositions[i] = [previousLeft, previousRight];
    topPositions[i] = [previousTop, previousBottom];

  });

});
&#13;
article {
  padding: 2em;
  border: 1px solid red;
}
article span {
  position: relative;
  display: inline-block;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<article></article>
&#13;
&#13;
&#13;

或循环理念:https://jsfiddle.net/n0jrd9sy/4/

答案 1 :(得分:1)

碰撞检测:

function intersectRect(rect1, rect2) { 
    return !(rect2.left > rect1.right || 
        rect2.right < rect1.left || 
        rect2.top > rect1.bottom || 
        rect2.bottom < rect1.top); 
}

您可能需要考虑此插件中的一些有趣代码。 https://github.com/mistic100/jQCloud/blob/master/src/jqcloud.js#L184