HTML5的Drag and Drop是很不錯的功能,網上使用例子較多如 http://html5demos.com/drag ,但這些例子大部分沒實際用途,本文將搞個有點使用價值的例子,通過Drag and Drop生成圖片的Base64的字串資訊。
使用Base64方式的圖片有諸多好處,可將多個圖片資訊整合到單個js檔案避免多次http請求,可以避免WebGL例子跨域訪問的安全限制無法本地檔案執行等好處,當然弊端也不少例如不能有效利用瀏覽器圖片快取機制等。使用HT for Web的朋友會發現HT的例子很多註冊圖片都採用Base64的方式,這主要是為了方便使用者直接本地檔案開啟HT的手冊即可操作瀏覽,無需構建web伺服器釋出進行訪問,使用者常問然後將圖片轉出Base64資訊,我們使用的就是本文介紹的小工具。
該工具由一個列表、一個拓撲圖和一個文字框三部分組成,使用者任意拖拽本地多圖片檔案到任意頁面部分,HT自動將圖片資訊生成對應的DataModel資料模型,列表顯示圖片效果、名稱和寬高資訊,拓撲顯示圖片、修改時間和檔案大小等資訊,文字框生成對應註冊到htDefault.setImage函式的程式碼片段,使用者直接可以將文字框內的程式碼拷貝到自己的工程的js檔案進行使用。
function init(){ dataModel = new ht.DataModel(); listView = new ht.widget.ListView(dataModel); graphView = new ht.graph.GraphView(dataModel); splitView = new ht.widget.SplitView(listView, graphView); textArea = new ht.widget.TextArea(); textArea.getElement().style.wordWrap = 'normal'; textArea.getElement().style.color = '#777'; textArea.setEditable(false); new ht.widget.SplitView(splitView, textArea, 'v').addToDOM(); new ht.layout.ForceLayout(graphView).start(); listView.setRowHeight(50); listView.drawRowBackground = function(g, data, selected, x, y, width, height){ if(this.isSelected(data)){ g.fillStyle = '#87A6CB'; } else if(this.getRowIndex(data) % 2 === 0){ g.fillStyle = '#F1F4F7'; } else{ g.fillStyle = '#FAFAFA'; } g.beginPath(); g.rect(x, y, width, height); g.fill(); }; ht.Default.setImage('icon', { width: 50, height: 50, clip: function(g, width, height) { g.beginPath(); g.arc(width/2, height/2, Math.min(width, height)/2-3, 0, Math.PI * 2, true); g.clip(); }, comps: [ { type: 'image', stretch: 'uniform', rect: [0, 0, 50, 50], name: {func: 'getImage'} } ] }); listView.setIndent(60); listView.setVisibleFunc(function(data){ return data instanceof ht.Node; }); listView.getIcon = function(data){ return 'icon'; }; listView.getLabel = function(data){ var name = data.getName(name); var image = ht.Default.getImage(name); if(image){ name += ' ( ' + image.width + ' X ' + image.height + ' )'; } return name; }; window.addEventListener("dragenter", dragEnter, false); window.addEventListener("dragexit", dragExit, false); window.addEventListener("dragover", dragOver, false); window.addEventListener("drop", drop, false); } function dragEnter(evt) { evt.stopPropagation(); evt.preventDefault(); } function dragExit(evt) { evt.stopPropagation(); evt.preventDefault(); } function dragOver(evt) { evt.stopPropagation(); evt.preventDefault(); } function drop(evt) { evt.stopPropagation(); evt.preventDefault(); dataModel.clear(); textArea.setText(""); lastNode = null; var files = evt.dataTransfer.files; var count = files.length; for (var i = 0; i < count; i++) { var file = files[i]; var reader = new FileReader(); reader.onloadend = handleReaderLoadEnd; reader.file = file; reader.readAsDataURL(file); } } function handleReaderLoadEnd(evt) { var reader = evt.target; var file = reader.file; var name = file.name; name = name.substr(0, name.length - 4); var text = "ht.Default.setImage('" + name + "', '" + reader.result + "');\n"; textArea.setText(textArea.getText() + text); ht.Default.setImage(name, reader.result); var note = 'Date: ' + file.lastModifiedDate.toLocaleString() + '\n' + 'Name: ' + file.name + '\n' + 'Size: ' + file.size + '\n' + 'Type: ' + file.type; var node = new ht.Node(); node.setName(name); node.setImage(name); node.s({ 'note': note, 'note.position': 3 }); dataModel.add(node); if(lastNode){ var edge = new ht.Edge(lastNode, node); dataModel.add(edge); } lastNode = node; }
該程式碼主要對window新增了dragenter、dragexit、dragover和drop的拖拽處理,大部分都是通過e.stopPropagation();和evt.preventDefault();阻止預設行為,我們僅需在最後的drop事件中通過e.dataTransfer.files得到所有當前拖拽檔案資訊,構建FileReader進行載入,然後對載入的資訊構建對應DataModel中的ht.Node物件和屬性就完事了。
最後程式碼中還有幾處使用HT for Web的技術細節值得提到,左側list列表通過自定義向量圖示,並且在定義向量時採用了clip的功能,這樣列表的圖示就會顯示成clip裁剪後的圓形效果。過載了listView.drawRowBackground函式,實現隔行變色的列表效果。過載了listView.getLabel顯示了更多的動態文字資訊。通過listView.setVisibleFunc過濾不顯示連線資訊在列表中。
以下為該Base64轉換工具的操作效果視訊和抓圖供參考:http://v.youku.com/v_show/id_XODUxNzY3OTA4.html
<iframe src="http://player.youku.com/embed/XODUxNzY3OTA4" frameborder="0" width="510" height="498"></iframe>