- ベストアンサー
absoluteで重なるとき右に避けて表示したい
- float: leftなどでは横に並ぶ要素のwidthが親を超えると下段にずれる問題があります。
- position: absoluteを使って要素を重ならせる場合に、要素が重なった際に右にずれて表示したい課題があります。
- 配列を用いた方法では最大で要素のサイズ分だけ検索する必要があり、効率的ではありません。より賢い解決策を模索しています。
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
<!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; }) (); // つづく
その他の回答 (4)
- babu_baboo
- ベストアンサー率51% (268/525)
またも、 y: top + round (sy * j); を y: top + round (sy * j) に。
- babu_baboo
- ベストアンサー率51% (268/525)
#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; }
- babu_baboo
- ベストアンサー率51% (268/525)
//------------ 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> ーー びみょうにかさなる! だめだこりゃ~! べつものを、しあんちゅう。
- babu_baboo
- ベストアンサー率51% (268/525)
おはようございます。 その位置に要素があるのか?を知るすべは 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を足すと、右隣の座標を得られる、と思う。 しかし、その座標に要素を配置しようとしたときに、その要素の幅以内に、すでに他の要素があった場合どうする?
補足
ご回答ありがとうございます。 >[...]この要素の座標を調べます。 今回は要素の配置に"position:absolute"を使う訳ですが、 そのときのtopとleftの指定はすでに別の処理で得られた 定数を使います。(JSONを取ってきて行うので) 要素幅も処理側で指定するので、基本的には情報は 揃っている状態です。(width, height, top, left) >[...]すでに他の要素があった場合どうする? そう、そこです。 例えば上記0-1テーブルの各行と列番号の積集合で 0がwidth-height以上に残っている領域を見つけ出す― とかそういうトリックが思いつかなくて 今回の質問にいたりました。
お礼
興味深い解決方法でした。ありがとうございます! つまり、既存の要素にサンプルをぶちまけて引っ掛かる場合は移動する、という手段でチェック回数を間引きした訳ですね。 納得しました。ここから考えを自分のものにしてみたいと思います。