Div要素の序盤の定石探す①
Drag可能なdiv要素
己自身をDragするもの
index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DOM</title>
</head>
<body>
<script type="module" src="main.js"></script>
</body>
</html>
main.js
const div = document.createElement('div');
div.style.position = 'absolute';
div.style.border = "1px solid black";
div.style.width = '300px';
div.style.height = '100px';
// Drag and Drop処理
let isDragging = false;
let offsetX, offsetY;
div.addEventListener('mousedown', (e) => {
isDragging = true;
offsetX = e.clientX - div.getBoundingClientRect().left;
offsetY = e.clientY - div.getBoundingClientRect().top;
document.addEventListener('mousemove', move);
document.addEventListener('mouseup', () => {
isDragging = false;
document.removeEventListener('mousemove', move);
document.addEventListener('mouseup', stopDragging);
});
});
function move(e) {
if (isDragging) {
div.style.left = (e.clientX - offsetX) + 'px';
div.style.top = (e.clientY - offsetY) + 'px';
}
}
const stopDragging = () => {
isDragging = false;
document.removeEventListener('mousemove', move);
document.removeEventListener('mouseup', stopDragging);
};
document.body.appendChild(div);
Google Colab用
%%html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DOM</title>
<style>
body {
position: relative;
}
.draggable-div {
position: absolute;
border: 1px solid black;
width: 300px;
height: 100px;
}
</style>
</head>
<body>
<div id="draggable" class="draggable-div"></div>
<script type="module">
const div = document.getElementById('draggable');
// Drag and Drop処理
let isDragging = false;
let offsetX, offsetY;
div.addEventListener('mousedown', (e) => {
isDragging = true;
offsetX = e.clientX - div.getBoundingClientRect().left;
offsetY = e.clientY - div.getBoundingClientRect().top;
document.addEventListener('mousemove', move);
document.addEventListener('mouseup', stopDragging);
});
function move(e) {
if (isDragging) {
div.style.left = (e.clientX - offsetX) + 'px';
div.style.top = (e.clientY - offsetY) + 'px';
}
}
function stopDragging() {
isDragging = false;
document.removeEventListener('mousemove', move);
document.removeEventListener('mouseup', stopDragging);
}
</script>
</body>
</html>
Dragするものされるもの
function createDragDivSelf(x, y, w, h, text) {
const div = document.createElement('div');
div.style.position = 'absolute';
div.style.border = "1px solid black";
div.style.left = x + 'px';
div.style.top = y + 'px';
div.style.width = w + 'px';
div.style.height = h + 'px';
div.innerHTML = text;
createDragEventListener(div)
return div;
}
function createDragDiv(target, x, y, w, h, text) {
const div = document.createElement('div');
div.style.position = 'absolute';
div.style.border = "1px solid black";
div.style.left = x + 'px';
div.style.top = y + 'px';
div.style.width = w + 'px';
div.style.height = h + 'px';
div.innerHTML = text;
createDragEventListener(div, target);
return div;
}
function createDragEventListener(div, target) {
// Drag and Drop処理
let isDragging = false;
let offsetX, offsetY;
let offsetTX, offsetTY;
div.addEventListener('mousedown', (e) => {
isDragging = true;
offsetX = e.clientX - div.getBoundingClientRect().left;
offsetY = e.clientY - div.getBoundingClientRect().top;
if (target) {
offsetTX = e.clientX - target.getBoundingClientRect().left;
offsetTY = e.clientY - target.getBoundingClientRect().top;
}
document.addEventListener('mousemove', move);
document.addEventListener('mouseup', stopDragging);
});
function move(e) {
if (isDragging) {
div.style.left = (e.clientX - offsetX) + 'px';
div.style.top = (e.clientY - offsetY) + 'px';
if (target) {
target.style.left = (e.clientX - offsetTX) + 'px';
target.style.top = (e.clientY - offsetTY) + 'px';
}
}
}
const stopDragging = () => {
isDragging = false;
document.removeEventListener('mousemove', move);
document.removeEventListener('mouseup', stopDragging);
};
}
//自分自身をdrag
const divSelf = createDragDivSelf(10,10,100,100,"hello");
//dragする側とされる側
const dragged = document.createElement('div');
dragged.innerHTML = "dragged";
dragged.style.position = 'absolute';
dragged.style.border = "1px solid black";
dragged.style.left = 300 + 'px';
dragged.style.top = 100 + 'px';
dragged.style.width = 100 + 'px';
dragged.style.height = 100 + 'px';
const dragger = createDragDiv(dragged, 300,10,20,20,"dragger")
document.body.appendChild(divSelf);
document.body.appendChild(dragger);
document.body.appendChild(dragged);
基本的な考え
ある要素を平行移動する
それに引きずられるものがあればそれも平行移動する
引きずられるものがなければある要素のみが動く(自分自身)
拡張すればtargetを複数形にできる。
Google Colab用
%%html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DOM</title>
<style>
body {
width: 500px;
height: 500px;
}
</style>
</head>
<body>
<script type="module">
function createDragDivSelf(x, y, w, h, text) {
const div = document.createElement('div');
div.style.position = 'absolute';
div.style.border = "1px solid black";
div.style.left = x + 'px';
div.style.top = y + 'px';
div.style.width = w + 'px';
div.style.height = h + 'px';
div.innerHTML = text;
createDragEventListener(div);
return div;
}
function createDragDiv(target, x, y, w, h, text) {
const div = document.createElement('div');
div.style.position = 'absolute';
div.style.border = "1px solid black";
div.style.left = x + 'px';
div.style.top = y + 'px';
div.style.width = w + 'px';
div.style.height = h + 'px';
div.innerHTML = text;
createDragEventListener(div, target);
return div;
}
function createDragEventListener(div, target) {
// Drag and Drop処理
let isDragging = false;
let offsetX, offsetY;
let offsetTX, offsetTY;
div.addEventListener('mousedown', (e) => {
isDragging = true;
offsetX = e.clientX - div.getBoundingClientRect().left;
offsetY = e.clientY - div.getBoundingClientRect().top;
if (target) {
offsetTX = e.clientX - target.getBoundingClientRect().left;
offsetTY = e.clientY - target.getBoundingClientRect().top;
}
document.addEventListener('mousemove', move);
document.addEventListener('mouseup', stopDragging);
});
function move(e) {
if (isDragging) {
div.style.left = (e.clientX - offsetX) + 'px';
div.style.top = (e.clientY - offsetY) + 'px';
if (target) {
target.style.left = (e.clientX - offsetTX) + 'px';
target.style.top = (e.clientY - offsetTY) + 'px';
}
}
}
const stopDragging = () => {
isDragging = false;
document.removeEventListener('mousemove', move);
document.removeEventListener('mouseup', stopDragging);
};
}
// 自分自身をdrag
const divSelf = createDragDivSelf(10, 10, 100, 100, "hello");
// dragする側とされる側
const dragged = document.createElement('div');
dragged.innerHTML = "dragged";
dragged.style.position = 'absolute';
dragged.style.border = "1px solid black";
dragged.style.left = 300 + 'px';
dragged.style.top = 100 + 'px';
dragged.style.width = 100 + 'px';
dragged.style.height = 100 + 'px';
const dragger = createDragDiv(dragged, 300, 10, 20, 20, "dragger");
document.body.appendChild(divSelf);
document.body.appendChild(dragger);
document.body.appendChild(dragged);
</script>
</body>
</html>
Google Colab用2
preventDefaultの追加(Drag対象の文字がハイライトされるのを防ぐ)
Drag中にマウスがwindowから出た時の処理の追加
%%html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DOM</title>
<style>
body {
width: 500px;
height: 500px;
}
</style>
</head>
<body>
<script type="module">
function createDragDivSelf(x, y, w, h, text) {
const div = document.createElement('div');
div.style.position = 'absolute';
div.style.border = "1px solid black";
div.style.left = x + 'px';
div.style.top = y + 'px';
div.style.width = w + 'px';
div.style.height = h + 'px';
div.innerHTML = text;
createDragEventListener(div);
return div;
}
function createDragDiv(target, x, y, w, h, text) {
const div = document.createElement('div');
div.style.position = 'absolute';
div.style.border = "1px solid black";
div.style.left = x + 'px';
div.style.top = y + 'px';
div.style.width = w + 'px';
div.style.height = h + 'px';
div.innerHTML = text;
createDragEventListener(div, target);
return div;
}
function createDragEventListener(div, target) {
// Drag and Drop処理
let isDragging = false;
let offsetX, offsetY;
let offsetTX, offsetTY;
div.addEventListener('mousedown', (e) => {
e.preventDefault(); // ドラッグ開始時にデフォルトのクリックイベントを無効化
isDragging = true;
offsetX = e.clientX - div.getBoundingClientRect().left;
offsetY = e.clientY - div.getBoundingClientRect().top;
if (target) {
offsetTX = e.clientX - target.getBoundingClientRect().left;
offsetTY = e.clientY - target.getBoundingClientRect().top;
}
document.addEventListener('mousemove', move);
document.addEventListener('mouseup', stopDragging);
window.addEventListener('mouseout', handleMouseOut);
});
function move(e) {
if (isDragging) {
div.style.left = (e.clientX - offsetX) + 'px';
div.style.top = (e.clientY - offsetY) + 'px';
if (target) {
target.style.left = (e.clientX - offsetTX) + 'px';
target.style.top = (e.clientY - offsetTY) + 'px';
}
}
}
function stopDragging() {
isDragging = false;
document.removeEventListener('mousemove', move);
document.removeEventListener('mouseup', stopDragging);
window.removeEventListener('mouseout', handleMouseOut);
}
function handleMouseOut(e) {
if (e.relatedTarget === null && isDragging) {
stopDragging();
}
}
}
// 自分自身をdrag
const divSelf = createDragDivSelf(10, 10, 100, 100, "hello");
// dragする側とされる側
const dragged = document.createElement('div');
dragged.innerHTML = "dragged";
dragged.style.position = 'absolute';
dragged.style.border = "1px solid black";
dragged.style.left = 300 + 'px';
dragged.style.top = 100 + 'px';
dragged.style.width = 100 + 'px';
dragged.style.height = 100 + 'px';
const dragger = createDragDiv(dragged, 300, 10, 20, 20, "dragger");
document.body.appendChild(divSelf);
document.body.appendChild(dragger);
document.body.appendChild(dragged);
</script>
</body>
</html>
IDやclassNameでDOM要素探してlogで表示
function createLogView(x,y,w,h) {
const div = document.createElement('div');
div.style.display = 'flex';
div.style.flexDirection = "column";
div.style.position = 'absolute';
div.style.left = x + 'px';
div.style.top = y + 'px';
div.style.width = w + 'px';
div.style.height = h + 'px';
// Input for ID
const targetDOMInputByID = document.createElement('input');
targetDOMInputByID.placeholder = "Enter ID";
div.appendChild(targetDOMInputByID);
// Button to get element by ID
const btnGetByID = document.createElement('button');
btnGetByID.textContent = "Get by ID";
div.appendChild(btnGetByID);
// Input for Class
const targetDOMInputByClass = document.createElement('input');
targetDOMInputByClass.placeholder = "Enter Class";
div.appendChild(targetDOMInputByClass);
// Button to get element by Class
const btnGetByClass = document.createElement('button');
btnGetByClass.textContent = "Get by Class";
div.appendChild(btnGetByClass);
let targetDOM;
btnGetByID.addEventListener('click', function () {
const idValue = targetDOMInputByID.value;
targetDOM = document.getElementById(idValue);
console.log(targetDOM);
});
btnGetByClass.addEventListener('click', function () {
const classValue = targetDOMInputByClass.value;
targetDOM = document.getElementsByClassName(classValue)[0]; // Only the first element with this class
console.log(targetDOM);
});
return div;
}
const viewer = createLogView(200,200,100,100);
document.body.appendChild(viewer);
Canvas+Scrollbar
初手
canvas要素包む。
行は減るがパラメータ数は変わっておらず。
export function CreateCanvas(x, y, width, height, id) {
const canvas = document.createElement('canvas');
canvas.id = id;
canvas.style.border = "1px solid black";
canvas.x = x;
canvas.y = y;
canvas.width = width;//canvas要素はwidth,heightを持つので+"px"は不要
canvas.height = height;
return canvas;
}
2手目
+ScrollBar
つくったcanvasを包む。
座標の移植とoverflowパラメータの操作。
export function CreateCanvasContainer(canvas) {
const container = document.createElement('div');
container.id = canvas.id + "Container";
//container.style.position = "absolute";
container.style.border = "1px solid black";
container.style.top = canvas.y + "px";
container.style.left = canvas.x + "px";
container.style.width = canvas.width + "px";//div要素はwidth,heightを持たないので+"px"が必要
container.style.height = canvas.height + "px";
//canvas側は座標を(0,0)に
canvas.style.top = 0 + 'px';
canvas.style.left = 0 + 'px';
container.style.overflow = "scroll";
container.appendChild(canvas);
//parent.appendChild(container);
return container;
}
関数内部でcanvasも作ってしまうパターン。
export function CreateCanvasContainer(x, y, width, height, id)
Flexboxに差し込むことなどを考えるとappenChildも内部でやってしまうパターン。
export function CreateCanvasContainer(parent, x, y, width, height, id)
レイヤー選択タブの元
//let x,y,w,h=100;//これだとhのみに100がはいる
let x = 100, y = 100, w = 100, h = 100;
const mainFrame = document.createElement('div');
mainFrame.id = "main_frame";
mainFrame.className = "MainFrame"
mainFrame.style.display = 'flex';
mainFrame.style.flexDirection = "column";
mainFrame.style.position = 'absolute';
mainFrame.style.border = "1px solid black";
mainFrame.style.left = x + 'px';
mainFrame.style.top = y + 'px';
// div.style.width = w + 'px';
// div.style.height = h + 'px';
//mainFrame.innerHTML = "hello";
document.body.appendChild(mainFrame);
const menubar = document.createElement('div');
menubar.id = "menubar";
menubar.className = "Menubar";
menubar.style.display = 'flex';
menubar.style.flexDirection = "row";
menubar.style.border = "1px solid black";
menubar.innerHTML = "menu";
mainFrame.appendChild(menubar);
let tabCount = 0;
const tabWidth = 300;
const tabHeight = 50;
let currentTab = null;
const upButton = document.createElement('button');
upButton.textContent = "up";
menubar.appendChild(upButton);
const downButton = document.createElement('button');
downButton.textContent = "down";
menubar.appendChild(downButton);
upButton.addEventListener('click', function () {
if (currentTab && currentTab.previousElementSibling) {
scrollContainer.insertBefore(currentTab, currentTab.previousElementSibling);
}
});
downButton.addEventListener('click', function () {
if (currentTab && currentTab.nextElementSibling) {
scrollContainer.insertBefore(currentTab.nextElementSibling, currentTab);
}
});
const addButton = document.createElement('button');
addButton.textContent = "add";
menubar.appendChild(addButton);
addButton.addEventListener('click', function () {
const tab = document.createElement('div');
tab.className = "Tab";
tab.style.display = 'flex';
tab.style.flexDirection = "row";
tab.style.border = "1px solid black";
tab.style.width = tabWidth + "px";
tab.style.height = tabHeight + "px";
tab.innerHTML = `tab ${tabCount}`;//バックスティックを使う
scrollContainer.appendChild(tab);
tabCount++;
});
const scrollContainer = document.createElement('div');
scrollContainer.id = "scroll_container";
scrollContainer.className = "ScrollContainer";
scrollContainer.style.overflow = "scroll";
scrollContainer.style.display = 'flex';
scrollContainer.style.flexDirection = "column";
scrollContainer.style.border = "1px solid black";
scrollContainer.innerHTML = "hello";
mainFrame.appendChild(scrollContainer);
scrollContainer.addEventListener('click', function (e) {
const tab = e.target.closest('div');
if (tab&&tab.className==="Tab") {
if(currentTab){
currentTab.style.background = "";
}
currentTab = tab;
currentTab.style.background = "rgba(0, 0, 255, 0.5)";
//console.log(tab.innerHTML);
}
});
const statusbar = document.createElement('div');
menubar.id = "statusbar";
menubar.className = "Statusbar";
statusbar.style.display = 'flex';
statusbar.style.flexDirection = "row";
statusbar.style.border = "1px solid black";
statusbar.innerHTML = "status";
mainFrame.appendChild(statusbar);
scrollContainer(Tabの親)のconst tab = e.target.closest('div');と
if (tab&&tab.className==="Tab")で
並んでるタブからクリックされたものを検出。
Google Colab用
%%html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DOM</title>
<style>
body {
position: relative;
}
.MainFrame {
display: flex;
flex-direction: column;
position: absolute;
border: 1px solid black;
}
.Menubar, .Statusbar {
display: flex;
flex-direction: row;
border: 1px solid black;
}
.ScrollContainer {
overflow: scroll;
display: flex;
flex-direction: column;
border: 1px solid black;
height: 200px;
}
.Tab {
display: flex;
flex-direction: row;
border: 1px solid black;
width: 300px;
height: 50px;
}
</style>
</head>
<body>
<script type="module">
let x = 100, y = 100, w = 100, h = 100;
const mainFrame = document.createElement('div');
mainFrame.id = "main_frame";
mainFrame.className = "MainFrame";
mainFrame.style.left = x + 'px';
mainFrame.style.top = y + 'px';
document.body.appendChild(mainFrame);
const menubar = document.createElement('div');
menubar.id = "menubar";
menubar.className = "Menubar";
menubar.innerHTML = "menu";
mainFrame.appendChild(menubar);
let tabCount = 0;
const tabWidth = 300;
const tabHeight = 50;
let currentTab = null;
const upButton = document.createElement('button');
upButton.textContent = "up";
menubar.appendChild(upButton);
const downButton = document.createElement('button');
downButton.textContent = "down";
menubar.appendChild(downButton);
upButton.addEventListener('click', function () {
if (currentTab && currentTab.previousElementSibling) {
scrollContainer.insertBefore(currentTab, currentTab.previousElementSibling);
}
});
downButton.addEventListener('click', function () {
if (currentTab && currentTab.nextElementSibling) {
scrollContainer.insertBefore(currentTab.nextElementSibling, currentTab);
}
});
const addButton = document.createElement('button');
addButton.textContent = "add";
menubar.appendChild(addButton);
addButton.addEventListener('click', function () {
const tab = document.createElement('div');
tab.className = "Tab";
tab.innerHTML = `tab ${tabCount}`;
scrollContainer.appendChild(tab);
tabCount++;
});
const scrollContainer = document.createElement('div');
scrollContainer.id = "scroll_container";
scrollContainer.className = "ScrollContainer";
mainFrame.appendChild(scrollContainer);
scrollContainer.addEventListener('click', function (e) {
const tab = e.target.closest('div');
if (tab && tab.className === "Tab") {
if (currentTab) {
currentTab.style.background = "";
}
currentTab = tab;
currentTab.style.background = "rgba(0, 0, 255, 0.5)";
}
});
const statusbar = document.createElement('div');
statusbar.id = "statusbar";
statusbar.className = "Statusbar";
statusbar.innerHTML = "status";
mainFrame.appendChild(statusbar);
</script>
</body>
</html>
畳めるdiv要素
export function MakeFoldingbox(parent, w, h) {
let foldingbar_h = 10;
// フレックスコンテナを生成
const flexContainer = document.createElement('div');
flexContainer.id = 'Foldingbox';
flexContainer.style.position = "absolute";
flexContainer.style.display = "flex";
flexContainer.style.flexDirection = "column";
flexContainer.style.width = w + "px";
//container.style.height = canvas.height + "px";
parent.appendChild(flexContainer);
const scrollContainer = document.createElement('div');
scrollContainer.id = "ScrollContainer";
scrollContainer.style.border = "1px solid black";
scrollContainer.style.overflow = "scroll";
scrollContainer.style.width = w + "px";
scrollContainer.style.height = h-foldingbar_h + "px";
flexContainer.appendChild(scrollContainer);
//これは後から格納する
// const innerDiv = document.createElement('div');
// innerDiv.id = canvas.id + "innerDiv";
// innerDiv.style.border = "1px solid black";
// innerDiv.style.width = w + "px";
// innerDiv.style.height = h-foldingbar_h + "px";
// scrollContainer.appendChild(innerDiv);
const foldingbar = document.createElement('div');
foldingbar.id = "Foldingbar";
foldingbar.style.border = "1px solid black";
foldingbar.style.width = w + "px";
foldingbar.style.height = foldingbar_h + "px";
flexContainer.appendChild(foldingbar);
let isDragging = false;
let startY;
foldingbar.addEventListener("mousedown", (e) => {
isDragging = true;
startY = e.clientY;
});
window.addEventListener("mousemove", (e) => {
if (isDragging) {
const deltaY = e.clientY - startY;
const newHeight = parseInt(scrollContainer.style.height) + deltaY;
if (newHeight > 0 && foldingbar.offsetTop >= scrollContainer.offsetTop) {
scrollContainer.style.height = newHeight + "px";
foldingbar.style.top = (foldingbar.offsetTop + deltaY) + "px";
}
startY = e.clientY;
}
});
window.addEventListener("mouseup", () => {
isDragging = false;
});
return flexContainer;
}
Google Colab用
%%html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DOM</title>
<style>
body {
position: relative;
}
#Foldingbox {
position: absolute;
display: flex;
flex-direction: column;
}
#ScrollContainer {
border: 1px solid black;
overflow: scroll;
}
#Foldingbar {
border: 1px solid black;
cursor: ns-resize;
}
</style>
</head>
<body>
<script type="module">
function MakeFoldingbox(parent, w, h) {
let foldingbar_h = 10;
// フレックスコンテナを生成
const flexContainer = document.createElement('div');
flexContainer.id = 'Foldingbox';
flexContainer.style.width = w + "px";
parent.appendChild(flexContainer);
const scrollContainer = document.createElement('div');
scrollContainer.id = "ScrollContainer";
scrollContainer.style.width = w + "px";
scrollContainer.style.height = h - foldingbar_h + "px";
flexContainer.appendChild(scrollContainer);
const foldingbar = document.createElement('div');
foldingbar.id = "Foldingbar";
foldingbar.style.width = w + "px";
foldingbar.style.height = foldingbar_h + "px";
flexContainer.appendChild(foldingbar);
let isDragging = false;
let startY;
foldingbar.addEventListener("mousedown", (e) => {
isDragging = true;
startY = e.clientY;
});
window.addEventListener("mousemove", (e) => {
if (isDragging) {
const deltaY = e.clientY - startY;
const newHeight = parseInt(scrollContainer.style.height) + deltaY;
if (newHeight > 0 && foldingbar.offsetTop >= scrollContainer.offsetTop) {
scrollContainer.style.height = newHeight + "px";
foldingbar.style.top = (foldingbar.offsetTop + deltaY) + "px";
}
startY = e.clientY;
}
});
window.addEventListener("mouseup", () => {
isDragging = false;
});
return flexContainer;
}
// サンプル使用例
const parentElement = document.body;
const foldingBox = MakeFoldingbox(parentElement, 300, 200);
</script>
</body>
</html>
Flexbox(Col)にFlexbox(Row)を継いでいく
index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Canvas Grids</title>
</head>
<body>
<script src="main.js"></script>
</body>
</html>
main.js
let x = 100;
let y = 100;
class InputManager {
constructor() {
this.isDragging = true;
this.prevX = 0;
this.prevY = 0;
}
}
const inputManager = new InputManager();
// フレックスコンテナを生成
const flexContainerCol = document.createElement('div');
flexContainerCol.id = 'mainFrame';
flexContainerCol.style.position = "absolute";
flexContainerCol.style.display = "flex";
flexContainerCol.style.flexDirection = "column";
//flexContainerCol.style.alignItems = "center";
// flexContainerCol.style.zIndex = "100"; //mainFrameより優先
flexContainerCol.style.left = x + "px";
flexContainerCol.style.top = y + "px";
flexContainerCol.style.width = '300px';
flexContainerCol.style.height = '500px';
flexContainerCol.style.border = '1px solid black';
document.body.appendChild(flexContainerCol);
/////////////////////////////////////////////////////////////////////////////
const flexContainerRow = document.createElement('div');
flexContainerRow.style.width = '300px';
flexContainerRow.style.height = '50px';
flexContainerRow.style.border = '1px solid black';
flexContainerRow.style.display = 'flex';
flexContainerRow.style.flexDirection = "row";
//this.flexContainerRow.style.justifyContent = 'center';
//this.flexContainerRow.style.alignItems = 'center';
flexContainerCol.appendChild(flexContainerRow);
/////////////////////////////////////////////////////////////////////////////
// ドラッグ対象のdivを作成
const draggableDiv = document.createElement('div');
draggableDiv.textContent = "ドラッグして移動";
draggableDiv.style.border = "1px solid black";
//draggableDiv.style.padding = '10px';
//draggableDiv.style.background = 'lightgray';
draggableDiv.style.cursor = 'pointer';
flexContainerRow.appendChild(draggableDiv);
// mousedownイベント
draggableDiv.addEventListener("mousedown", function (event) {
inputManager.isDragging = true;
inputManager.prevX = event.clientX;
inputManager.prevY = event.clientY;
});
window.addEventListener("mousemove", function (event) {
if (inputManager.isDragging) {
const dx = event.clientX - inputManager.prevX;
const dy = event.clientY - inputManager.prevY;
if (mainFrame.style.display === "none") {
// menubarの現在の位置を取得
const currentTop = parseInt(flexContainerRow.style.top || 0, 10);
const currentLeft = parseInt(flexContainerRow.style.left || 0, 10);
// 新しい位置を設定
flexContainerRow.style.top = `${currentTop + dy}px`;
flexContainerRow.style.left = `${currentLeft + dx}px`;
} else {
// mainFrameの現在の位置を取得
const currentTop = parseInt(flexContainerCol.style.top || 0, 10);
const currentLeft = parseInt(flexContainerCol.style.left || 0, 10);
// 新しい位置を設定
flexContainerCol.style.top = `${currentTop + dy}px`;
flexContainerCol.style.left = `${currentLeft + dx}px`;
}
inputManager.prevX = event.clientX;
inputManager.prevY = event.clientY;
}
});
// mouseupイベント
window.addEventListener("mouseup", function () {
inputManager.isDragging = false;
});
関数の分離
親の親をドラッグできる、という能力をdiv要素に持たせたい。
そのため、div要素のparentNodeを2回呼びだして親の親を辿るようにした。
また、親をドラッグできる、という能力も与えたい。
結果関数として分離した。
targetをドラッグしたい、といった抽象的な要求はclass化するなりグローバススコープに変数を確保する必要があると思われる。
やること:クロージャを試す。
let x = 100;
let y = 100;
class InputManager {
constructor() {
this.isDragging = true;
this.prevX = 0;
this.prevY = 0;
}
}
const inputManager = new InputManager();
// フレックスコンテナを生成
const flexContainerCol = document.createElement('div');
flexContainerCol.id = 'mainFrame';
flexContainerCol.style.position = "absolute";
flexContainerCol.style.display = "flex";
flexContainerCol.style.flexDirection = "column";
//flexContainerCol.style.alignItems = "center";
// flexContainerCol.style.zIndex = "100"; //mainFrameより優先
flexContainerCol.style.left = x + "px";
flexContainerCol.style.top = y + "px";
flexContainerCol.style.width = '300px';
flexContainerCol.style.height = '500px';
flexContainerCol.style.border = '1px solid black';
document.body.appendChild(flexContainerCol);
/////////////////////////////////////////////////////////////////////////////
const flexContainerRow = document.createElement('div');
flexContainerRow.style.position = "absolute";
flexContainerRow.style.width = '300px';
flexContainerRow.style.height = '50px';
flexContainerRow.style.border = '1px solid black';
flexContainerRow.style.display = 'flex';
flexContainerRow.style.flexDirection = "row";
//this.flexContainerRow.style.justifyContent = 'center';
//this.flexContainerRow.style.alignItems = 'center';
flexContainerCol.appendChild(flexContainerRow);
//document.body.appendChild(flexContainerRow);
/////////////////////////////////////////////////////////////////////////////
// ドラッグ対象のdivを作成
const draggableDiv = document.createElement('div');
draggableDiv.textContent = "ドラッグして移動";
draggableDiv.style.border = "1px solid black";
//draggableDiv.style.padding = '10px';
//draggableDiv.style.background = 'lightgray';
draggableDiv.style.cursor = 'pointer';
flexContainerRow.appendChild(draggableDiv);
// mousedownイベント
draggableDiv.addEventListener("mousedown", function (event) {
inputManager.isDragging = true;
inputManager.prevX = event.clientX;
inputManager.prevY = event.clientY;
});
window.addEventListener("mousemove", parentParentDrag);
// mouseupイベント
window.addEventListener("mouseup", function () {
inputManager.isDragging = false;
});
function parentParentDrag(event) {
if (inputManager.isDragging) {
const dx = event.clientX - inputManager.prevX;
const dy = event.clientY - inputManager.prevY;
// draggableDivの親の親を取得
const parentOfParent = draggableDiv.parentNode.parentNode;
// 親の親の現在の位置を取得
const currentTop = parseInt(parentOfParent.style.top || 0, 10);
const currentLeft = parseInt(parentOfParent.style.left || 0, 10);
// 新しい位置を設定
parentOfParent.style.top = `${currentTop + dy}px`;
parentOfParent.style.left = `${currentLeft + dx}px`;
inputManager.prevX = event.clientX;
inputManager.prevY = event.clientY;
}
}
function parentDrag(event) {
if (inputManager.isDragging) {
const dx = event.clientX - inputManager.prevX;
const dy = event.clientY - inputManager.prevY;
// draggableDivの親の親を取得
const parent = draggableDiv.parentNode;
// 親の親の現在の位置を取得
const currentTop = parseInt(parent.style.top || 0, 10);
const currentLeft = parseInt(parent.style.left || 0, 10);
// 新しい位置を設定
parent.style.top = `${currentTop + dy}px`;
parent.style.left = `${currentLeft + dx}px`;
inputManager.prevX = event.clientX;
inputManager.prevY = event.clientY;
}
}
[Purge]ParentのParentからParentを切り離す
let x = 100;
let y = 100;
class InputManager {
constructor() {
this.isDragging = true;
this.prevX = 0;
this.prevY = 0;
}
}
const inputManager = new InputManager();
// フレックスコンテナを生成
const flexContainerCol = document.createElement('div');
flexContainerCol.id = 'mainFrame';
flexContainerCol.style.position = "absolute";
flexContainerCol.style.display = "flex";
flexContainerCol.style.flexDirection = "column";
//flexContainerCol.style.alignItems = "center";
// flexContainerCol.style.zIndex = "100"; //mainFrameより優先
flexContainerCol.style.left = x + "px";
flexContainerCol.style.top = y + "px";
flexContainerCol.style.width = '300px';
flexContainerCol.style.height = '500px';
flexContainerCol.style.border = '1px solid black';
document.body.appendChild(flexContainerCol);
/////////////////////////////////////////////////////////////////////////////
const flexContainerRow = document.createElement('div');
flexContainerRow.style.position = "absolute";
flexContainerRow.style.width = '300px';
flexContainerRow.style.height = '50px';
flexContainerRow.style.border = '1px solid black';
flexContainerRow.style.display = 'flex';
flexContainerRow.style.flexDirection = "row";
//this.flexContainerRow.style.justifyContent = 'center';
//this.flexContainerRow.style.alignItems = 'center';
flexContainerCol.appendChild(flexContainerRow);
//document.body.appendChild(flexContainerRow);
/////////////////////////////////////////////////////////////////////////////
// ドラッグ対象のdivを作成
const draggableDiv = document.createElement('div');
draggableDiv.textContent = "ドラッグして移動";
draggableDiv.style.border = "1px solid black";
//draggableDiv.style.padding = '10px';
//draggableDiv.style.background = 'lightgray';
draggableDiv.style.cursor = 'pointer';
flexContainerRow.appendChild(draggableDiv);
// mousedownイベント
draggableDiv.addEventListener("mousedown", function (event) {
inputManager.isDragging = true;
inputManager.prevX = event.clientX;
inputManager.prevY = event.clientY;
});
window.addEventListener("mousemove", parentParentDrag);
// mouseupイベント
window.addEventListener("mouseup", function () {
inputManager.isDragging = false;
});
// 新しいdiv要素を作成
const newDiv = document.createElement('div');
newDiv.textContent = "Purge";
newDiv.style.border = "1px solid red";
//newDiv.style.margin = "10px";
newDiv.style.cursor = 'pointer';
flexContainerRow.appendChild(newDiv);
newDiv.addEventListener("mousedown", function(event) {
// 親要素を親の親から削除
const parent = this.parentNode;
const parentOfParent = parent.parentNode;
let x = getAbsolutePositionX(parent);
let y = getAbsolutePositionY(parent);
parent.style.left = x + "px";
parent.style.top = y + "px";
parentOfParent.removeChild(parent);
document.body.appendChild(parent);
// parentParentDragからparentDragに切り替え
window.removeEventListener("mousemove", parentParentDrag);
window.addEventListener("mousemove", parentDrag);
// ドラッグを開始
inputManager.isDragging = true;
inputManager.prevX = event.clientX;
inputManager.prevY = event.clientY;
});
function parentParentDrag(event) {
if (inputManager.isDragging) {
const dx = event.clientX - inputManager.prevX;
const dy = event.clientY - inputManager.prevY;
// draggableDivの親の親を取得
const parentOfParent = draggableDiv.parentNode.parentNode;
// 親の親の現在の位置を取得
const currentTop = parseInt(parentOfParent.style.top || 0, 10);
const currentLeft = parseInt(parentOfParent.style.left || 0, 10);
// 新しい位置を設定
parentOfParent.style.top = `${currentTop + dy}px`;
parentOfParent.style.left = `${currentLeft + dx}px`;
inputManager.prevX = event.clientX;
inputManager.prevY = event.clientY;
}
}
function parentDrag(event) {
if (inputManager.isDragging) {
const dx = event.clientX - inputManager.prevX;
const dy = event.clientY - inputManager.prevY;
// draggableDivの親の親を取得
const parent = draggableDiv.parentNode;
// 親の親の現在の位置を取得
const currentTop = parseInt(parent.style.top || 0, 10);
const currentLeft = parseInt(parent.style.left || 0, 10);
// 新しい位置を設定
parent.style.top = `${currentTop + dy}px`;
parent.style.left = `${currentLeft + dx}px`;
inputManager.prevX = event.clientX;
inputManager.prevY = event.clientY;
}
}
function getAbsolutePositionX(element) {
let xPosition = 0;
while (element) {
xPosition += (element.offsetLeft - element.scrollLeft + element.clientLeft);
element = element.offsetParent;
}
return xPosition;
}
function getAbsolutePositionY(element) {
let yPosition = 0;
while (element) {
yPosition += (element.offsetTop - element.scrollTop + element.clientTop);
element = element.offsetParent;
}
return yPosition;
}
getBoundingClientRectを使う場合
let x = 100;
let y = 100;
class InputManager {
constructor() {
this.isDragging = true;
this.prevX = 0;
this.prevY = 0;
}
}
const inputManager = new InputManager();
// フレックスコンテナを生成
const flexContainerCol = document.createElement('div');
flexContainerCol.id = 'mainFrame';
flexContainerCol.style.position = "absolute";
flexContainerCol.style.display = "flex";
flexContainerCol.style.flexDirection = "column";
//flexContainerCol.style.alignItems = "center";
// flexContainerCol.style.zIndex = "100"; //mainFrameより優先
flexContainerCol.style.left = x + "px";
flexContainerCol.style.top = y + "px";
flexContainerCol.style.width = '300px';
flexContainerCol.style.height = '500px';
flexContainerCol.style.border = '1px solid black';
document.body.appendChild(flexContainerCol);
/////////////////////////////////////////////////////////////////////////////
const flexContainerRow = document.createElement('div');
flexContainerRow.style.position = "absolute";
flexContainerRow.style.width = '300px';
flexContainerRow.style.height = '50px';
flexContainerRow.style.border = '1px solid black';
flexContainerRow.style.display = 'flex';
flexContainerRow.style.flexDirection = "row";
//this.flexContainerRow.style.justifyContent = 'center';
//this.flexContainerRow.style.alignItems = 'center';
flexContainerCol.appendChild(flexContainerRow);
//document.body.appendChild(flexContainerRow);
/////////////////////////////////////////////////////////////////////////////
// ドラッグ対象のdivを作成
const draggableDiv = document.createElement('div');
draggableDiv.textContent = "ドラッグして移動";
draggableDiv.style.border = "1px solid black";
//draggableDiv.style.padding = '10px';
//draggableDiv.style.background = 'lightgray';
draggableDiv.style.cursor = 'pointer';
flexContainerRow.appendChild(draggableDiv);
// mousedownイベント
draggableDiv.addEventListener("mousedown", function (event) {
inputManager.isDragging = true;
inputManager.prevX = event.clientX;
inputManager.prevY = event.clientY;
});
window.addEventListener("mousemove", parentParentDrag);
// mouseupイベント
window.addEventListener("mouseup", function () {
inputManager.isDragging = false;
});
// 新しいdiv要素を作成
const newDiv = document.createElement('div');
newDiv.textContent = "Purge";
newDiv.style.border = "1px solid red";
//newDiv.style.margin = "10px";
newDiv.style.cursor = 'pointer';
flexContainerRow.appendChild(newDiv);
newDiv.addEventListener("mousedown", function(event) {
// 親要素を親の親から削除
const parent = this.parentNode;
const parentOfParent = parent.parentNode;
// getBoundingClientRectを使用して要素の位置を取得
const rect = parent.getBoundingClientRect();
let x = rect.left;
let y = rect.top;
parent.style.left = x + "px";
parent.style.top = y + "px";
// 要素の位置とマウスの位置のオフセットを計算する場合
//const offsetX = event.clientX - x;
//const offsetY = event.clientY - y;
//parent.style.left = (x + offsetX) + "px";
//parent.style.top = (y + offsetY) + "px";
parentOfParent.removeChild(parent);
document.body.appendChild(parent);
// parentParentDragからparentDragに切り替え
window.removeEventListener("mousemove", parentParentDrag);
window.addEventListener("mousemove", parentDrag);
// ドラッグを開始
inputManager.isDragging = true;
inputManager.prevX = event.clientX;
inputManager.prevY = event.clientY;
});
function parentParentDrag(event) {
if (inputManager.isDragging) {
const dx = event.clientX - inputManager.prevX;
const dy = event.clientY - inputManager.prevY;
// draggableDivの親の親を取得
const parentOfParent = draggableDiv.parentNode.parentNode;
// 親の親の現在の位置を取得
const currentTop = parseInt(parentOfParent.style.top || 0, 10);
const currentLeft = parseInt(parentOfParent.style.left || 0, 10);
// 新しい位置を設定
parentOfParent.style.top = `${currentTop + dy}px`;
parentOfParent.style.left = `${currentLeft + dx}px`;
inputManager.prevX = event.clientX;
inputManager.prevY = event.clientY;
}
}
function parentDrag(event) {
if (inputManager.isDragging) {
const dx = event.clientX - inputManager.prevX;
const dy = event.clientY - inputManager.prevY;
// draggableDivの親の親を取得
const parent = draggableDiv.parentNode;
// 親の親の現在の位置を取得
const currentTop = parseInt(parent.style.top || 0, 10);
const currentLeft = parseInt(parent.style.left || 0, 10);
// 新しい位置を設定
parent.style.top = `${currentTop + dy}px`;
parent.style.left = `${currentLeft + dx}px`;
inputManager.prevX = event.clientX;
inputManager.prevY = event.clientY;
}
}
[Dock]Purgeしてから元に戻す
ただし現状の実装だと切り離した瞬間に元に戻ってしまうエリアがある。
let x = 100;
let y = 100;
class InputManager {
constructor() {
this.isDragging = true;
this.prevX = 0;
this.prevY = 0;
}
}
const inputManager = new InputManager();
// フレックスコンテナを生成
const flexContainerCol = document.createElement('div');
flexContainerCol.id = 'mainFrame';
flexContainerCol.style.position = "absolute";
flexContainerCol.style.display = "flex";
flexContainerCol.style.flexDirection = "column";
//flexContainerCol.style.alignItems = "center";
// flexContainerCol.style.zIndex = "100"; //mainFrameより優先
flexContainerCol.style.left = x + "px";
flexContainerCol.style.top = y + "px";
flexContainerCol.style.width = '300px';
flexContainerCol.style.height = '500px';
flexContainerCol.style.border = '1px solid black';
document.body.appendChild(flexContainerCol);
/////////////////////////////////////////////////////////////////////////////
const flexContainerRow = document.createElement('div');
flexContainerRow.style.position = "absolute";
flexContainerRow.style.width = '300px';
flexContainerRow.style.height = '50px';
flexContainerRow.style.border = '1px solid black';
flexContainerRow.style.display = 'flex';
flexContainerRow.style.flexDirection = "row";
//this.flexContainerRow.style.justifyContent = 'center';
//this.flexContainerRow.style.alignItems = 'center';
flexContainerCol.appendChild(flexContainerRow);
//document.body.appendChild(flexContainerRow);
/////////////////////////////////////////////////////////////////////////////
// ドラッグ対象のdivを作成
const draggableDiv = document.createElement('div');
draggableDiv.textContent = "ドラッグして移動";
draggableDiv.style.border = "1px solid black";
//draggableDiv.style.padding = '10px';
//draggableDiv.style.background = 'lightgray';
draggableDiv.style.cursor = 'pointer';
flexContainerRow.appendChild(draggableDiv);
// mousedownイベント
draggableDiv.addEventListener("mousedown", function (event) {
inputManager.isDragging = true;
inputManager.prevX = event.clientX;
inputManager.prevY = event.clientY;
});
window.addEventListener("mousemove", parentParentDrag);
// mouseupイベント
window.addEventListener("mouseup", function () {
inputManager.isDragging = false;
});
// 新しいdiv要素を作成
const newDiv = document.createElement('div');
newDiv.textContent = "Purge";
newDiv.style.border = "1px solid red";
//newDiv.style.margin = "10px";
newDiv.style.cursor = 'pointer';
flexContainerRow.appendChild(newDiv);
newDiv.addEventListener("mousedown", function(event) {
// 親要素を親の親から削除
const parent = this.parentNode;
const parentOfParent = parent.parentNode;
// getBoundingClientRectを使用して要素の位置を取得
const rect = parent.getBoundingClientRect();
let x = rect.left;
let y = rect.top;
parent.style.left = x + "px";
parent.style.top = y + "px";
// 要素の位置とマウスの位置のオフセットを計算する場合
//const offsetX = event.clientX - x;
//const offsetY = event.clientY - y;
//parent.style.left = (x + offsetX) + "px";
//parent.style.top = (y + offsetY) + "px";
parentOfParent.removeChild(parent);
document.body.appendChild(parent);
// parentParentDragからparentDragに切り替え
window.removeEventListener("mousemove", parentParentDrag);
window.addEventListener("mousemove", parentDrag);
// ドラッグを開始
inputManager.isDragging = true;
inputManager.prevX = event.clientX;
inputManager.prevY = event.clientY;
});
function parentParentDrag(event) {
if (inputManager.isDragging) {
const dx = event.clientX - inputManager.prevX;
const dy = event.clientY - inputManager.prevY;
// draggableDivの親の親を取得
const parentOfParent = draggableDiv.parentNode.parentNode;
// 親の親の現在の位置を取得
const currentTop = parseInt(parentOfParent.style.top || 0, 10);
const currentLeft = parseInt(parentOfParent.style.left || 0, 10);
// 新しい位置を設定
parentOfParent.style.top = `${currentTop + dy}px`;
parentOfParent.style.left = `${currentLeft + dx}px`;
inputManager.prevX = event.clientX;
inputManager.prevY = event.clientY;
}
}
function parentDrag(event) {
if (inputManager.isDragging) {
const dx = event.clientX - inputManager.prevX;
const dy = event.clientY - inputManager.prevY;
// draggableDivの親を取得
const parent = draggableDiv.parentNode;
// 親の現在の位置を取得
const currentTop = parseInt(parent.style.top || 0, 10);
const currentLeft = parseInt(parent.style.left || 0, 10);
// 新しい位置を設定
parent.style.top = `${currentTop + dy}px`;
parent.style.left = `${currentLeft + dx}px`;
inputManager.prevX = event.clientX;
inputManager.prevY = event.clientY;
// ここから条件をチェックして、指定の操作を行います
const flexContainerColRect = flexContainerCol.getBoundingClientRect();
const parentRect = parent.getBoundingClientRect();
if (flexContainerColRect.left < parentRect.left && parentRect.left < flexContainerColRect.left + 20) {
if(flexContainerColRect.bottom > parentRect.top && parentRect.top > flexContainerColRect.top) {
parent.style.top = 0 + "px";
parent.style.left = 0 + "px";
// parentをdocument.bodyからremoveChild
document.body.removeChild(parent);
// parentをflexContainerColにappendChild
flexContainerCol.appendChild(parent);
// parentParentDragに戻す
window.removeEventListener("mousemove", parentDrag);
window.addEventListener("mousemove", parentParentDrag);
}
}
}
}
div要素のルートまで辿る
ほんとのルートはdocument.bodyになるので、document.bodyの直接の子供まで辿る。
function findConvenientRoot(element) {
while (element && element.parentNode !== document.body) {
element = element.parentNode;
}
return element;
}
// 使用例
let div = document.querySelector('#someDiv'); // 任意のdiv要素を取得
let root = findConvenientRoot(div);
console.log(root); // divからdocument.bodyの直接の子要素への参照
この記事が気に入ったらサポートをしてみませんか?