• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:absoluteで重なるとき右に避けて表示したい)

absoluteで重なるとき右に避けて表示したい

このQ&Aのポイント
  • float: leftなどでは横に並ぶ要素のwidthが親を超えると下段にずれる問題があります。
  • position: absoluteを使って要素を重ならせる場合に、要素が重なった際に右にずれて表示したい課題があります。
  • 配列を用いた方法では最大で要素のサイズ分だけ検索する必要があり、効率的ではありません。より賢い解決策を模索しています。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.2

<!DOCTYPE html> <meta charset="UTF-8"> <title></title> <style> ul {  list-style: none;  position:relative; } li {  position: absolute;  margin : 0;  padding: 0;  border: 1px red solid;  text-align :center;  font-size: 10px;  color: red;  width : 60px;  height: 80px; } </style> <body> <h1>Position Test</h1> <ul>  <li style="width: 50px; height:130px;">ABC  <li style="width: 40px; height:80px;">DEF  <li style="width: 100px; height:140px;">GHI  <li style="width: 60px; height:70px;">JKL  <li style="width: 150px; height:50px;">MNO  <li style="width: 70px; height:30px;">PQR </ul> <script> (function () {  // 四角形のオブジェクト  function Square (element, top, left, right, bottom) {   this.type  = 'square';   this.element = element.tagName ? element: null;   this.top   = top;   this.left  = left;   this.right  = right;   this.bottom = bottom; }    // 引数(point) が四角形の内側にあるか?  function isOverlap (point) {   var x = point.x;   var y = point.y;   if (this.top <= y)    if (y <= this.bottom)     if (this.left <= x)      if (x <= this.right)       return true;   return false;  }    // 位置を指定する  function setPosition (position) {   var d;   if ((d = position.x)) {    this.right = d + (this.right - this.left);    this.left = d;   }   if ((d = position.y)) {    this.bottom = d + (this.bottom - this.top);    this.top = d;   }  }  // 四角形のオブジェクトの生成  Square_create = function (e, x, y) {   if (1 > arguments.length)    throw new Error;   x = x || 0, y = y || 0;   return new Square (e, y, x, x + e.offsetWidth, y + e.offsetHeight);  };  //______  Square.prototype.isOverlap = isOverlap;  Square.prototype.setPosition = setPosition;  Square.create = Square_create;  this.Square = Square;   //______   // エリアにすでに領域があるかを調べるモノ。  function AreaChecker () {   this.stock = [];  }  // エリアに領域を加える  function AreaChecker_add (area) {   var e, s;   if (! area)    throw new Error ();   if ((e = area.element)) {    s = e.style;    s.top = area.top + 'px';    s.left = area.left + 'px';   }   this.stock.push (area); //配列に足すだけ  };    // 点(this)が、与えられたエリアに含まれているのか?  function overlap (area) {   return this.some (area.isOverlap, area)  }  // 引数の領域が、エリアの領域とカブっているか?  function getOverlap (area) {   var points = [ ]; //検査する点   var result;   if (! area)    throw new Error ();      switch (area.type) {      case 'square' :   default :    var st = 6;    var sx = (area.right - area.left) / st;    var sy = (area.bottom - area.top) / st;    var x, y;    var i, j;           points = [     {x: area.left, y: area.top},     {x: area.right, y: area.top},     {x: area.right, y: area.bottom},     {x: area.left, y: area.bottom},     {x: (area.left + area.right)/ 2, y:(area.top + area.bottom)/ 2} //重心もチェックでごまかす     ];    for (i = 1; i < st; i++)     for (j = 1; j < st; j++)      points.push ({x: area.left + sx * i, y: area.top + sy * j});    break;   }   result = (this.stock.length)   ? this.stock.filter (overlap, points) // 重なっているものを配列で返す   : [];   return result.length ? result: null;  }     //__________________    function AreaChecker_create () {   return new AreaChecker;  }    AreaChecker.prototype.add = AreaChecker_add;  AreaChecker.prototype.getOverlap = getOverlap;    AreaChecker.create = AreaChecker_create;    this.AreaChecker = AreaChecker; }) (); // つづく

masatook
質問者

お礼

興味深い解決方法でした。ありがとうございます! つまり、既存の要素にサンプルをぶちまけて引っ掛かる場合は移動する、という手段でチェック回数を間引きした訳ですね。 納得しました。ここから考えを自分のものにしてみたいと思います。

その他の回答 (4)

回答No.5

またも、 y: top + round (sy * j); を y: top + round (sy * j) に。

回答No.4

#1~3です。ちょっとていせい。 わかっているとおもいますが、st のあたいをふやすと、けっきょくちからわざ。 四角形だけでなく丸もできそうですが、する~。  function getOverlap (area) {   var points = [ ]; //検査する点   var result;   var round = Math.round;   if (! area)    throw new Error ();      if (! this.stock.length)    return null;      switch (area.type) {      case 'square' :   default :    var st = 6;    var sx = (area.right - area.left) / st;    var sy = (area.bottom - area.top) / st;    var left = area.left;    var top = area.top;    var i, j, t;           for (i = 0; i <= st; i++) {     t = round (sx * i);     for (j = 0; j <= st; j++) {      points.push ({       x: left + t,       y: top + round (sy * j);      });     }    }    break;   }   result = this.stock.filter (overlap, points); // 重なっているものを配列で返す   return result.length ? result: null;  }

回答No.3

//------------ var randomInt = function (n) { return Math.random () * n |0; }; var A = AreaChecker.create (); var li = document.querySelectorAll ('li'); // 面積順にする li = Array.prototype.slice.call (li, 0); function area (x, y) { return x * y }; // 面積をもとめる function comp (a, b) {  var areaA = area(a.offsetWidth, a.offsetHeight);  var areaB = area(b.offsetWidth, b.offsetHeight);  return areaA == areaB ? 0: areaB - areaA; } li.sort (comp); (function () {  var maxX = 240;  var maxY = 120;  var i = 0, j = 0;  var e;  var sq;  var db;  while (e = li[i++]) {   sq = Square.create (e);   do {    sq.setPosition ({x:randomInt (maxX), y:randomInt (maxY)});    db = A.getOverlap (sq);    if (db) {     sq.setPosition ({x: db[0].right + 1});     db = A.getOverlap (sq);    }   } while (db);   A.add (sq);  } }) (); </script> ーー びみょうにかさなる! だめだこりゃ~! べつものを、しあんちゅう。

回答No.1

おはようございます。 その位置に要素があるのか?を知るすべは var element = document.elementFromPoint (x, y); element があれば、この要素の座標を調べます。 親をたどりながら、親要素の offsetTop or offsetLeft の値を加算していくか、 var point = element.getBoundingClientRect (); var x = point.left; var y = point.top; で、座標を得る(?)。 element の座標に、その element.offsetWidth と1を足すと、右隣の座標を得られる、と思う。 しかし、その座標に要素を配置しようとしたときに、その要素の幅以内に、すでに他の要素があった場合どうする?

masatook
質問者

補足

ご回答ありがとうございます。 >[...]この要素の座標を調べます。 今回は要素の配置に"position:absolute"を使う訳ですが、 そのときのtopとleftの指定はすでに別の処理で得られた 定数を使います。(JSONを取ってきて行うので) 要素幅も処理側で指定するので、基本的には情報は 揃っている状態です。(width, height, top, left) >[...]すでに他の要素があった場合どうする? そう、そこです。 例えば上記0-1テーブルの各行と列番号の積集合で 0がwidth-height以上に残っている領域を見つけ出す― とかそういうトリックが思いつかなくて 今回の質問にいたりました。