数字の特定の構成によって作成されたパターンと、それらの間の関係を視覚的に表示する必要があります。これを行うために、テーブルを作成し、行/列をx / y座標(IDでエンコード)として使用しました。多くのTD要素に、意味のある背景色を付け、マウスオーバー/アウトハンドラーをアタッチして、そのTDに割り当てられた番号とその情報を含むポップアップを表示します。(セルは小さすぎて実際に数字を含めることができません。セルはより視覚的なデバイスであり、パターンが見やすいように上記の背景色を使用しています。)
このテーブルをズームインおよびズームアウトしたり、他の方法で管理したりできる必要があります。ただし、大きなテーブル(1000行および列以上)を処理する場合、ブラウザーが新しいズームレベルごとにテーブルをレンダリングするのに非常に長い時間がかかります。少し調べてみると、ブラウザはセルの内容とテーブル内の利用可能な幅に基づいて再計算する必要があるため、TABLE要素にはもう少し時間がかかることがわかりました。'table-layout'を'fixed'に設定し、テーブルに幅を指定すると、それが発生しないようにする必要がありますが、それでも永遠にかかりました。
次に、代わりにDIV要素を使用してテーブルを作成すると、必要な要素の総数が少なくなり、テーブルの場合のように自動サイズ変更が行われないため、機能する可能性があると考えました。ディメンションをハードコーディングできます。「display:table」(これまで聞いたことがない)と、テーブル化されていないDIV(単語を作るのが大好き...)を使用して、Webで見つけたコードを試しました。
これが私が3つをテストしてそれらの時間を計るために作成したテストページです(ここでそれを見てください):
<!--
Only tested in Google Chrome on Windows 7!
I have not bothered testing in other browsers as this is a private project
and all members of the project use Chrome.
-->
<html>
<head>
<title>Table Test</title>
<style>
#controls td {
font-family: Courier New, monospace;
}
input[type=button] {
width: 100%;
}
input[type=text] {
width: 50px;
}
/* styles the pure table version */
table {
table-layout: fixed;
border-collapse: collapse;
}
.td {
border: 1px solid black;
width: 48px;
height: 48px;
vertical-align: top;
}
/* styles the DIV version using "display: table" */
.div-table {
display: table;
border: solid black;
border-width: 1px 0px 0px 1px;
}
.div-table-row {
display: table-row;
width: auto;
clear: both;
}
.div-table-col {
float: left;
display: table-column;
width: 48px;
height: 48px;
border: solid black;
border-width: 0px 1px 1px 0px;
}
/* styles the pure DIV version */
div#grid {
border: solid black;
border-width: 1px 0px 0px 1px;
}
.cell {
display: inline-block;
width: 49px;
height: 49px;
padding: 0px;
margin: 0px;
border: solid black;
border-width: 0px 1px 1px 0px;
}
</style>
<script type="text/javascript">
function Stopwatch() { // basic Stopwatch object to time functions
var startTime = null;
var stopTime = null;
var running = false;
function getTime() {
var day = new Date();
return day.getTime();
}
this.start = function() {
if (running == true)
return;
else if (startTime != null)
stopTime = null;
running = true;
startTime = getTime();
return startTime;
}
this.stop = function() {
if (running == false)
return;
stopTime = getTime();
running = false;
return stopTime;
}
this.duration = function() {
if (startTime == null || stopTime == null)
return 'Undefined';
else
return (stopTime - startTime) / 1000;
}
}
var stopwatch = new Stopwatch();
var x = 50; // global dimension variables
var y = 100;
function updateDims() { // updates the global dimension variables
// returns true/false to indicate success
x = parseInt(document.getElementById('x').value);
y = parseInt(document.getElementById('y').value);
if (typeof x == 'number' && x > 0 && typeof y == 'number' && y > 0) return true;
return false;
}
function makeTableTable() { // creates the pure table version
if (!updateDims()) return false; // grab desired x/y dimensions
// grab count of how many times function has been run to calculate average
var count = document.getElementById('count1');
count = count.value = parseInt(count.value) + 1;
// grab previous average time to calculate new average
var avg = parseFloat(document.getElementById('avg1').innerHTML);
// start the stopwatch, grabbing initial start time, and begin concatenating
var start = stopwatch.start();
var html = '<table id="grid" cellpadding="0" cellspacing="0">';
for (var i = 0; i < y; i++) { // for each row...
html += '<tr>';
for (var j = 0; j < x; j++) { // build desired number of cells
html += '<td class="td" id="'+j+'/'+[y-[i+1]]+'">' + [1+j+i*x] + '</td>';
}
html += '</tr>'; // close row
j = 0;
}
html += '</table>';
// stop the watch and record duration it took to concatenate
stopwatch.stop();
document.getElementById('concat1').innerHTML = stopwatch.duration();
// start the watch again and insert HTML
stopwatch.start();
document.getElementById('output').innerHTML = html;
// stop the watch, grabbing the final end time, and record duration for innerHTML
var end = stopwatch.stop();
document.getElementById('insert1').innerHTML = stopwatch.duration();
// find total time from initial start time and final end time
document.getElementById('total1').innerHTML = (end - start) / 1000;
// calculate average time
if (count > 1)
document.getElementById('avg1').innerHTML = Math.round(100000*(avg*(count-1)+(end-start)/1000)/count)/100000;
else
document.getElementById('avg1').innerHTML = (end-start) / 1000;
}
function makeDivTable() { // creates the DIV version using "display: table"
if (!updateDims()) return false;
var count = document.getElementById('count2');
count = count.value = parseInt(count.value) + 1;
var avg = parseFloat(document.getElementById('avg2').innerHTML);
var start = stopwatch.start();
var html = '<div id="grid" class="div-table">';
for (var i = 0; i < y; i++) {
html += '<div class="div-table-row">';
for (var j = 0; j < x; j++) {
html += '<div class="div-table-col" id="'+j+'/'+[y-[i+1]]+'">' + [1+j+i*x] + '</div>';
}
html += '</div>';
j = 0;
}
html += '</div>';
stopwatch.stop();
document.getElementById('concat2').innerHTML = stopwatch.duration();
stopwatch.start();
document.getElementById('output').innerHTML = html;
var end = stopwatch.stop();
document.getElementById('insert2').innerHTML = stopwatch.duration();
document.getElementById('total2').innerHTML = (end - start) / 1000;
if (count > 1)
document.getElementById('avg2').innerHTML = Math.round(100000*(avg*(count-1)+(end-start)/1000)/count)/100000;
else
document.getElementById('avg2').innerHTML = (end-start) / 1000;
// update width of outer DIV
document.getElementById('grid').style.width = 50 * x + 'px';
}
function makeDivDiv() { // creates the pure DIV version
if (!updateDims()) return false;
var cells = x*y; // will iterate through total number of cells,
// rather than by row and column
var count = document.getElementById('count3');
count = count.value = parseInt(count.value) + 1;
var avg = parseFloat(document.getElementById('avg3').innerHTML);
var start = stopwatch.start();
var html = '<div id="grid">';
for (var i = 0; i < cells; i++) {
var id = [i-x*Math.floor(i/x)+1] + '/' + [y-Math.floor(i/x)];
html += '<div class="cell" id="' + id + '">' + [i+1] + '</div>';
}
html += '</div>';
stopwatch.stop();
document.getElementById('concat3').innerHTML = stopwatch.duration();
stopwatch.start();
document.getElementById('output').innerHTML = html;
var end = stopwatch.stop();
document.getElementById('insert3').innerHTML = stopwatch.duration();
document.getElementById('total3').innerHTML = (end - start) / 1000;
if (count > 1)
document.getElementById('avg3').innerHTML = Math.round(100000*(avg*(count-1)+(end-start)/1000)/count)/100000;
else
document.getElementById('avg3').innerHTML = (end-start) / 1000;
document.getElementById('grid').style.width = 50 * x + 'px';
}
</script>
</head>
<body>
<table id="controls" border="1">
<tr>
<td>x: <input type="text" id="x" value="50" /></td>
<td>y: <input type="text" id="y" value="100" /></td>
<td colspan="7"></td>
</tr>
<tr>
<td><input type="button" onclick="makeTableTable()" value="Standard table" />
<input type="hidden" id="count1" value="0" /></td>
<td>Concatenation:</td>
<td id="concat1"> </td>
<td>Insertion:</td>
<td id="insert1"> </td>
<td>Total:</td>
<td id="total1"> </td>
<td>Average:</td>
<td id="avg1"> </td>
</tr>
<tr>
<td><input type="button" onclick="makeDivTable()" value="Div w/ 'display:table'" />
<input type="hidden" id="count2" value="0" /></td>
<td>Concatenation:</td>
<td id="concat2"> </td>
<td>Insertion:</td>
<td id="insert2"> </td>
<td>Total:</td>
<td id="total2"> </td>
<td>Average:</td>
<td id="avg2"> </td>
</tr>
<tr>
<td><input type="button" onclick="makeDivDiv()" value="Div Table" />
<input type="hidden" id="count3" value="0" /></td>
<td>Concatenation:</td>
<td id="concat3"> </td>
<td>Insertion:</td>
<td id="insert3"> </td>
<td>Total:</td>
<td id="total3"> </td>
<td>Average:</td>
<td id="avg3"> </td>
</tr>
</table><br />
<div id="output"></div>
</body>
</html>
まず、デフォルトなどの小さな値で試してください。次に、xとyを1000に変更して、デフォルトのブラウザズーム機能を試してください。テーブルの生成とズームインまたはズームアウトの両方にかなりの時間がかかるはずです。
ただし、注目すべき興味深い点は、報告されている時間は実際にかかる時間ではないことです。ボールパークの2番目のカウント(古き良き「1つのミシシッピ」)を実行するだけでわかります。400x400のグリッドは、数回の実行後に報告された平均時間が約2.3、2.7、および2.4であった場合、一貫してそれぞれ約13秒、5秒、および7秒かかりました。タイミングに関連するすべてのコードは、それほど影響しません。すべて削除するか、コメントアウトして(表示)、同じでした(私にとっては13、5、7)。
したがって、2つの質問:
まず、なぜこれらの数値の不一致があるのでしょうか。タイマーは、関数で行われているすべてのタイミングを計る必要があります。updateDimsの最初の呼び出しとは別に、発生する主な2つのことは、文字列の連結とinnerHTMLへの割り当てです。(グリッドの幅にも変更がありますが、それがどのように時間がかかるかはわかりません。)関数が完了した後に実行され、タイミングが合わないのは、単にブラウザーのレンダリング時間ですか?これを支持するいくつかの証拠は、純粋なテーブルバージョンの見かけの時間がはるかに長いことです。つまり、ブラウザはおそらくすべてのTD幅などを再計算しています。
第二に、それについて何ができるでしょうか?なんでも?連結はその短い部分なので、それは問題ではありません。(そして、私はすでに配列にプッシュして結合しようとしましたが、少なくとも私にとっては、連結は一貫して高速でした。)また、ストップウォッチを信じるなら、innerHTMLに挿入するのにそれほど時間はかかりません。それはその後何が起こっているのかです。バックグラウンダーの手法を採用することを考えていたので、更新に時間がかかっても、少なくともその間ずっとブラウザーがロックされることはなく、いくつかの顕著なアクティビティが発生します。しかし、ロックポイントが関数の「外部」で発生している場合、それがどのように機能するかわかりません。独自のズーム機能を設計することはできますが、ブラウザよりも高速になるとは確信していません。予備テストはそうではないと言います。
私がやろうとしていることに対する他の選択肢は(おそらくあなたにはかなり曖昧ですが、申し訳ありませんが)確かにありがたいです!
StackOverflowの他のいくつかのページ:
大きなhtmlテーブルは遅いですか?テーブルは通常レンダリングが速いように聞こえます。ただし、これは、私のように生成されたものではなく、HTMLファイルにすでにハードコードされているテーブルの場合のみです。
大きなテーブルを作成する場合のJavascriptのパフォーマンスは、私の場合と非常に似ていますが、ページ付けされたテーブルを持つ受け入れられたソリューションは、目的を損なうため、私にとってオプションではありません。そして、私のテーブルにはデータが含まれていません。ただし、回答者の1人は、このような大きなテーブルでは、DOMメソッドがHTML解析よりも高速である可能性があることを示唆していました(他の場所でその逆が当てはまることがわかりましたが、おそらく要素の量はかなり多いです)。機会があればそれをテストするかもしれません。どう思いますか?