Drag and Drop APIはHTML5から実装されたAPIです。 clickイベントなどを細かく書かずとも、ドラッグアンドドロップを簡単に実装できます。 今回はアイコンをレイアウトするアプリを作りました。
サンプル
1)アイコンアプリにアイコン画像ファイルを登録しておく。
2)レイアウトアプリのレコード追加画面で、背景画像を登録する。
3)レイアウトアプリのレコード詳細画面で、背景画像上にアイコンを配置する。
※配置したアイコンを削除する場合は、背景画像の範囲外にドロップします。
※レイアウトアプリ内でアイコンの色やサイズを変更する機能は実装していません。
フォーム設定
アイコンアプリ
レイアウトアプリ
コード
レイアウトアプリに下記sample.jsとsample.cssを読み込ませます。
JavaScript
sample.js
(function(){"use strict";kintone.events.on(['app.record.create.show','app.record.edit.show'],function(event){kintone.app.record.setFieldShown('Table',false);});kintone.events.on('app.record.detail.show',function(event){varicons,listBox=document.createElement('div'),layoutBox=document.createElement('div'),saveButton=document.createElement('a'),createImageUrl=function(fileKey){returnnewkintone.Promise(function(resolve){varxhr=newXMLHttpRequest();xhr.open('GET','/k/v1/file.json?fileKey='+fileKey);xhr.setRequestHeader('X-Requested-With','XMLHttpRequest');xhr.responseType='blob';xhr.addEventListener('load',function(){resolve((window.URL||window.webkitURL).createObjectURL(xhr.response));});xhr.send();});},placeIcon=function(fileKey,x,y){varimg=document.createElement('img');img.setAttribute('src',icons.find(function(icon){returnicon.fileKey===fileKey}).url);img.dataset.fileKey=fileKey;img.dataset.x=x;img.dataset.y=y;img.style.left=x+'px';img.style.top=y+'px';img.classList.add('icon');layoutBox.appendChild(img);img.addEventListener('dragstart',function(e){img.classList.add('dragging');e.dataTransfer.setData('dragFile',fileKey);e.dataTransfer.setData('dragX',e.offsetX);e.dataTransfer.setData('dragY',e.offsetY);});},removeIcon=function(){if(document.getElementsByClassName('dragging').length)layoutBox.removeChild(document.getElementsByClassName('dragging')[0]);};kintone.app.record.setFieldShown('Table',false);kintone.app.record.setFieldShown('背景',false);layoutBox.id='layoutBox';saveButton.innerHTML='保存';kintone.app.record.getSpaceElement('space').appendChild(listBox);kintone.app.record.getSpaceElement('space').appendChild(layoutBox);kintone.app.record.getSpaceElement('space').appendChild(saveButton);createImageUrl(event.record.背景.value[0].fileKey).then(function(url){varimg=document.createElement('img');img.addEventListener('load',function(){layoutBox.style.width=img.naturalWidth+'px';layoutBox.style.height=img.naturalHeight+'px';});img.setAttribute('src',url);img.setAttribute('draggable','false');layoutBox.appendChild(img);});kintone.api(kintone.api.url('/k/v1/records',true),'GET',{app:10914//アイコンアプリのID}).then(function(response){Promise.all(response.records.map(function(record){returncreateImageUrl(record.icon.value[0].fileKey).then(function(url){return{url:url,fileKey:record.icon.value[0].fileKey};});})).then(function(results){icons=results;icons.forEach(function(icon){varimg=document.createElement('img');img.setAttribute('src',icon.url);img.addEventListener('dragstart',function(e){e.dataTransfer.setData('dragFile',icon.fileKey);e.dataTransfer.setData('dragX',e.offsetX);e.dataTransfer.setData('dragY',e.offsetY);});listBox.appendChild(img);});event.record.Table.value.forEach(function(row){if(!row.value.icon.value)return;placeIcon(row.value.icon.value,row.value.x.value,row.value.y.value);});});});layoutBox.addEventListener('dragover',function(e){e.preventDefault();});layoutBox.addEventListener('dragleave',function(e){removeIcon();});layoutBox.addEventListener('drop',function(e){e.preventDefault();removeIcon();placeIcon(e.dataTransfer.getData('dragFile'),e.offsetX-e.dataTransfer.getData('dragX'),e.offsetY-e.dataTransfer.getData('dragY'));});saveButton.addEventListener('click',function(){kintone.api(kintone.api.url('/k/v1/record',true),'PUT',{app:kintone.app.getId(),id:kintone.app.record.getId(),record:{Table:{value:[].map.call(document.getElementsByClassName('icon'),function(icon){return{value:{icon:{type:'SINGLE\_LINE\_TEXT',value:icon.dataset.fileKey},x:{type:'NUMBER',value:icon.dataset.x},y:{type:'NUMBER',value:icon.dataset.y},}};})}}}).then(function(response){alert('保存しました。');location.reload();});});});})();
CSS
sample.css
#layoutBox{position:relative;}#layoutBox\*{position:absolute;}