HTML/JavaScriptでDOMをドラッグ&ドロップで動かせるようにしたい

https://teratail.com/questions/4pnustw5rp458d

<!DOCTYPE html>
<meta charset="utf-8">
<title></title>
<style>
p {
  border: solid 1px black;
  width: 100px;
  height: 100px;
  margin: 0;
}
</style>


<body>

<p>drag</p>

<script>

class A {
  
  draggable = false;
  diffX = null;
  diffY = null;

  #init = function (e) {
    ['mousedown','mouseup', 'mousemove', 'mouseout'].forEach (etype=>e.addEventListener (etype, this, false));
    e.draggable = false;
    e.style.position = 'absolute';
  };

  constructor (target) {
    this.target = target;
    this.#init (target);
  }
  
  locate (x, y) {
    let s = this.target.style;
    s.top = (this.diffY + y) + 'px';
    s.left = (this.diffX + x) + 'px';
  }


  handleEvent (event) {
    switch (event.type) {
    case 'mousedown':
      this.draggable = true;
      let { top, left } = this.target.getBoundingClientRect ();
      let { clientX: mx, clientY: my} = event;
      this.diffX = (left - mx) | 0;
      this.diffY = (top - my) | 0;
      break;

    case 'mouseup' : case 'mouseout' :
      this.draggable = false;
      break;

    case 'mousemove':
      if (this.draggable) {
        let { pageX: x, pageY: y} = event;
        this.locate (x, y);    
      }
      break;
    }
  }

}

let p = new A (document.querySelector ('p'));

//_________________

{//蛇足
  let p = document.createElement ('p');
  for (let i = 1; i <= 12; i++) {
    let _p = p.cloneNode (true);
    let x = 600 + Math.sin (360/12*i*Math.PI/180)*300;
    let y = 320 - Math.cos (360/12*i*Math.PI/180)*300;
    document.body.appendChild (_p).append ('drag', i);
    
    _p.style.position = 'absolute';
    _p.style.top = (y|0) + 'px';
    _p.style.left = (x|0) + 'px';
    new A (_p);
  }
}
</script>

画面をこするとページ遷移するコード
https://teratail.com/questions/j459osplrnxfeo

「こする」をどうとらえるか?

<!DOCTYPE html>
<meta charset="utf-8">
<title></title>
<style>
</style>

<body>

<a href="https://www.google.co.jp/">
  <img src="https://picsum.photos/600/200?random=1"><br>
  <p>Test</p>
</a>

<script>


class A {
  #clientX = null;
  #clientY = null;

  constructor (target, limit = 600) {
    this.target = target;
    this.limit = limit;
    this.distance = null;

    this.clientX = null;
    this.clientY = null;

    document.addEventListener ('mousemove', this, false);
  }

  targetOut () {
    this.distance = this.#clientX = this.#clientY = null;
    return this;
  }

  targetIn (event) {
    this.distance = 1;
    this.#clientX = event.clientX;
    this.#clientY = event.clientY;
  }

  targetMove (event) {
    let { clientX: x, clientY: y } = event;
    this.distance += (
      (this.#clientX - x) ** 2 +
      (this.#clientY - y) ** 2
    ) **.5;

    if (this.distance < this.limit) {
      this.#clientX = x;
      this.#clientY = y;
//      console.log(this.distance);
    }
    else {
      this.target.click ();
    }
  }

  handleEvent (event) {
    let e = event.target;
    if (this.target.contains (e)) {
      if (! this.distance)
        this.targetIn (event);
      this.targetMove (event);
    } else {
      this.targetOut (); 
    }
  }
}

let a = new A (document.querySelector ('a'));

</script>

javascript: さてこの質問にどうやって最小のコードで書くか?!

OKWAVE セレクトボックスで、逆順に選択しても同じにしたい

https://okwave.jp/qa/q10023002.html
//
https://okwave.jp/qa/q10021995.html
質:「能力なき者泣き寝入りせざるを得ませんか。」

俺:「学校では平等だったかもしれませんが、社会では泣くしかありません。
もちろん寝たところで解決しません。
違う道を歩むことをお勧めします。」

質:「人の能力を評価するのはいいですが、才能の限界までいう人は生物としてみることができません。」
//

その回答に今度は寺尾で答えてみた。
https://teratail.com/questions/nx3z7htkbmp4ae

その直後、OKWAVEなどでそのコードを使って質問しまくっている
気に入ってくれたのだろう?!
//

なんとかして、泣き寝入りさせてみたい!
いやっ!ここで放置プレーすればよい!
//
進展!
https://oshiete.goo.ne.jp/qa/13012030.html
質:「もしこれに誰も答えられなかったら技術者は罵詈雑言を吐かれてもしょうがないものとみなします。」

これって泣き寝入りの手前だよな!

//


fujillin 君はOKWAVEを見ていない。
そして、
https://oshiete.goo.ne.jp/qa/13012030.html
>あなたは、動物ですか。動物ならこんな回答しません。
と、言われてしまい・・・
植物か菌類か?!
//
思うに日本人じゃないよな。

<!DOCTYPE html>
<meta charset="utf-8">
<title></title>
<style>
</style>

<body>
<p id=A>
<select id=B>
	<option value="">--
        <option value="nakamozu">中百舌鳥
	<option value="fukai">深井
	<option value="izumigaoka">泉ケ丘
        <option value="togamikita">栂・美木多
	<option value="komyoike">光明池
	<option value="a0">a0
	<option value="a1">a1
	<option value="a2">a2
</select>

<select id=C>
	<option value="">--
        <option value="nakamozu">中百舌鳥
	<option value="fukai">深井
	<option value="izumigaoka">泉ケ丘
        <option value="togamikita">栂・美木多
	<option value="komyoike">光明池
	<option value="b0">b0
	<option value="b1">b1
	<option value="b2">b2
</select>
</p>
<p id=D></p>

<script>
const vals = {
    'nakamozufukai':3.7,
    'nakamozuizumigaoka':7.8,
    'a0b0': 1.2,
    'a0b1': 12,
    'a0b2': 28.8,
  },
  len = [  2,  4,  6,  8,  10],
  prc = [170,190, 210, 230, 250],
  f=(_,l=Math.round(_))=>D.textContent=l?prc[len.findIndex(_=>_>l)]+'円':'';

A.addEventListener('change',_=>f(vals[B.value+C.value]));

</script>

少しでも短く

//A.addEventListener('change',_=>f(vals[B.value+C.value])||f(vals[C.value+B.value]));
A.addEventListener('change',(_,b=B.value,c=C.value)=>f(vals[b+c])||f(vals[c+b]));

今更ながらフェードアウトで画像を切り替える

本来ならスクリプトを使わないでできる














<!DOCTYPE html>
<meta charset="UTF-8">
<title></title>

<style>
.fade_out_change {
  position: relative;
}
.fade_out_change > *  {
  position: absolute;
  left: 0;
  top: 0;
}

.chgTypeA {
  height: 200px;
}
.chgTypeB {
  height: 100px;
}

.chgTypeA > *:last-of-type {
  animation: 3s fadeOut 4s forwards;
}
.chgTypeB > *:last-of-type {
  animation-name: fadeOut;
  animation-duration: 1s; /*アニメーション時間*/
  animation-delay: 3s; /*開始まで遅らせる時間*/
  animation-timing-function: ease; /* ease, ease-in, ease-out, linear, steps, cubic-bezier */
  animation-fill-mode: none; /*none, forwards, backwards, both*/
  animation-iteration-count: 1; /* infinite */
  animation-direction: normal; /*normal, reverse, alternate, alternate-reverse*/

}

@keyframes fadeOut { from { opacity: 1; } to { opacity: 0; }}

</style>


<body>
<div id="A" class="fade_out_change chgTypeA">
  <img src="https://picsum.photos/600/200?random=1">
  <img src="https://picsum.photos/600/200?random=2">
  <img src="https://picsum.photos/600/200?random=3">
  <img src="https://picsum.photos/600/200?random=4">
</div>

<div id="B" class="fade_out_change chgTypeB">
  <img src="https://picsum.photos/400/100?random=5">
  <img src="https://picsum.photos/400/100?random=6">
  <img src="https://picsum.photos/400/100?random=7">
  <img src="https://picsum.photos/400/100?random=8">
</div>

<script>

const moveFirst = e=> e.parentNode.prepend (e);

A.addEventListener('animationend', event => moveFirst (event.target));
B.addEventListener('animationend', event => moveFirst (event.target));

</script>

ショートコードの備忘録

//配列をテーブルにする
const ary2tbody=(a,b=document.createElement('tbody'))=>a.reduce((b,a)=>(a.reduce((c,d)=>(c.insertCell().append(d),c),b.insertRow()),b),b);
/*
function ary2tbody (ary, tb = document.createElement('tbody')) {
  return ary.reduce((tb, a)=>(a.reduce((tr, str)=>(tr.insertCell().textContent = str, tr),tb.insertRow()), tb), tb);
}
*/


//配列を SELECT 要素の OPTION 要素に置き換える
const replaceSelect =(select, ary = [ ]) => select.replaceChildren (...ary.map(a=>new Option(...a)));


//配列の転置(XとYを交換)
const transpose=a=>a[0].map((_,i)=>a.map(b=>b[i]));


//配列の回転(時計回り)
//const rotateRight a=> a[0].map((_,i)=>a.map(b=>b[i]).reverse());
const rotateRight = a=> a[0].map((_,i)=>a.reduceRight((b,c)=>[...b,c[i]],[]));


//配列の回転(180度)
//const inversion =a=> [...a].reverse().map(b=>[...b].reverse());
//const inversion =a=> a.slice().reverse().map(b=>b.slice().reverse());
//const inversion =a=> a.reduceRight((b,c)=>[...b,[...c].reverse()],[]);
const inversion = a=>a.reduceRight((b,c)=>[...b,c.reduceRight((d,e)=>[...d,e],[])],[]);


//配列の回転(反時計回り)
const rotateLeft = a=> a[0].reduceRight((b,_,i)=>[...b,a.map(c=>c[i])],[]);


//順列を配列にして返す 
const  permutations=((f=(A,B=A.length,C=[])=>--B?A.reduce((a,b,c,[...d],_=d.splice(c,1))=>[...a,...f(d,B,[...C,b])],[]):A.map(a=>[...C,a]))=>f)();
console.log (permutations ([1,2,3,4],2));

//組み合わせを配列にして返す
const combinatorics =((f=(a,c=1,r=[])=>c?a.reduce((r,d,e,_,g=f(a.slice(e+1),c-1))=>r.concat(g?g.map(z=>[d].concat(z)):[[d]]),r):0)=>f)();
console.log (combinatorics([1,2,3,4],2));


//
class P2{
  constructor(x=0,y=0){this.x=x;this.y=y}
  get clone(){return new this.constructor(this.x, this.y)}//複写
  get toArray(){return[this.x,this.y]}//単純配列化
  add({x=0,y=0},{x:X,y:Y}=this){this.x=X+x;this.y=Y+y;return this}//加算
  sub({x=0,y=0},{x:X,y:Y}=this){this.x=X-X;this.y=Y-y;return this}//減算
  mul({x=0,y=0},{x:X,y:Y}=this){this.x=X*x;this.y=Y*y;return this}//乗算
  div({x=0,y=0},{x:X,y:Y}=this){this.x=X/x;this.y=Y/y;return this}//除算
  sMul(n=0,{x:X,y:Y}=this){this.x=X*n;this.y=Y*n;return this}//スカラー倍
}

class V2 extends P2{
  constructor(...p){super(...p)}
  get length(){return(this.x**2+this.y**2)**.5}//長さ
  get negate(){this.x=-this.x;this.y=-this.y;return this}//逆向き
  get normalize(){let L=1/(this.length||1);this.x*=L;this.y*=L;return this}//単位化
  get angle(){return Math.atan2(-this.y,-this.x)+Math.PI}//原点を基準にした角度
  dot({x=0,y=0},{x:X,y:Y}=this){return X*x+Y*y}//ドット積
  cross({x=0,y=0},{x:X,y:Y}=this){return X*y-Y*x}//クロス積
  rotation(a){let m=Math,s=m.sin(a),c=m.cos(a),{x,y}=this;this.x=x*c+y*s;this.y=x*-s+y*c;return this}//回転
}


class P3{
  constructor(x=0,y=0,z=0){this.x=x,this.y=y,this.z=z}
  get clone(){return new this.constructor(this.x,this.y,this.z)}//複写
  get toArray(){return[this.x,this.y,this.z]}//単純配列化
  add({x=0,y=0,z=0},{x:X,y:Y,z:Z}=this){this.x=X+x;this.y=Y+y;this.z=Z+z;return this}//加算
  sub({x=0,y=0,z=0},{x:X,y:Y,z:Z}=this){this.x=X-x;this.y=Y-y;this.z=Z-z;return this}//減算
  mul({x=0,y=0,z=0},{x:X,y:Y,z:Z}=this){this.x=X*x;this.y=Y*y;this.z=Z*z;return this}//乗算
  div({x=0,y=0,z=0},{x:X,y:Y,z:Z}=this){this.x=X/x;this.y=Y/y;this.z=Z/z;return this}//除算
  sMul(n=0,{x:X,y:Y,z:Z}=this){this.x=X*n;this.y=Y*n;this.z=Z*n;return this}//スカラー倍
  applyQuaternion({x=0,y=0,z=0,w=1},{x:X,y:Y,z:Z}=this){//クオータニオンの適用
    let a=w*X+y*Z-z*Y,b=w*Y+z*X-x*Z,c=w*Z+x*Y-y*X,d=-x*X-y*Y-z*Z;
    return this.x=a*w+d*-x+b*-z-c*-y,this.y=b*w+d*-y+c*-x-a*-z,this.z=c*w+d*-z+a*-y-b*-x,this;
  }
  rotation(a=0,b=0,c=0){//ロール、ピッチ、ヨウ
    let {sin:S,cos:C,PI}=Math,{x,y,z}=this,d=PI/180,e=a*d,f=b*d,g=c*d,h=S(e),i=S(f),j=S(g),k=C(e),l=C(f),m=C(g);
    this.x=x*k*l+y*(k*i*j-h*m)+z*(k*i*m+h*j);this.y=x*h*l+y*(h*i*j+k*m)+z*(h*i*m-k*j);this.z=x*-i+y*l*j+z*l*m;return this;
  }
}

class Vector extends P3{
  constructor(...p){super(...p)}
  get length(){return(this.x**2+this.y**2+this.z**2)**.5}//長さ
  get clone(){return new this.constructor(this.x,this.y,this.z)}//複写
  get negate(){return this.sMul(-1)}//逆向き
  get normalize(){return this.sMul(1/(this.length||1))}//単位化
  dot({x=0,y=0,z=0},{x:X,y:Y,z:Z}=this){return X*x+Y*y+Z*z}
	cross ({x=0,y=0,z=0},{x:X,y:Y,z:Z}=this){return this.x=y*Z-z*Y,this.y=z*X-x*Z,this.z=x*Y-y*X,this}
  rotation (a=0,b=0) {//ピッチ、ロール
    let {sin:S,cos:C,PI}=Math,{x,y,z}=this,d=PI/360,e=a*d,f=b*d,g=S(e),h=S(f),
    A=(new Vector(-z,0,(!z&&!x?1:x)).normalize),B=(new Vector(x,y,z).normalize);
    return this.applyQuaternion(new Quaternion(A.x*g,A.y*g,A.z*g,C(e))).applyQuaternion(new Quaternion(B.x*h,B.y*h,B.z*h,C(f)));
  }
}

//__________________________

class Quaternion{
  constructor (x=0,y=0,z=0,w=1){this.x=x;this.y=y;this.z=z;this.w=w}
  get clone(){return new this.constructor(this.x,this.y,this.z,this.w)}//複写
  get length(){return(this.x**2+this.y**2+this.z**2+this.w**2)**.5}
	get normalize(){let L=this.length;return (L?(L=1/L,this.x*=L,this.y*=L,this.z*=L,this.w*=L):this.x=this.y=this.z=0,this.w=1),this}
  dot({x=0,y=0,z=0,w=1},{x:X,y:Y,z:Z,w:W}=this){return X*x+Y*y+Z*z+W*w}
  mul({x=0,y=0,z=0,w=1},{x:X,y:Y,z:Z,w:W}=this){return this.x=X*w+W*x+Y*z-Z*y,this.y=Y*w+W*y+Z*x-X*z,this.z=Z*w+W*z+X*y-Y*x,this.w=W*w-X*x-Y*y-Z*z,this}
  add({x,y,z,w}){return this.x+=x,this.y+=y,this.z+=z,this.w+=w,this}
  setFromAxisAngle(a=0,_){this.w*=Math.cos(_=a/2);this.x*=(_=Math.sin(_));this.y*=_;this.z*=_;return this}
}

//______________________________________________________________

//template要素を雛型として配列をデータにする
function deriveFromTemplate (template, recs = [ ]) {
  let tp = ('TEMPLATE' === template.tagName)
           ? template.content.cloneNode (true)
           : template.cloneNode (true);
  let es = [...tp.querySelectorAll ('*[name]')];
  let rst = [ ];
  
  for (let rec of recs) {
    for (let e of es) {
      let name = e.name;
      if (rec.hasOwnProperty (name)) {
        let val = rec[name];
        e.value = (val != null) ? val: '';
      }
    }
    rst.push (tp.cloneNode (true));
  }
  return rst;
}


//template要素から前方の要素を削除する
function replaceBeforeFromTemplate (template, elements = [ ]) {
  if ('TEMPLATE' !== template.tagName)
    throw new Error ();
  
  for (let e; e = template.previousElementSibling; ) {
    if ('TEMPLATE' === e.tagName)
      break;
    e.remove ();
  }
  if (elements.length)
    template.before (...elements);
}


//template要素から後方の要素を削除する
function replaceAfterFromTemplate (template, elements = [ ]) {
  if ('TEMPLATE' !== template.tagName)
    throw new Error ();
  
  for (let e; e = template.nextElementSibling; ) {
    if ('TEMPLATE' === e.tagName)
      break;
    e.remove ();
  }
  if (elements.length)
    template.after (...elements);
}