Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 01.09.2008, 17:08
Интересующийся
Отправить личное сообщение для gagagogo Посмотреть профиль Найти все сообщения от gagagogo
 
Регистрация: 01.09.2008
Сообщений: 18

Электронные таблицы на JS
Здравствуйте!
Хочу сделать нечто вроде экселевской таблицы на JavaScript. Я сделал её, но работает медленно. Если взять таблицу размером (800х14) то её загрузка в IE требует 29 секунд. Я недоволен. Не хочется изобретать велосипед, может ктото делал такую вещь? Посоветуйте что нибудь. Могу скинуть свой код, там 205 строк.
Ответить с цитированием
  #2 (permalink)  
Старый 01.09.2008, 17:57
Флудер
Отправить личное сообщение для ZoNT Посмотреть профиль Найти все сообщения от ZoNT
 
Регистрация: 24.07.2008
Сообщений: 1,271

скинь, мне интересно.

У меня генерация таблицы 800*14 в ФФ2 занимает 2100миллисекунды (визуально 3).
Ответить с цитированием
  #3 (permalink)  
Старый 01.09.2008, 18:24
Новичок на форуме
Отправить личное сообщение для Kolyaj Посмотреть профиль Найти все сообщения от Kolyaj
 
Регистрация: 19.02.2008
Сообщений: 9,177

Сам не реализовывал, поэтому по слухам: большие таблицы сильно тормозят (в ИЕ?). Вариант решения: разбивать на много маленьких таблиц, следующих друг за другом.
Ответить с цитированием
  #4 (permalink)  
Старый 01.09.2008, 19:24
Флудер
Отправить личное сообщение для ZoNT Посмотреть профиль Найти все сообщения от ZoNT
 
Регистрация: 24.07.2008
Сообщений: 1,271

Большик таблицы просто жесть как тормозят в ИЕ, но также они тормозят в Сафари (но меньше), потом идёт ФФ, и почти не тормозят в Опере (но в опере вылазит куча других проблем)...
Ответить с цитированием
  #5 (permalink)  
Старый 02.09.2008, 08:33
Интересующийся
Отправить личное сообщение для gagagogo Посмотреть профиль Найти все сообщения от gagagogo
 
Регистрация: 01.09.2008
Сообщений: 18

вот мой код
/*
SpreadSheet.js
*/
Array.prototype.search = function(search){
	var i=0;while(this[i++]!=search && i<this.length);
	return this[i-1]!=search?false:i-1;
};

/*
ЯЧЕЙКА ТАБЛИЦИ
*/
function cell(){
	this.r = 0;
	this.c = 0;
	this.parent = null;
	this.value = '';
	this.borderColor = '#7F9DB9';
	this.borderWidth = '1';
	this.defaultStyle = function(){
		this.borderColor = '#7F9DB9';
		this.borderWidth = '1';
	};
	this.activeStyle = function(){
		this.borderColor = '#000000';
		this.borderWidth = '3';
	};
	this.setAutoCompleter = function(url){
		/*var td = this.findTableCell(this.r,this.c);
		var input = td.getElementsByTagName('INPUT')[0];
		var acDiv = document.createElement("DIV");
		acDiv.className = 'ac';
		td.appendChild(acDiv);
		this.AutoCompleter = new AutoCompleter(acDiv,input,url);
		_onkeydown = input.onkeydown;
		input.onkeydown = function(e){
			if('block' == acDiv.style.display){}
			else {_onkeydown();}
		};*/
	};
	this.findTableCell = function(r,c){
		var t = this.parent._obj.getElementsByTagName('TABLE');
		return t[t.length-1].getElementsByTagName('TR')[this.r-1].getElementsByTagName('TD')[this.c-1];
	};
}
/*
ТАБЛИЦА
*/
function sheet(obj){
	return {
		row:1,
		col:1,
		cells:[], // хеш массив ячеек
		_obj:obj,
		cell:function(r,c){
			var rCount=0,cCount=0;
			while(this.cells.length < r){
				this.cells.push([]);
				rCount = this.cells.length - 1;
				while(this.cells[rCount].length < c){
					this.cells[rCount].push(new cell());
					cCount = this.cells[rCount].length - 1;
					this.cells[rCount][cCount].r = rCount+1;
					this.cells[rCount][cCount].c = cCount+1;
					this.cells[rCount][cCount].parent = this;
				}
			}
			return this.cells[r-1][c-1];
		},
		moveTo:function(r,c){
			if(r<1 || c<1 || r>this.cells.length || c>this.cells[0].length)
			return;
			with(this){
				cell(this.row,this.col).defaultStyle();
				cell(r,c).activeStyle();
				updateCell(this.row,this.col);
				updateCell(r,c);
				row=r;
				col=c;
			}
		},
		updateCell:function(r,c){
			var t = obj.getElementsByTagName('TABLE');
			row   = t[t.length-1].getElementsByTagName('TR')[r-1];
			cell  = row.cells[c-1];
			input = cell.getElementsByTagName('INPUT')[0];
			input.style.borderWidth = this.cell(r,c).borderWidth;
			input.style.borderColor = this.cell(r,c).borderColor;
			if(''!=input.value && input.value!=this.cell(r,c).value)
			this.cell(r,c).value = input.value;
			input.value = this.cell(r,c).value;
			input.focus();
		},
		show:function(){
			t = [];
			currenCell = {};
			t.push('<div></div><br><div><table border="0">');
			rCount = this.cells.length;
			cCount = this.cells[0].length;
			var tt= this
			var OnKeyDown = function(e){
				switch( keyCode(e) ){
					case 37: tt.moveTo(tt.row,tt.col-1); break;  // move left
					case 38: tt.moveTo(tt.row-1,tt.col); break;  // move up
					case 39: tt.moveTo(tt.row,tt.col+1); break;  // move right
					case 40: tt.moveTo(tt.row+1,tt.col); break;  // move down
				}
			};

			for(r=0; r<rCount; r++){
				t.push('<tr>');
				for(c=0; c<cCount; c++){
					currenCell = this.cells[r][c];
					t.push('<td><input autocomplete="off" style="width:100%;border:'+ currenCell.borderWidth +'px '+currenCell.borderColor+' solid" value="'  + currenCell.value +  '"></td>');
				}
				t.push('</tr>');
			}
			t.push('</table></div>');
			obj.innerHTML = t.join("\n");
			var inputs = obj.getElementsByTagName('INPUT');
			var inpCount = inputs.length;
			for(i=0;i<inpCount;i++){
				inputs[i].onclick= function(){
					c = this.parentNode.cellIndex +1;
					r = this.parentNode.parentNode.rowIndex +1;
					tt.moveTo(r,c);
				};
				inputs[i].onkeydown = OnKeyDown;
			}/**/
			window.onunload = function(){tt.cleanUp(tt)};
		},
		addHeaders:function(labelsList){ // labelList format: {name1:isSortable,name2:isSortable}
			var labels = [],h = [];
			for(key in labelsList)
			labels.push({name:key,isSortable:labelsList[key]});
			var rCount = this.cells[0].length;

			var t  = this._obj.getElementsByTagName('DIV')[0];
			var tw = this._obj.getElementsByTagName('TABLE')[0].clientWidth;

			var dt = this._obj.getElementsByTagName('TABLE')[0].getElementsByTagName('TR');

			h.push('<table cellspacing="0" cellpadding="0"><tr>');
			var v,options=[];
			for(i=0;i<rCount;i++){
				h.push('<td>');
				if(i<labels.length){
					if(labels[i].isSortable){
						h.push('<select style="background:#99CCFF;">');
						h.push('<option>'+labels[i].name+'</option>');
						for(j=0;j<this.cells.length;j++){
							if(false===options.search(this.cells[j][i].value) && ''!=this.cells[j][i].value){
								options.push(this.cells[j][i].value);
							}
						}
						for(j=0;j<options.length;j++)
						h.push('<option value="'+options[j]+'">'+options[j]+'</option>');
						options=[];
						h.push('</select>');
					}else
					h.push(labels[i].name);
				}else{h.push('&nbsp;')}
				h.push('</td>');
			}
			h.push('</tr></table>');
			t.innerHTML = h.join("\n");
			h = this._obj.getElementsByTagName('TABLE')[0].getElementsByTagName('TR')[0].getElementsByTagName('TD');
			t = this._obj.getElementsByTagName('TABLE')[1].getElementsByTagName('TR')[0].getElementsByTagName('TD');

			this._obj.getElementsByTagName('TABLE')[1].style.width = this._obj.getElementsByTagName('TABLE')[0].clientWidth;

			for(i=0;i<h.length;i++)
			t[i].style.width = h[i].clientWidth;
		},
		getValueList:function(collIndex){
			var list = [],v;
			for(i=0;i<this.cells.length;i++){
				if(!list.toString().match(this.cells[i][collIndex].value)){
					v = this.cells[i][collIndex].value;
					list.push('<option value="' + v +'">' + v + '</option>');
				}
			}
			return list.join('');
		},
		cleanUp:function(tt){
			// избегаем утечку памяти в Microsoft Internet Explorer
			for(i=0;i<tt.cells.length;i++){
				for(j=0;j<tt.cells[0].length;j++){
					tt.cells[i][j].parent=null;
					if(tt.cells[i][j].AutoCompleter){
						tt.cells[i][j].AutoCompleter = null;
					}
				}
			}
			var inp = document.getElementsByTagName('INPUT');
			for(l=0;l<inp.length;l++){
				inp[l].onclick 	 = null;
				inp[l].onkeydown = null;
			}
		}
	};
}
function keyCode(e){
	if (window.event) return window.event.keyCode;
	else if (e) return e.which;
}


так его запускать

<html>
	<head>
	<!--<link type="text/css" href="style.css" rel="stylesheet">-->
	<!--<script type="text/javascript" src="java.js"></script>-->
	</head>
	<body>
		<!-- ЭЛЕКТРОННАЯ ТАБЛИЦА-->
		<script type="text/javascript" src="SpreadSheet.js"></script>
		<div id="SpreadSheet" align="center">
			
		</div>
		<script>
			var b = new Date();
			var s = new sheet(document.getElementById('SpreadSheet'));
			s.cell(800,14);
						s.show();
//			s.cell(1,1).value = '11';
			//s.updateCell(1,1);
			//s.moveTo(1,1);
			//s.cell(305,14);
			//s.cell(1,1).setAutoCompleter('../helpdesk/trunk/ajaxDispecher.php?name=street');
			s.addHeaders({'Адрес установки':1,'Дом':1,'Под':1,'Switch':1,'IP адрес':1,'serial sw':1,'модуль':1,'1 модуль':1,'2 модуль':1,'Заказан':1,'Подготовлен':1,'Выдан':1,'Установлен':1,'Пометки':1});
			var e = new Date();
			alert((e.getTime() - b.getTime())/1000);
		</script>
		
		<!-- КОНЕЦ ЭЛЕКТРОННОЙ ТАБЛИЦИ-->
	</body>
</html>

Последний раз редактировалось gagagogo, 02.09.2008 в 08:40.
Ответить с цитированием
  #6 (permalink)  
Старый 02.09.2008, 08:55
Флудер
Отправить личное сообщение для ZoNT Посмотреть профиль Найти все сообщения от ZoNT
 
Регистрация: 24.07.2008
Сообщений: 1,271

жесть... updateCell тормозная функция 117 милисекунд выполняется... с учётом того, что на одно передвижение она вызывается 2 раза получаются визуальные тормоза...

После профилировки обнаружил, что addHeaders занимает больше времени при создании таблицы, чем show

Оптимизировать и оптимизировать...

Советы:
- избавиться от всех getElementsByTagName (снести в инициализацию, одни раз их сделать, записать в свойства объекта "Электронная Таблица")
- не использовать .push, а использовать [index] = ...
- ты при генерации таблицы делаешь t.innerHTML = h.join("\n"); Я не помещаю строки в массив, а формирую сразу строку. В итоге получается быстрее, чем у тебя (хоть тесты и говорят, что в массив быстрее)...
Ответить с цитированием
  #7 (permalink)  
Старый 02.09.2008, 11:53
Интересующийся
Отправить личное сообщение для gagagogo Посмотреть профиль Найти все сообщения от gagagogo
 
Регистрация: 01.09.2008
Сообщений: 18

ZoNT, спасибо за советы. Как думаешь если оптимизировать можно в 2 секунды уложиться ? Или может лучше сгенерировать таблицу на php, а к ней уже обработчики событий прикрутить? Или может лучше вообще отказаться от этой затеи и написать на java аплет? Если у тебя есть можеш свой вариант скинуть ?
Ответить с цитированием
  #8 (permalink)  
Старый 02.09.2008, 11:54
Флудер
Отправить личное сообщение для ZoNT Посмотреть профиль Найти все сообщения от ZoNT
 
Регистрация: 24.07.2008
Сообщений: 1,271

Немного ускорил.
Но структура бредовая...
1) Зачем в каждую ячейку пихать инпут?
2) Зачем на каждый инпут(ячейку) вешать обработчик событий?

/*
SpreadSheet.js
*/
Array.prototype.search = function(search){
	for(var i=0,l=this.length;i<l;i++)if(this[i]==search)return i;
	return false;
}
 
/*
ЯЧЕЙКА ТАБЛИЦИ
*/
function cell(){
    this.r = 0;
    this.c = 0;
    this.parent = null;
    this.value = '';
    this.borderColor = '#7F9DB9';
    this.borderWidth = '1';
    this.defaultStyle = function(){
        this.borderColor = '#7F9DB9';
        this.borderWidth = '1';
    }
    this.activeStyle = function(){
        this.borderColor = '#000000';
        this.borderWidth = '3';
    }
    this.setAutoCompleter = function(url){}
    this.findTableCell = function(r,c){
        var t = this.parent._obj.getElementsByTagName('TABLE');
        return t[t.length-1].getElementsByTagName('TR')[this.r-1].getElementsByTagName('TD')[this.c-1];
    }
}
/*
ТАБЛИЦА
*/
function sheet(obj){
    return {
        row:1,
        col:1,
        cells:[], // хеш массив ячеек
        _obj:obj,
        cell:function(r,c){
            var rCount=0,cCount=0;
            while(this.cells.length < r){
                this.cells.push([]);
                rCount = this.cells.length - 1;
                while(this.cells[rCount].length < c){
                    this.cells[rCount].push(new cell());
                    cCount = this.cells[rCount].length - 1;
                    this.cells[rCount][cCount].r = rCount+1;
                    this.cells[rCount][cCount].c = cCount+1;
                    this.cells[rCount][cCount].parent = this;
                }
            }
            return this.cells[r-1][c-1];
        },
        moveTo:function(r,c){
            if(r<1 || c<1 || r>this.cells.length || c>this.cells[0].length)
            return;
            with(this){
                cell(this.row,this.col).defaultStyle();
                cell(r,c).activeStyle();
                updateCell(this.row,this.col);
                updateCell(r,c);
                row=r;
                col=c;
            }
        },
        updateCell:function(r,c){
            var input = this.Table.rows[r-1].cells[c-1].firstChild;
			var C = this.cell(r,c);
            input.style.borderWidth = C.borderWidth;
            input.style.borderColor = C.borderColor;
            if(''!=input.value && input.value!=C.value)
				C.value = input.value;
            input.value = C.value;
            input.focus();
        },
        show:function(){
            var t=[],i=0,currenCell;
            t[i++] = '<table border="0">';
            var rCount = this.cells.length;
            var cCount = this.cells[0].length;
            var tt = this;
            var OnKeyDown = function(e){
				e=e||event;
                switch(e.keyCode||e.charCode){
                    case 37: tt.moveTo(tt.row,tt.col-1); break;  // move left
                    case 38: tt.moveTo(tt.row-1,tt.col); break;  // move up
                    case 39: tt.moveTo(tt.row,tt.col+1); break;  // move right
                    case 40: tt.moveTo(tt.row+1,tt.col); break;  // move down
                }
            }
 
			t[i++] = '<tr>';
			var h = this.Header.rows[0];
			for(var c=0; c<cCount; c++){
				currenCell = this.cells[0][c];
				t[i++] = '<td style="width:'+h.cells[c].offsetWidth+'px;"><input autocomplete="off" style="width:100%;border:'+ currenCell.borderWidth +'px '+currenCell.borderColor+' solid" value="'  + currenCell.value +  '"></td>';
			}
			t[i++] = '</tr>';
			
            for(var r=1; r<rCount; r++){
                t[i++] = '<tr>';
                for(var c=0; c<cCount; c++){
                    currenCell = this.cells[r][c];
                    t[i++] = '<td><input autocomplete="off" style="width:100%;border:'+ currenCell.borderWidth +'px '+currenCell.borderColor+' solid" value="'  + currenCell.value +  '"></td>';
                }
                t[i++] = '</tr>';
            }
            t[i++] = '</table>';
            this._obj.lastChild.innerHTML = t.join("");
			
			this.Table = this._obj.lastChild.firstChild;
			this.Table.style.width = this.Header.offsetWidth;
			
            var inputs = this._obj.getElementsByTagName('INPUT');
            var inpCount = inputs.length;
            for(var i=0;i<inpCount;i++){
                inputs[i].onclick= function(){
                    c = this.parentNode.cellIndex +1;
                    r = this.parentNode.parentNode.rowIndex +1;
                    tt.moveTo(r,c);
                };
                inputs[i].onkeydown = OnKeyDown;
            }
            window.onunload = function(){tt.cleanUp(tt)};
        },
        addHeaders:function(labelsList){ // labelList format: {name1:isSortable,name2:isSortable}
            var labels = [],h = [],k=0;
            for(var key in labelsList)
				labels.push({name:key,isSortable:labelsList[key]});
				
            var rCount = this.cells[0].length;
			var cCount = this.cells.length;
 
            var t = this._obj;
			
            h[k++] = '<div><table cellspacing="0" cellpadding="0"><tr>';
			
            for(var i=0;i<rCount;i++){
                h[k++] = '<td>';
                if(i<labels.length){
                    if(labels[i].isSortable){
						h[k++] = '<select style="background:#99CCFF;"><option>'+labels[i].name+'</option>';
						
						var options=[];
                        for(var j=0;j<cCount;j++){
							var v = this.cells[j][i].value;
                            if(false===options.search(v) && ''!=v){
                                options.push(v);
								h[k++] = '<option value="'+v+'">'+v+'</option>';
                            }
                        }
						
                        h[k++] = '</select>';
                    }
					else h[k++] = labels[i].name;
                }
				else h[k++] = '&nbsp;';
				
                h[k++] = '</td>';
            }
            h[k++] = '</tr></table></div><br><div></div>';
            t.innerHTML = h.join("");
			this.Header = t.firstChild.firstChild;
        },
		
        getValueList:function(collIndex){
            var list = [],v;
            for(var i=0;i<this.cells.length;i++){
                if(!list.toString().match(this.cells[i][collIndex].value)){
                    v = this.cells[i][collIndex].value;
                    list.push('<option value="' + v +'">' + v + '</option>');
                }
            }
            return list.join('');
        },
        cleanUp:function(tt){
            // избегаем утечку памяти в Microsoft Internet Explorer
            for(var i=0;i<tt.cells.length;i++){
                for(var j=0;j<tt.cells[0].length;j++){
                    tt.cells[i][j].parent=null;
                    if(tt.cells[i][j].AutoCompleter){
                        tt.cells[i][j].AutoCompleter = null;
                    }
                }
            }
            var inp = document.getElementsByTagName('INPUT');
            for(var l=0;l<inp.length;l++){
                inp[l].onclick = inp[l].onkeydown = null;
            }
        }
    };
}



Вызов addHeaders в html должен идти ПЕРЕД show()!!!

Последний раз редактировалось ZoNT, 02.09.2008 в 12:00.
Ответить с цитированием
  #9 (permalink)  
Старый 02.09.2008, 11:59
Флудер
Отправить личное сообщение для ZoNT Посмотреть профиль Найти все сообщения от ZoNT
 
Регистрация: 24.07.2008
Сообщений: 1,271

Сообщение от gagagogo Посмотреть сообщение
ZoNT, спасибо за советы. Как думаешь если оптимизировать можно в 2 секунды уложиться ? Или может лучше сгенерировать таблицу на php, а к ней уже обработчики событий прикрутить? Или может лучше вообще отказаться от этой затеи и написать на java аплет? Если у тебя есть можеш свой вариант скинуть ?
Свой вариант скинуть не могу (так как он делался для коммерческих целей), но твой мы можем доработать до этих самых двух секунд...

Если на пхп таблица сгенерится быстрее, то это конечно лучший вариант...
Ответить с цитированием
  #10 (permalink)  
Старый 02.09.2008, 12:32
Интересующийся
Отправить личное сообщение для gagagogo Посмотреть профиль Найти все сообщения от gagagogo
 
Регистрация: 01.09.2008
Сообщений: 18

Ага, учтя твои замечания думаю сделать так:
1 таблицу генерировать на пхп
2 сделать один input который будет бегать по ячейкам таблицы и менять значения в них.
3 на input повесить все события, и убрать объект cell - поидеи он тогда вообще не нужен будет
Ответить с цитированием
Ответ



Опции темы Искать в теме
Искать в теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Скрыть ссылку на js Googert Общие вопросы Javascript 10 21.02.2012 15:29
Нужно с помощью JS записывать данные в БД d!mm Общие вопросы Javascript 2 01.11.2008 17:36
вызов функции, из JS генерируемого на сервере subaru AJAX и COMET 1 12.07.2008 12:44
опубликуйте пожалуйста функционал JS scuter Сайт Javascript.ru 21 05.06.2008 16:44
подключение стороннего js скрипта friend Общие вопросы Javascript 2 24.05.2008 18:51