考えてグーグルで調べた後、少なくとも次のようにD&Dを次のように実装することにしました。
ユーザーがアプリケーションでタブから切り替えると、つまり フォーカスを失い、ドロップされたファイルをキャッチするイベントがハングするフラッシュドライブの上にdivが重ねられます。
次に、ExternalInterfaceを介して、ByteArray形式のイメージがフラッシュに転送され、そこでデコードおよび表示されます。
フラッシュにdivを表示
#over_holder_full { background-color: #eee; opacity: 0.6; position: absolute; width: 100%; height: 100%; z-index: 7; display: none; } #flash_conainer { width: 100%; height: 100%; position: absolute; z-index: 0; } <div id="over_holder_full"></div> <div id="flash_conainer"> <div id="myContent"> <h1>Alternative content</h1> </div> </div>
ドラッグアンドドロップがマウントされているフォーカスが失われたときに#over_holder_fullを表示します
window.addEventListener('blur', function() { fullDragArea.style.display = "block"; console.log("not focused"); }); window.addEventListener('focus', function() { fullDragArea.style.display = "none"; console.log("focus"); });
#over_holder_fullによってドロップされたファイルをキャッチ
fullDragArea = $id("over_holder_full"); // is XHR2 available? var xhr = new XMLHttpRequest(); if (xhr.upload) { fullDragArea.addEventListener("dragover", FileDragHover, false); fullDragArea.addEventListener("drop", FileSelectHandler, false); // <-- //.... }
フラッシュ画像転送
// file selection function FileSelectHandler(e) { fullDragArea.style.display = "none"; // fetch FileList object var files = e.target.files || e.dataTransfer.files; //set grey preview in flash setPreview(pageX, pageY); // process all File objects setTimeout(function(){//<-- setPreview for (var i = 0, f; f = files[i]; i++) { ParseFile(f); }}, 100); } // output file information function ParseFile(file) { var arrBuffer; if (file.type.indexOf("image") == 0) { var reader = new FileReader(); reader.onload = function(e) { //console.log("arrBuffer + " + e.target.result.byteLength); var dataview = new DataView(e.target.result); var ints = new Int32Array(e.target.result.byteLength / 4); //<-- for (var i = 0; i < ints.length; i++) { ints[i] = dataview.getInt32(i * 4);//<-- 4 ( ByteArray) } console.log("ints" + ints.length); // display an image setImage(pageX, pageY, ints); } reader.readAsArrayBuffer(file); } }
JavaScriptとFlashをバインドする関数
function setImage(pageX, pageY, int32Arr) { if (swfReady){ var res = []; for (var i = 0; i < int32Arr.length; i++) { res[i] = int32Arr[i]; //<-- .. externalinterface , Int32Array } getSWF("DefaultLauncher").setImage(pageX, pageY, res);// - } } function setPreview(pageX, pageY) { if (swfReady) { console.log("setPreview"); getSWF("DefaultLauncher").setPreview(pageX, pageY); } }
フラッシュ側で画像を受け入れます
var exManager:EXManager = new EXManager(); exManager.setImageCallback = function(pageX:Number, pageY:Number, listBytes:Array):void{ var ba:ByteArray = new ByteArray(); for(var i:int = 0; i<listBytes.length; i++){ ba.writeInt(listBytes[i]); // ByteArray } var myDecoder:JPEGDecoder = new JPEGDecoder(); // ByteArray myDecoder.parse(ba); var colorComponents:uint = myDecoder.colorComponents; var numComponents:uint = myDecoder.numComponents; var pixels:Vector.<uint> = myDecoder.pixels; var width:uint = myDecoder.width; var height:uint = myDecoder.height; var bitmap:BitmapData = new BitmapData ( width, height, false ); bitmap.setVector ( bitmap.rect, pixels ); var bmp:Bitmap = new Bitmap(bitmap); var oldW:Number = bmp.width; bmp.width = bmp.width > 500 ? 500 : bmp.width; bmp.height = bmp.height*(bmp.width / oldW); bmp.x = pageX; bmp.y = pageY; stage.addChild(bmp); } exManager.setPreviewCallback = function(pageX:Number, pageY:Number):void{ var sp:Sprite = new Sprite(); sp.graphics.beginFill(0x666666, 0.8); sp.graphics.drawRect(0,0,100,80); sp.x = pageX; sp.y = pageY; stage.addChild(sp); }
ソースはここからダウンロードできます
注:
この例は、JPG拡張子の画像でのみ機能しますが、他の形式に簡単に拡張できます。
wmode:opaqueプロパティは、その上にdivを表示するために必要であるため、フラッシュドライブのスクロールは機能しません。 解決策があれば、私はそれらを聞いてうれしいです。
この例を実行するには、少なくともローカルサーバーに配置する必要があります。
更新:
提案されているように、mouseWheelイベントでグリッチを克服するには、次をjsに追加する必要があります。
function wheel(event){ var delta = 0; if (!event) event = window.event; // IE. // delta if (event.wheelDelta) { // IE, Opera, safari, chrome - 120 delta = event.wheelDelta/120; } else if (event.detail) { // Mozilla, 3 delta = -event.detail/3; } // mousewheel if (delta && typeof wheelHandle == 'function') { wheelHandle(delta); // - ( ). if (event.preventDefault) event.preventDefault(); event.returnValue = false; // IE } } function wheelHandle(delta){ if (swfReady){ getSWF("DefaultLauncher").externalMouseWheelHandler(delta); } } function pageInit() { jsReady = true; // mousewheel if (window.addEventListener) // mozilla, safari, chrome window.addEventListener('DOMMouseScroll', wheel, false); // IE, Opera. window.onmousewheel = document.onmousewheel = wheel; }
また、フラッシュに追加します。
private function externalMouseWheelHandler(delta:int):void { var globalPoint:Point = new Point(stage.mouseX, stage.mouseY); var objects:Array = stage.getObjectsUnderPoint(globalPoint); if (!objects || !objects.length) { return; } var target:DisplayObject = objects[objects.length - 1] as DisplayObject; if (!target) { return; } target = (target is InteractiveObject) ? target : target.parent; if (!target) { return; } var localPoint:Point = target.globalToLocal(globalPoint); var mouseEvent:MouseEvent = new MouseEvent(MouseEvent.MOUSE_WHEEL); mouseEvent.localX = localPoint.x; mouseEvent.localY = localPoint.y; mouseEvent.delta = delta; target.dispatchEvent(mouseEvent); }
アップデート2:
いくつかの実験の後、データを分割して転送すること、および
getInt8
ではなく
getInt8
介してバッファーから読み取る方が良いことが明らかになりました。 最初のケースで想定されているように、ファイル長は必ずしも4の倍数ではありません。
Javascript
function setImage(bufer) { if (swfReady){ var dataview = new DataView(bufer); var byteLength = bufer.byteLength; // 4 var numBytes = 10000; var startPos = 0; var finishPos; var i = 0; while(i < byteLength){ finishPos = ((startPos + numBytes) > byteLength) ? byteLength : startPos + numBytes; var res = []; for (i = startPos; i < finishPos; i++) { res[i - startPos] = dataview.getInt8(i); // getInt32 getInt8 } startPos = finishPos; getSWF().sendData(res); } getSWF().sendDataFinish(); } } function setPreview(pageX, pageY, fileName) { if (swfReady){ getSWF().sendDataStart(pageX, pageY, fileName); } }
ActionScript
_exManager.sendDataStartCb = function(pageX:Number, pageY:Number, fileName:String):void { prevtime = getTimer(); }; _exManager.sendDataCb = function(listBytes:Array):void { for (var i:int = 0; i < listBytes.length; i++) { ba.writeByte(listBytes[i]);// } }; _exManager.sendDataFinishCb = function():void { loadFromByteArray(ba); ba.clear(); };