JavaScriptを色々あれこれしようとするがひたすら失敗を繰り返している
| Revision | 23 (tree) |
|---|---|
| Time | 2016-11-21 11:58:00 |
| Author | |
Action Palette処理追加
Drag中の表示は未対応
| @@ -24,27 +24,32 @@ | ||
| 24 | 24 | display:block; |
| 25 | 25 | width:400px; height:300px; |
| 26 | 26 | border:1px solid black; |
| 27 | + margin: 10px; | |
| 27 | 28 | } |
| 28 | 29 | |
| 29 | - .palbg { | |
| 30 | + | |
| 31 | + | |
| 32 | + .palbg, | |
| 33 | + .paltxtcol, | |
| 34 | + .palact { | |
| 30 | 35 | display: inline-block; |
| 31 | 36 | width: 25px; height: 25px; |
| 32 | 37 | border: 2px solid blue; |
| 33 | - margin: 10px; | |
| 34 | 38 | } |
| 35 | - | |
| 39 | + .palbg { | |
| 40 | + border: 2px solid black; | |
| 41 | + } | |
| 36 | 42 | .paltxtcol { |
| 37 | - display: inline-block; | |
| 38 | - width: 25px; height: 25px; | |
| 39 | 43 | border: 2px solid brown; |
| 40 | - margin: 10px; | |
| 41 | 44 | text-align: center; |
| 42 | 45 | font-size: 100%; |
| 43 | 46 | } |
| 47 | + .palact { | |
| 48 | + border: 2px solid brown; | |
| 49 | + } | |
| 44 | 50 | |
| 45 | 51 | |
| 46 | 52 | |
| 47 | - | |
| 48 | 53 | .scaler { |
| 49 | 54 | border: 2px solid black; |
| 50 | 55 | border-radius: 50%; |
| @@ -13,7 +13,7 @@ | ||
| 13 | 13 | </div> |
| 14 | 14 | <!-- 固定ボタン (選択要素の削除, 保存, …) --> |
| 15 | 15 | <button type=button class="pal" data-objid="pal" data-palid="0" data-value="0xff000001">削除</button> |
| 16 | - <button type=button class="pal" data-objid="pal" data-palid="1" data-value="0x00ff0001">button2</button> | |
| 16 | + <button type=button class="pal" data-objid="pal" data-palid="1" data-value="0x00ff0001">Preset 1</button> | |
| 17 | 17 | <button type=button class="pal" data-objid="pal" data-palid="2" data-value="0x0000ff01">button3</button> |
| 18 | 18 | <button type=button class="pal" data-objid="pal" data-palid="3" data-value="0xffffff01">button4</button> |
| 19 | 19 | <button type=button class="pal" data-objid="pal" data-palid="4" data-value="0x00000000">button5</button> |
| @@ -60,6 +60,8 @@ | ||
| 60 | 60 | <div class="palbg palbg3" data-objid="palbg3" data-palid="3"></div> |
| 61 | 61 | <div class="palbg palbg4" data-objid="palbg4" data-palid="4"></div> |
| 62 | 62 | |
| 63 | + <br /> | |
| 64 | + | |
| 63 | 65 | <div class="paltxtcol paltxtcol0" data-objid="paltxtcol0" data-palid="0">あ</div> |
| 64 | 66 | <div class="paltxtcol paltxtcol1" data-objid="paltxtcol1" data-palid="1">あ</div> |
| 65 | 67 | <div class="paltxtcol paltxtcol2" data-objid="paltxtcol2" data-palid="2">あ</div> |
| @@ -66,6 +68,14 @@ | ||
| 66 | 68 | <div class="paltxtcol paltxtcol3" data-objid="paltxtcol3" data-palid="3">あ</div> |
| 67 | 69 | <div class="paltxtcol paltxtcol4" data-objid="paltxtcol4" data-palid="4">あ</div> |
| 68 | 70 | |
| 71 | + <br /> | |
| 72 | + | |
| 73 | + <div class="palact palact0" data-objid="palact0" data-palid="0"></div> | |
| 74 | + <div class="palact palact1" data-objid="palact1" data-palid="1"></div> | |
| 75 | + <div class="palact palact2" data-objid="palact2" data-palid="2"></div> | |
| 76 | + <div class="palact palact3" data-objid="palact3" data-palid="3"></div> | |
| 77 | + <div class="palact palact4" data-objid="palact4" data-palid="4"></div> | |
| 78 | + | |
| 69 | 79 | <script type="text/javascript" src="js/Common.js"></script> |
| 70 | 80 | <script type="text/javascript" src="js/Queue.js"></script> |
| 71 | 81 | <script type="text/javascript" src="js/CommandObj.js"></script> |
| @@ -15,6 +15,7 @@ | ||
| 15 | 15 | this.styleact = document.getElementById('stylepalact'); |
| 16 | 16 | |
| 17 | 17 | // palette要素を保持 |
| 18 | + // 背景設定パレット | |
| 18 | 19 | this.DOMpalbg = document.getElementsByClassName('palbg'); |
| 19 | 20 | for (let cnt = 0; cnt < this.DOMpalbg.length; cnt++) { |
| 20 | 21 | this.DOMpalbg[cnt].addEventListener('mousedown', this.onMouseDown.bind(this), false); |
| @@ -22,6 +23,7 @@ | ||
| 22 | 23 | this.DOMpalbg[cnt].addEventListener('dragover', this.onDragOver.bind(this), false); |
| 23 | 24 | this.DOMpalbg[cnt].addEventListener('drop', this.onDrop.bind(this), false); |
| 24 | 25 | } |
| 26 | + // テキストカラーパレット | |
| 25 | 27 | this.DOMpaltxtcol = document.getElementsByClassName('paltxtcol'); |
| 26 | 28 | for (let cnt = 0; cnt < this.DOMpaltxtcol.length; cnt++) { |
| 27 | 29 | this.DOMpaltxtcol[cnt].addEventListener('mousedown', this.onMouseDown.bind(this), false); |
| @@ -29,6 +31,14 @@ | ||
| 29 | 31 | this.DOMpaltxtcol[cnt].addEventListener('dragover', this.onDragOver.bind(this), false); |
| 30 | 32 | this.DOMpaltxtcol[cnt].addEventListener('drop', this.onDrop.bind(this), false); |
| 31 | 33 | } |
| 34 | + // アクションパレット | |
| 35 | + this.DOMpalact = document.getElementsByClassName('palact'); | |
| 36 | + for (let cnt = 0; cnt < this.DOMpalact.length; cnt++) { | |
| 37 | + this.DOMpalact[cnt].addEventListener('mousedown', this.onMouseDown.bind(this), false); | |
| 38 | + this.DOMpalact[cnt].addEventListener('dragstart', this.onDragStart.bind(this), false); | |
| 39 | + this.DOMpalact[cnt].addEventListener('dragover', this.onDragOver.bind(this), false); | |
| 40 | + this.DOMpalact[cnt].addEventListener('drop', this.onDrop.bind(this), false); | |
| 41 | + } | |
| 32 | 42 | } |
| 33 | 43 | |
| 34 | 44 | // 操作関数 ---------------------------- |
| @@ -55,21 +65,29 @@ | ||
| 55 | 65 | id, // txtcol palette要素番号 |
| 56 | 66 | file // 画像を指しているfile object |
| 57 | 67 | ) { |
| 58 | -let cssstr1 = '\ | |
| 59 | -.paltxtcol' + id + ' {\n\ | |
| 60 | -background: url('; | |
| 61 | - | |
| 62 | -let cssstr2 = '\ | |
| 63 | -);\n\ | |
| 64 | -background-size: contain;\n\ | |
| 65 | -color: #fff;\n\ | |
| 66 | --webkit-text-fill-color: transparent;\n\ | |
| 67 | --webkit-background-clip: text;\n\ | |
| 68 | -}'; | |
| 69 | - | |
| 68 | + let cssstr1 = '.paltxtcol' + id + ' { background: url('; | |
| 69 | + let cssstr2 = '); background-size: contain; color: #fff; -webkit-text-fill-color: transparent; -webkit-background-clip: text; }'; | |
| 70 | 70 | setImageFileToCSS(this.styletxtcol, id, cssstr1, cssstr2, file); |
| 71 | - } | |
| 71 | + }; | |
| 72 | + definepalactText( | |
| 73 | + id, // act palette要素番号 | |
| 74 | + file // Textを指しているfile object | |
| 75 | + ) { | |
| 76 | + let cssstr1 = '.palact' + id + ' { '; | |
| 77 | + let cssstr2 = '}'; | |
| 72 | 78 | |
| 79 | + // drop fileの読み込み | |
| 80 | + let reader = new FileReader(); | |
| 81 | + // Text fileを読み込み | |
| 82 | + reader.readAsText(file); | |
| 83 | + reader.onload = function (ele, num, cssstr1, cssstr2, evt) { | |
| 84 | + let blob = evt.target.result; | |
| 85 | + // blobの適用 | |
| 86 | + let csstext = String(cssstr1) + blob + String(cssstr2); | |
| 87 | + ele.sheet.deleteRule(num); | |
| 88 | + ele.sheet.insertRule(csstext, num); | |
| 89 | + }.bind(this, this.styleact, id, cssstr1, cssstr2); | |
| 90 | + }; | |
| 73 | 91 | |
| 74 | 92 | |
| 75 | 93 |
| @@ -79,6 +97,9 @@ | ||
| 79 | 97 | // Drag&Drop event : Application外からのfileのやり取り |
| 80 | 98 | // Mouse event : Elementに対する操作 |
| 81 | 99 | |
| 100 | + // Drag&Drop event | |
| 101 | + // Applicationの外からFile Dropされたときに | |
| 102 | + // File内容情報を読み込み、CSSに反映させる | |
| 82 | 103 | onDragStart(evt) { |
| 83 | 104 | evt.preventDefault(); |
| 84 | 105 | } |
| @@ -93,22 +114,26 @@ | ||
| 93 | 114 | evt.preventDefault(); // 要素既定のdefault動作を止める |
| 94 | 115 | |
| 95 | 116 | |
| 96 | - let palid = 0; | |
| 97 | 117 | // drop対象 elementを特定 |
| 98 | 118 | let objid = evt.target.dataset.objid; |
| 119 | + let palid = parseInt(evt.target.dataset.palid);; | |
| 120 | + | |
| 121 | + // Dropされたfileを読み込み、CSSに反映 | |
| 99 | 122 | if (null != objid.match(/^palbg/)) { |
| 100 | - palid = parseInt(evt.target.dataset.palid); | |
| 101 | - getDropFile(evt, null, this.definepalbg.bind(this, palid)); | |
| 123 | + getDropFile(evt, null, this.definepalbg.bind(this, palid), null); | |
| 102 | 124 | } |
| 103 | 125 | else if (null != objid.match(/^paltxtcol/)) { |
| 104 | - palid = parseInt(evt.target.dataset.palid); | |
| 105 | - getDropFile(evt, this.definepaltxtcolText.bind(this, palid), this.definepaltxtcolImage.bind(this, palid)); | |
| 126 | + getDropFile(evt, this.definepaltxtcolText.bind(this, palid), this.definepaltxtcolImage.bind(this, palid), null); | |
| 106 | 127 | } |
| 128 | + else if (null != objid.match(/^palact/)) { | |
| 129 | + getDropFile(evt, this.definepalactText.bind(this, palid), null, null); | |
| 130 | + } | |
| 107 | 131 | |
| 108 | 132 | } |
| 109 | 133 | |
| 110 | 134 | |
| 111 | - | |
| 135 | + // Mouse event | |
| 136 | + // 自elementをDragし、Drop時にTarget elementに自分のCSS classを適用する | |
| 112 | 137 | onMouseDown(evt) { |
| 113 | 138 | this.draggingDOM = evt.target; |
| 114 | 139 |
| @@ -34,7 +34,7 @@ | ||
| 34 | 34 | <build:Metadata> |
| 35 | 35 | <build:Item Name="VisualStudio" Version="14.0" /> |
| 36 | 36 | <build:Item Name="VisualStudioEdition" Value="Microsoft Visual Studio Community 2015" /> |
| 37 | - <build:Item Name="OperatingSystem" Version="10.0.14959.1000 (rs_prerelease.161026-1700)" /> | |
| 37 | + <build:Item Name="OperatingSystem" Version="10.0.14971.1000 (rs_prerelease.161111-1700)" /> | |
| 38 | 38 | <build:Item Name="Microsoft.Build.AppxPackage.dll" Version="14.0.25431.1" /> |
| 39 | 39 | <build:Item Name="ProjectGUID" Value="284de86f-bd39-49ec-b61a-983818f9b461" /> |
| 40 | 40 | <build:Item Name="OptimizingToolset" Value="None" /> |
| @@ -34,7 +34,7 @@ | ||
| 34 | 34 | <build:Metadata> |
| 35 | 35 | <build:Item Name="VisualStudio" Version="14.0" /> |
| 36 | 36 | <build:Item Name="VisualStudioEdition" Value="Microsoft Visual Studio Community 2015" /> |
| 37 | - <build:Item Name="OperatingSystem" Version="10.0.14959.1000 (rs_prerelease.161026-1700)" /> | |
| 37 | + <build:Item Name="OperatingSystem" Version="10.0.14971.1000 (rs_prerelease.161111-1700)" /> | |
| 38 | 38 | <build:Item Name="Microsoft.Build.AppxPackage.dll" Version="14.0.25431.1" /> |
| 39 | 39 | <build:Item Name="ProjectGUID" Value="284de86f-bd39-49ec-b61a-983818f9b461" /> |
| 40 | 40 | <build:Item Name="OptimizingToolset" Value="None" /> |
| @@ -3,3 +3,88 @@ | ||
| 3 | 3 | タッチ操作: 操作; |
| 4 | 4 | */ |
| 5 | 5 | } |
| 6 | + *, *:before, *:after { | |
| 7 | + -webkit-box-sizing: border-box; | |
| 8 | + -moz-box-sizing: border-box; | |
| 9 | + -o-box-sizing: border-box; | |
| 10 | + -ms-box-sizing: border-box; | |
| 11 | + box-sizing: border-box; | |
| 12 | + -webkit-user-select: none; | |
| 13 | + -khtml-user-select: none; | |
| 14 | + -moz-user-select: none; | |
| 15 | + user-select: none; | |
| 16 | + } | |
| 17 | +/* | |
| 18 | + [data-objid] { | |
| 19 | + transition: transform 2s linear 0s; | |
| 20 | + } | |
| 21 | +*/ | |
| 22 | + | |
| 23 | + #DispField{ | |
| 24 | + display:block; | |
| 25 | + width:400px; height:300px; | |
| 26 | + border:1px solid black; | |
| 27 | + margin: 10px; | |
| 28 | + } | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + .palbg, | |
| 33 | + .paltxtcol, | |
| 34 | + .palact { | |
| 35 | + display: inline-block; | |
| 36 | + width: 25px; height: 25px; | |
| 37 | + border: 2px solid blue; | |
| 38 | + margin: 2px; | |
| 39 | + } | |
| 40 | + .palbg { | |
| 41 | + border: 2px solid black; | |
| 42 | + } | |
| 43 | + .paltxtcol { | |
| 44 | + border: 2px solid brown; | |
| 45 | + text-align: center; | |
| 46 | + font-size: 100%; | |
| 47 | + } | |
| 48 | + .palact { | |
| 49 | + border: 2px solid brown; | |
| 50 | + } | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + .scaler { | |
| 55 | + border: 2px solid black; | |
| 56 | + border-radius: 50%; | |
| 57 | + background-color: orange; | |
| 58 | + } | |
| 59 | + .roller { | |
| 60 | + border: 2px solid black; | |
| 61 | + border-radius: 50%; | |
| 62 | + background-color: green; | |
| 63 | + } | |
| 64 | + | |
| 65 | + .focusimage { | |
| 66 | + background-image: linear-gradient( | |
| 67 | + -45deg, | |
| 68 | + rgba(255,255,255,0.5), | |
| 69 | + rgba(255,255,255,0.5) 25%, | |
| 70 | + rgba(0,0,0,0.5) 26%, | |
| 71 | + rgba(0,0,0,0.5) 50%, | |
| 72 | + rgba(255,255,255,0.5) 51%, | |
| 73 | + rgba(255,255,255,0.5) 75%, | |
| 74 | + rgba(0,0,0,0.5) 76%, | |
| 75 | + rgba(0,0,0,0.5) 100% | |
| 76 | + ); | |
| 77 | + background-size: 8px 8px; | |
| 78 | + } | |
| 79 | + .focusleft { animation: animForcus1 3s linear infinite; } | |
| 80 | + .focusright { animation: animForcus2 3s linear infinite; } | |
| 81 | + .focustop { animation: animForcus2 3s linear infinite; } | |
| 82 | + .focusbottom { animation: animForcus1 3s linear infinite; } | |
| 83 | + @keyframes animForcus1 { | |
| 84 | + 0% { background-position:0% 0%} | |
| 85 | + 100% {background-position:100% 100%} | |
| 86 | + } | |
| 87 | + @keyframes animForcus2 { | |
| 88 | + 0% { background-position:100% 100%} | |
| 89 | + 100% {background-position:0% 0%} | |
| 90 | + } |
| @@ -1,13 +1,107 @@ | ||
| 1 | 1 | <!DOCTYPE html> |
| 2 | -<html> | |
| 2 | +<html lang="ja"> | |
| 3 | 3 | <head> |
| 4 | 4 | <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> |
| 5 | 5 | <meta charset="utf-8" /> |
| 6 | + <meta name="viewport" content="user-scalable=yes, initial-scale=1, maximum-scale=10, minimum-scale=0.1, width=device-width, height=device-height"> | |
| 6 | 7 | <title>HTMLDrawApp</title> |
| 7 | 8 | <link href="css/default.css" rel="stylesheet" /> |
| 8 | 9 | </head> |
| 9 | 10 | <body> |
| 10 | - <div>コンテンツをここに挿入。</div> | |
| 11 | - <script src="js/main.js"></script> | |
| 11 | + <!-- 編集領域 --> | |
| 12 | + <div id="DispField" data-objid="DisplayField" data-focus="true"> | |
| 13 | + </div> | |
| 14 | + <!-- 固定ボタン (選択要素の削除, 保存, …) --> | |
| 15 | + <button type=button class="pal" data-objid="pal" data-palid="0" data-value="0xff000001">削除</button> | |
| 16 | + <button type=button class="pal" data-objid="pal" data-palid="1" data-value="0x00ff0001">設定保存</button> | |
| 17 | + <button type=button class="pal" data-objid="pal" data-palid="2" data-value="0x0000ff01">設定Drop</button> | |
| 18 | + <button type=button class="pal" data-objid="pal" data-palid="3" data-value="0xffffff01">アニメ停止</button> | |
| 19 | + <button type=button class="pal" data-objid="pal" data-palid="4" data-value="0x00000000">button5</button> | |
| 20 | + <a href="#" id="save" download="savefilename.txt">画像保存</a><br /> | |
| 21 | + | |
| 22 | + <!-- Palette --> | |
| 23 | + <style id="stylepalbg"> | |
| 24 | + .palbg0 { background-image: url(dummy.png); } | |
| 25 | + .palbg1 { background-image: url(dummy.png); } | |
| 26 | + .palbg2 { background-image: url(dummy.png); } | |
| 27 | + .palbg3 { background-image: url(dummy.png); } | |
| 28 | + .palbg4 { background-image: url(dummy.png); } | |
| 29 | + </style> | |
| 30 | + <style id="stylepaltxtcol"> | |
| 31 | + .paltxtcol0 { color: black; } | |
| 32 | + .paltxtcol1 { color: red; } | |
| 33 | + .paltxtcol2 { color: blue; } | |
| 34 | + .paltxtcol3 { color: green; } | |
| 35 | + .paltxtcol4 { color: brown; } | |
| 36 | + </style> | |
| 37 | + <style id="stylepalact"> | |
| 38 | + /* animation指定,keyframe指定, … と交互に設定されている想定 */ | |
| 39 | + /* palette css と keyframe は必ず1対1.例えkeyframeが使いまわせたとしても。 */ | |
| 40 | + .palact0 { animation: animeY1 0.5s ease-in 0.3s 1 normal; } | |
| 41 | + @keyframes animeY1 { | |
| 42 | + 0% {transform: translateY(-60px) translateX(-30px);} | |
| 43 | + 10% {transform: translateY(20px) translateX(30px);} | |
| 44 | + 20% {transform: translateY(-40px) translateX(-20px);} | |
| 45 | + 30% {transform: translateY(50px) translateX(-10px);} | |
| 46 | + 40% {transform: translateY(-40px) translateX(20px);} | |
| 47 | + 50% {transform: translateY(30px) translateX(-15px);} | |
| 48 | + 60% {transform: translateY(-25px) translateX(0px);} | |
| 49 | + 70% {transform: translateY(15px) translateX(-15px);} | |
| 50 | + 80% {transform: translateY(-10px) translateX(10px);} | |
| 51 | + 90% {transform: translateY(0px) translateX(-5px);} | |
| 52 | + 100% {transform: translateY(0px) translateX(0px);} | |
| 53 | + } | |
| 54 | + | |
| 55 | + .palact1 { animation: animeact1 2s ease-in 0.3s 1 normal; } | |
| 56 | + @keyframes animeact1 { to {color:black;} } | |
| 57 | + | |
| 58 | + .palact2 { animation: animeact2 2s ease-in 0.3s 1 normal; } | |
| 59 | + @keyframes animeact2 { to {color:black;} } | |
| 60 | + | |
| 61 | + .palact3 { animation: animeact3 2s ease-in 0.3s 1 normal; } | |
| 62 | + @keyframes animeact3 { to {color:black;} } | |
| 63 | + | |
| 64 | + .palact4 { animation: animeact4 2s ease-in 0.3s 1 normal; } | |
| 65 | + @keyframes animeact4 { to {color:black;} } | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + </style> | |
| 74 | + <div class="palbg palbg0" data-objid="palbg0" data-palid="0"></div> | |
| 75 | + <div class="palbg palbg1" data-objid="palbg1" data-palid="1"></div> | |
| 76 | + <div class="palbg palbg2" data-objid="palbg2" data-palid="2"></div> | |
| 77 | + <div class="palbg palbg3" data-objid="palbg3" data-palid="3"></div> | |
| 78 | + <div class="palbg palbg4" data-objid="palbg4" data-palid="4"></div> | |
| 79 | + | |
| 80 | + <br /> | |
| 81 | + | |
| 82 | + <div class="paltxtcol paltxtcol0" data-objid="paltxtcol0" data-palid="0">あ</div> | |
| 83 | + <div class="paltxtcol paltxtcol1" data-objid="paltxtcol1" data-palid="1">あ</div> | |
| 84 | + <div class="paltxtcol paltxtcol2" data-objid="paltxtcol2" data-palid="2">あ</div> | |
| 85 | + <div class="paltxtcol paltxtcol3" data-objid="paltxtcol3" data-palid="3">あ</div> | |
| 86 | + <div class="paltxtcol paltxtcol4" data-objid="paltxtcol4" data-palid="4">あ</div> | |
| 87 | + | |
| 88 | + <br /> | |
| 89 | + | |
| 90 | + <div class="palact palact0" data-objid="palact0" data-palid="0"></div> | |
| 91 | + <div class="palact palact1" data-objid="palact1" data-palid="1"></div> | |
| 92 | + <div class="palact palact2" data-objid="palact2" data-palid="2"></div> | |
| 93 | + <div class="palact palact3" data-objid="palact3" data-palid="3"></div> | |
| 94 | + <div class="palact palact4" data-objid="palact4" data-palid="4"></div> | |
| 95 | + | |
| 96 | + <script type="text/javascript" src="js/Common.js"></script> | |
| 97 | + <script type="text/javascript" src="js/Queue.js"></script> | |
| 98 | + <script type="text/javascript" src="js/CommandObj.js"></script> | |
| 99 | + <script type="text/javascript" src="js/UI_parts.js"></script> | |
| 100 | + <script type="text/javascript" src="js/palette.js"></script> | |
| 101 | + <script type="text/javascript" src="js/DispObj.js"></script> | |
| 102 | + <script type="text/javascript" src="js/ObjIDMgr.js"></script> | |
| 103 | + <script type="text/javascript" src="js/ThreadMessage.js"></script> | |
| 104 | + <script type="text/javascript" src="js/DisplayField.js"></script> | |
| 105 | + <script type="text/javascript" src="js/main.js"></script> | |
| 12 | 106 | </body> |
| 13 | 107 | </html> |
| @@ -0,0 +1,143 @@ | ||
| 1 | +// Worker thread | |
| 2 | +// Command処理を実行する | |
| 3 | +// ・Queuing command. | |
| 4 | +// ・To process the command sequentially. | |
| 5 | +// ・And stack to undo list. | |
| 6 | + | |
| 7 | +// cmdAddress宛先に対応するcmd送信処理関数 | |
| 8 | +// DispObj GroupObj CommandMgr ObjIDMgr DispField Dialog InputMgr SaveLoadMgr | |
| 9 | +const eachDestOfFuncTbl = [cmdSendUiThread, cmdSendUiThread, cmdSendCommandMgr, cmdSendUiThread, cmdSendUiThread, cmdSendUiThread, cmdSendUiThread, cmdSendSaveLoadMgr]; | |
| 10 | + | |
| 11 | +// UI threadにcmd情報を送信 | |
| 12 | +// (InstanceがUI threadにあるobjに対して使用する) | |
| 13 | +function cmdSendUiThread(cmdObj) { | |
| 14 | + // 宛先の実体がUI thread側にあるものは、一律postMessageでcommandを送り付ける | |
| 15 | + self.postToUI.post(cmdObj); | |
| 16 | +}; | |
| 17 | +function cmdSendCommandMgr(cmdObj) { | |
| 18 | +}; | |
| 19 | +function cmdSendSaveLoadMgr(cmdObj) { | |
| 20 | +}; | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | +// commandごとに undo commandの作成処理関数を登録 | |
| 25 | +const cmdUndoFunc = []; | |
| 26 | +cmdUndoFunc[cmdCmd.createTextbox] = undoCreateTextbox; | |
| 27 | +cmdUndoFunc[cmdCmd.createImagebox] = undoCreateImagebox; | |
| 28 | +cmdUndoFunc[cmdCmd.movebox] = undoMovebox; | |
| 29 | +cmdUndoFunc[cmdCmd.scalebox] = undoScalebox; | |
| 30 | +cmdUndoFunc[cmdCmd.rollbox] = undoRollbox; | |
| 31 | +cmdUndoFunc[cmdCmd.deletebox] = undoDeletebox; | |
| 32 | + | |
| 33 | + | |
| 34 | +// Undoコマンド作成関数 | |
| 35 | +function undoCreateTextbox(cmd) { | |
| 36 | + debuglog("undoCreateTextbox"); | |
| 37 | + var undoCmd = new CCommandObj(); | |
| 38 | + undoCmd.createCommand(cmdType.request, cmd.from, cmd.to, cmdCmd.deletebox, cmd.param1, cmd.param2, cmd.param3, cmd.param4, cmd.msgID); | |
| 39 | + return undoCmd; | |
| 40 | +}; | |
| 41 | +function undoCreateImagebox(cmd) { | |
| 42 | +}; | |
| 43 | +function undoMovebox(cmd) { | |
| 44 | + debuglog("undoMovebox"); | |
| 45 | + var undoCmd = new CCommandObj(); | |
| 46 | + // dummy | |
| 47 | + undoCmd.createCommand(cmdType.request, cmd.from, cmd.to, cmdCmd.deletebox, cmd.param1, cmd.param2, cmd.param3, cmd.param4, cmd.msgID); | |
| 48 | + return undoCmd; | |
| 49 | +}; | |
| 50 | +function undoScalebox(cmd) { | |
| 51 | + debuglog("undoScalebox"); | |
| 52 | + var undoCmd = new CCommandObj(); | |
| 53 | + // dummy | |
| 54 | + undoCmd.createCommand(cmdType.request, cmd.from, cmd.to, cmdCmd.deletebox, cmd.param1, cmd.param2, cmd.param3, cmd.param4, cmd.msgID); | |
| 55 | + return undoCmd; | |
| 56 | +}; | |
| 57 | +function undoRollbox(cmd) { | |
| 58 | + debuglog("undoRollbox"); | |
| 59 | + var undoCmd = new CCommandObj(); | |
| 60 | + // dummy | |
| 61 | + undoCmd.createCommand(cmdType.request, cmd.from, cmd.to, cmdCmd.deletebox, cmd.param1, cmd.param2, cmd.param3, cmd.param4, cmd.msgID); | |
| 62 | + return undoCmd; | |
| 63 | +}; | |
| 64 | +function undoDeletebox(cmd) { | |
| 65 | +}; | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | +class CCommandMgr { | |
| 72 | + constructor(){ | |
| 73 | + this.cmdProcessTbl = {}; | |
| 74 | + this.cmdQue = new Queue(); | |
| 75 | + this.undoQue = new Queue(); | |
| 76 | + } | |
| 77 | + | |
| 78 | + debuglog (str) { | |
| 79 | + debuglog("【CommandMgr】 " + str); | |
| 80 | + } | |
| 81 | + | |
| 82 | + | |
| 83 | + // コマンド要求してもらうためのI/F関数 | |
| 84 | + requestCommand (cmdObj) { | |
| 85 | + this.debuglog( "requestCommand()" ); | |
| 86 | + | |
| 87 | + // 処理予約queueにコマンド インスタンスを登録 | |
| 88 | + this.cmdQue.enqueue( cmdObj ); | |
| 89 | + | |
| 90 | + return true; | |
| 91 | + } | |
| 92 | + | |
| 93 | + // cmdQueにある Commandを処理 | |
| 94 | + processCommands () { | |
| 95 | + // Queに cmdが溜まっている場合はここで処理 | |
| 96 | + // その間 UI threadから要求があった場合は threadの Msg queに溜まる | |
| 97 | + // (Receiveできないため) | |
| 98 | + while( 0 < this.cmdQue.size() ){ | |
| 99 | + this.processSingleCommand(); | |
| 100 | + } | |
| 101 | + } | |
| 102 | + // cmdQueに積まれた commandを1回処理 | |
| 103 | + // (worker thread の onmessage event handlerから呼び出される) | |
| 104 | + processSingleCommand () { | |
| 105 | + if( this.cmdQue.size() < 1 ){ | |
| 106 | + this.debugLog("processCommand() cmdQue is empty!"); | |
| 107 | + return; | |
| 108 | + } | |
| 109 | + | |
| 110 | + let cmdObj = null; | |
| 111 | + cmdObj = this.cmdQue.dequeue(); | |
| 112 | + this.debuglog( "processCommand() dequeue." ); | |
| 113 | + | |
| 114 | + // cmd内部処理実行 | |
| 115 | + this.cmdProcess( cmdObj ); | |
| 116 | + | |
| 117 | + // 応答cmd作成 | |
| 118 | + this.cmdCreateResponse( cmdObj ); | |
| 119 | + | |
| 120 | + // Undo情報作成 | |
| 121 | + this.createUndoInfo( cmdObj ); | |
| 122 | + | |
| 123 | + // cmdの宛先によりcmd送信処理分け | |
| 124 | + eachDestOfFuncTbl[ cmdObj.to ]( cmdObj ); | |
| 125 | + } | |
| 126 | + | |
| 127 | + | |
| 128 | + // 以降、private method ----------------- | |
| 129 | + cmdProcess ( cmd ) { | |
| 130 | + // 必要ならここでcmdごとに必要な計算を行う | |
| 131 | + } | |
| 132 | + | |
| 133 | + cmdCreateResponse ( cmd ) { | |
| 134 | + cmd.type = cmdType.result; | |
| 135 | + } | |
| 136 | + | |
| 137 | + // 処理するcmdから逆操作情報を作成し、Undo queに積む | |
| 138 | + createUndoInfo ( cmd ) { | |
| 139 | + this.debuglog("createUndoInfo"); | |
| 140 | + var undoCmd = cmdUndoFunc[ cmd.cmd ]( cmd ); | |
| 141 | + this.undoQue.enqueue( undoCmd ); | |
| 142 | + } | |
| 143 | +} // class CCommandMgr |
| @@ -0,0 +1,134 @@ | ||
| 1 | +const cmdType = { | |
| 2 | + request: 0, | |
| 3 | + response: 1, | |
| 4 | + result: 2, | |
| 5 | +}; | |
| 6 | +// commandの送信元,送信先オブジェクト | |
| 7 | +const cmdAddress = { | |
| 8 | + DispObj: 0, | |
| 9 | + GroupObj: 1, | |
| 10 | + CommandMgr: 2, | |
| 11 | + ObjIDMgr: 3, | |
| 12 | + DisplayField: 4, | |
| 13 | + Dialog: 5, | |
| 14 | + InputMgr: 6, | |
| 15 | + SaveLoadMgr: 7, | |
| 16 | + Focus: 8, | |
| 17 | +}; | |
| 18 | +const cmdCmd = { | |
| 19 | + createTextbox: 0, | |
| 20 | + createImagebox: 1, | |
| 21 | + movebox: 10, | |
| 22 | + scalebox: 11, | |
| 23 | + rollbox: 12, | |
| 24 | + deletebox: 100, | |
| 25 | +}; | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | +// Command本体定義 | |
| 30 | +// Command処理 および postMessageでのデータやり取りに使用 | |
| 31 | +// postMessageでは methodは送れないためここに methodは定義しないこと (必要ならtext変換してparamで渡し、evalで復元すること) | |
| 32 | +class CCommandObj { | |
| 33 | + // constructorでは真偽値を返せないので createCommand関数で作成する | |
| 34 | + constructor() { | |
| 35 | + const undoList = []; | |
| 36 | + } | |
| 37 | + | |
| 38 | + // toには最終到達 moduleを指定する。CommandMgrに要求するわけではないため | |
| 39 | + createCommand(type, from, to, cmd, param1, param2, param3, param4, msgID) { | |
| 40 | + this.type = type; // 'Request', 'Response', 'Result' | |
| 41 | + this.msgID = msgID; // msgID from postMessage (1~) 2つ以上のsequenceが同時に走るとき、処理が識別できれば(重複IDにならなければ)なんでもOK | |
| 42 | + this.from = from; | |
| 43 | + this.to = to; | |
| 44 | + this.cmd = cmd; | |
| 45 | + this.param1 = param1; | |
| 46 | + this.param2 = param2; | |
| 47 | + this.param3 = param3; | |
| 48 | + this.param4 = param4; | |
| 49 | + | |
| 50 | + // return checkCommandInfo(); | |
| 51 | + | |
| 52 | + debuglog("createCommand"); | |
| 53 | + debuglog(this); | |
| 54 | + return true; | |
| 55 | + } | |
| 56 | + | |
| 57 | + outputLog() { | |
| 58 | + debuglog("commandObj data ------------\ntype=" + this.type + ", msgID=" + this.msgID + ",\nfrom=" + this.from + ", to=" + this.to + ",\ncmd=" + this.cmd + ", praram1=" + this.param1 + ", param2=" + this.param2 + ", param3=" + this.param3 + ", param4=" + this.param4 + "\n---------------------------------"); | |
| 59 | + } | |
| 60 | + | |
| 61 | + // 設定されたコマンド情報の正当性チェック | |
| 62 | + // 先に内部変数に値を入れてから呼び出すこと | |
| 63 | + checkCommandInfo() { | |
| 64 | + let retFrom = checkInfoFrom(); | |
| 65 | + let retTo = checkInfoTo(); | |
| 66 | + let retCmd = checkInfoCmd(); | |
| 67 | + let retParam1 = checkInfoParam1(); | |
| 68 | + let retParam2 = checkInfoParam2(); | |
| 69 | + | |
| 70 | + if (true == retFrom | |
| 71 | + && true == retTo | |
| 72 | + && true == retCmd | |
| 73 | + && true == retParam1 | |
| 74 | + && true == retParam2) { | |
| 75 | + return true; | |
| 76 | + } | |
| 77 | + else { | |
| 78 | + return false; | |
| 79 | + } | |
| 80 | + } | |
| 81 | + checkInfoFrom() { | |
| 82 | + let ret = checkCmdFromTo(this.from); | |
| 83 | + if (false == ret) { | |
| 84 | + // 指定された Command発行元ID誤り | |
| 85 | + console.log("Cmd From ID Error."); | |
| 86 | + console.log(this); | |
| 87 | + return false; | |
| 88 | + } | |
| 89 | + return true; | |
| 90 | + } | |
| 91 | + checkInfoTo() { | |
| 92 | + let ret = checkCmdFromTo(this.to); | |
| 93 | + if (false == ret) { | |
| 94 | + // 指定された Command発行元ID誤り | |
| 95 | + console.log("Cmd To ID Error."); | |
| 96 | + console.log(this); | |
| 97 | + return false; | |
| 98 | + } | |
| 99 | + return true; | |
| 100 | + } | |
| 101 | + // 送信先,送信元確認用 | |
| 102 | + checkCmdFromTo(str) { | |
| 103 | + let fromto = getFromToStr(str); | |
| 104 | + if (null == fromto) { | |
| 105 | + console.log("cmdmgr error. fromto=" + str); | |
| 106 | + return false; | |
| 107 | + } | |
| 108 | + // 抽出文字が送信先ごと関数tblに要素として存在するか確認 | |
| 109 | + if (!fromto in eachDestOfFuncTbl) { | |
| 110 | + console.log("cmdmgr error. 要素がFuncTblにない fromto=" + str); | |
| 111 | + return false; | |
| 112 | + } | |
| 113 | + if (null == eachDestOfFuncTbl[fromto]) { | |
| 114 | + console.log("cmdmgr error. FuncTblにfunc未登録 fromto=" + str); | |
| 115 | + return false; | |
| 116 | + } | |
| 117 | + return true; | |
| 118 | + } | |
| 119 | + checkInfoCmd() { | |
| 120 | + return true; | |
| 121 | + } | |
| 122 | + checkInfoParam1() { | |
| 123 | + return true; | |
| 124 | + } | |
| 125 | + checkInfoParam2() { | |
| 126 | + return true; | |
| 127 | + } | |
| 128 | + getFromToStr(str) { | |
| 129 | + // 数字部分以外を抽出 | |
| 130 | + let index = /[^0-9]/.exec(str); | |
| 131 | + if (index.index < 1) return null; | |
| 132 | + return index; | |
| 133 | + } | |
| 134 | +} // class CCommandObj |
| @@ -0,0 +1,184 @@ | ||
| 1 | +// 汎用処理定義 | |
| 2 | +// この sourceは UI thread, Worker threadのそれぞれから呼び出される | |
| 3 | + | |
| 4 | +var DEBUGLOG = true; | |
| 5 | +debuglog = (true==DEBUGLOG)? debugLog : logQuiet; | |
| 6 | + | |
| 7 | +function debugLog(str) { | |
| 8 | + console.log(str); | |
| 9 | +}; | |
| 10 | +function logQuiet(str) { | |
| 11 | + // 処理なし | |
| 12 | +}; | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | +function rectData( left, top, right, bottom ) { | |
| 17 | + this.setData( left, top, right, bottom ); | |
| 18 | +}; | |
| 19 | +rectData.prototype.setData = function ( left, top, right, bottom ) { | |
| 20 | + this.left = parseInt(left); | |
| 21 | + this.top = parseInt(top); | |
| 22 | + this.right = parseInt(right); | |
| 23 | + this.bottom = parseInt(bottom); | |
| 24 | +}; | |
| 25 | +rectData.prototype.setLTWH = function (left, top, width, height) { | |
| 26 | + this.left = parseInt(left); | |
| 27 | + this.top = parseInt(top); | |
| 28 | + this.right = this.left + parseInt(width); | |
| 29 | + this.bottom = this.top + parseInt(height); | |
| 30 | +}; | |
| 31 | + | |
| 32 | + | |
| 33 | +function angle(x1, y1, x2, y2) { | |
| 34 | + let theta = Math.atan2(y2 - y1, x2 - x1); | |
| 35 | + if (theta < 0) { | |
| 36 | + theta = theta + 2 * Math.PI; | |
| 37 | + } | |
| 38 | + return (theta * 360 / (2 * Math.PI) - 90); // atan2は X軸基準での角度を出すため、画面表示系の Y軸基準に合わせるため 90を減算する | |
| 39 | +}; | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | +// Image fileを読み込み、その内容を対象CSSに設定 | |
| 44 | +// CSSには "'cssstr1' + fileBlob + 'cssstr2'" が設定される | |
| 45 | +function setImageFileToCSS( | |
| 46 | + ele, // CSS書き換え対象Element | |
| 47 | + num, // 書き換える CSS要素番号 (ele.sheet.cssRules[n] ← このnの値) | |
| 48 | + cssstr1, // CSS書き換え前半文字 | |
| 49 | + cssstr2, // CSS書き換え後半文字 | |
| 50 | + file // 画像ファイルを指している file object | |
| 51 | +) { | |
| 52 | + // drop fileの読み込み | |
| 53 | + let reader = new FileReader(); | |
| 54 | + // Image fileを読み込み (画像の幅・高さは取れない。Binary dataを memory上に読むだけなので) | |
| 55 | + reader.readAsDataURL(file); | |
| 56 | + reader.onload = setFileToCSS.bind(null, ele, num, cssstr1, cssstr2); | |
| 57 | +}; | |
| 58 | +// Text fileを読み込み、その内容を対象CSSに設定 | |
| 59 | +function setTextFileToCSS( | |
| 60 | + ele, // CSS書き換え対象Element | |
| 61 | + num, // 書き換える CSS要素番号 (ele.sheet.cssRules[n] ← このnの値) | |
| 62 | + cssstr1, // CSS書き換え前半文字 | |
| 63 | + cssstr2, // CSS書き換え後半文字 | |
| 64 | + file // Textファイルを指している file object | |
| 65 | +) { | |
| 66 | + // drop fileの読み込み | |
| 67 | + let reader = new FileReader(); | |
| 68 | + // Text fileを読み込み | |
| 69 | + reader.readAsText(file); | |
| 70 | + reader.onload = setFileToCSS.bind(null, ele, num, cssstr1, cssstr2); | |
| 71 | +}; | |
| 72 | +function setFileToCSS( ele, num, cssstr1, cssstr2, evt ){ | |
| 73 | + let blob = evt.target.result; | |
| 74 | + // blobの適用 | |
| 75 | + let csstext = String(cssstr1) + blob + String(cssstr2); | |
| 76 | + ele.sheet.deleteRule(num); | |
| 77 | + ele.sheet.insertRule(csstext, num); | |
| 78 | +}; | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | +// Drop fileから file objectを取得 (同期処理) | |
| 83 | +// 複数file 非対応。text or image がヒットした時点でcallbackを呼び出す | |
| 84 | +// callback書式(text,image): function(blob) | |
| 85 | +// callback書式(error): function() | |
| 86 | +function getDropFile(evt, callbacktext, callbackimage, callbackerror) { | |
| 87 | + let ret = false; | |
| 88 | + let files = evt.dataTransfer.files; | |
| 89 | + if (!files) { | |
| 90 | + console.error('dropされた file listが取得できない'); | |
| 91 | + if (null != callbackerror) callbackerror(); | |
| 92 | + return ret; | |
| 93 | + } | |
| 94 | + if (files.length <= 0) { | |
| 95 | + // Fileではないものを Dropされると発生 | |
| 96 | + console.error('drop fileの file list length == 0'); | |
| 97 | + if (null != callbackerror) callbackerror(); | |
| 98 | + return ret; | |
| 99 | + } | |
| 100 | + let dropfile = null; | |
| 101 | + for (var cnt = 0; cnt < files.length; cnt++) { | |
| 102 | + dropfile = files[cnt]; | |
| 103 | + if (null != dropfile.type.match(/image/)) { | |
| 104 | + | |
| 105 | + if (null != callbackimage) callbackimage(dropfile); | |
| 106 | + ret = true; | |
| 107 | + break; | |
| 108 | + } | |
| 109 | + else if (null != dropfile.type.match(/text\/plain/)) { | |
| 110 | + | |
| 111 | + if (null != callbacktext) callbacktext(dropfile); | |
| 112 | + ret = true; | |
| 113 | + break; | |
| 114 | + } | |
| 115 | + } | |
| 116 | + | |
| 117 | + if (false == ret) { | |
| 118 | + console.error('Drop file error. Drop するファイルは 画像かテキストにしてください\n' | |
| 119 | + + 'type=' + files[0].type.toString() + ', name=' + files[0].name.toString()); | |
| 120 | + if (null != callbackerror) callbackerror(); | |
| 121 | + } | |
| 122 | + return ret; | |
| 123 | +}; | |
| 124 | + | |
| 125 | + | |
| 126 | +// 保存処理 | |
| 127 | +class SaveFile { | |
| 128 | + constructor() { | |
| 129 | + this.filename = null; | |
| 130 | + this.callbackComplete = null; | |
| 131 | + this.callbackError = null; | |
| 132 | + } | |
| 133 | + | |
| 134 | + // ブラウザ上で実行している場合のファイル保存処理 | |
| 135 | + saveFileBrowser(filename, data) { | |
| 136 | + // Blobに変換して download | |
| 137 | + let blob = new Blob([data], { type: "text/plain" }); | |
| 138 | + let a = document.createElement('a'); | |
| 139 | + a.href = URL.createObjectURL(blob); | |
| 140 | + a.target = '_blank'; | |
| 141 | + a.download = filename; // Edgeは無効…… | |
| 142 | + a.click(); | |
| 143 | + | |
| 144 | + // download完了後に memory解放したほうがいい | |
| 145 | + // URL.revokeObjectURL(); | |
| 146 | + }; | |
| 147 | + | |
| 148 | + // アプリケーションとして実行している場合のファイル保存処理 | |
| 149 | + saveFileApp(filename, data, callbackComplete, callbackError) { | |
| 150 | + if (null != callbackComplete) this.callbackComplete = callbackComplete; | |
| 151 | + if (null != callbackError) this.callbackError = callbackError; | |
| 152 | + | |
| 153 | + // Unique filename作成 (ABC.txtが既にある → ABC(1).txt という file nameになる | |
| 154 | + // write, append指定はerrorになる。filepickerかmanifestで権限取得する必要があるかも | |
| 155 | + let fileoption = Windows.Storage.CreationCollisionOption.generateUniqueName; | |
| 156 | + Windows.Storage.DownloadsFolder.createFileAsync(filename, fileoption).done(this.saveFileAppOpenFile.bind(this, data), this.saveFileError.bind(this)); | |
| 157 | + }; | |
| 158 | + | |
| 159 | + // 以下、Private関数 ------------------- | |
| 160 | + | |
| 161 | + saveFileAppOpenFile(savedata, file) { // [!!caution] callback設定時に savedataを無理やりbind済み | |
| 162 | + // 実際に書き込まれた file nameを取得 | |
| 163 | + let name = file.name; | |
| 164 | + // file objectの pathを参照すると保存先 folderが大変なことになっているが | |
| 165 | + // 実際に保存される場所は Downloads/<ApplicationName>/ になる | |
| 166 | + | |
| 167 | + // この時点で fileは既に open済みになっている | |
| 168 | + // fileへデータ書き込み | |
| 169 | + Windows.Storage.FileIO.writeTextAsync(file, savedata); | |
| 170 | + // 書き込み完了チェック | |
| 171 | + Windows.Storage.CachedFileManager.completeUpdatesAsync(file).done(this.saveFileComplete.bind(this), this.saveFileError.bind(this)); | |
| 172 | + | |
| 173 | + }; | |
| 174 | + saveFileComplete() { | |
| 175 | + // 保存完了 | |
| 176 | + debuglog('ファイル保存完了'); | |
| 177 | + | |
| 178 | + if (null != this.callbackComplete) this.callbackComplete(); | |
| 179 | + }; | |
| 180 | + saveFileError(err) { | |
| 181 | + console.error('ファイル保存エラー\nerror=' + err.message + 'description=' + err.description); | |
| 182 | + if (null != this.callbackError) this.callbackError(err.message); | |
| 183 | + }; | |
| 184 | +} // class SaveFile |
| @@ -0,0 +1,279 @@ | ||
| 1 | + | |
| 2 | +class CDispObj { | |
| 3 | + constructor() { | |
| 4 | + this.ObjID = 0; | |
| 5 | + this.GroupID = 0; | |
| 6 | + this.type = 0; | |
| 7 | + this.x = 0.0; | |
| 8 | + this.y = 0.0; | |
| 9 | + this.width = 0.0; | |
| 10 | + this.height = 0.0; | |
| 11 | + this.opacity = 1.0; | |
| 12 | + this.degree = 0; | |
| 13 | + this.text = null; | |
| 14 | + this.transformStr = null; | |
| 15 | + this.DOMobject = null; | |
| 16 | + this.renderFunc = new Queue(); | |
| 17 | + | |
| 18 | + this.originalWidth = 0; | |
| 19 | + this.originalHeight = 0; | |
| 20 | + | |
| 21 | + this.dropinitsize = 100.0; | |
| 22 | + } | |
| 23 | + | |
| 24 | + debuglog(str) { | |
| 25 | + debuglog("【DispObj " + this.ObjID + "】" + str); | |
| 26 | + } | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + // ブラウザ上への描画 ------------------------- | |
| 31 | + | |
| 32 | + // コマンド要求実行後の描画共通処理 | |
| 33 | + // requestAnimationFrameのcallbackから呼び出される | |
| 34 | + render() { | |
| 35 | + while (0 < this.renderFunc.size()) { | |
| 36 | + this.debuglog("render() renderFunc size=" + this.renderFunc.size()); | |
| 37 | + let renderFunction = this.renderFunc.dequeue(); | |
| 38 | + renderFunction(); | |
| 39 | + } | |
| 40 | + } | |
| 41 | + | |
| 42 | + // コマンド実行処理 ----------------------------- | |
| 43 | + | |
| 44 | + // DIV Box作成 | |
| 45 | + // 作成 ObjIDMgrへの登録も行う | |
| 46 | + create(type, rect, opt1) { | |
| 47 | + this.debuglog("DispObj.Create() called. type=" + type + ", left=" + rect.left + ", top=" + rect.top + ", right=" + rect.right + ", bottom=" + rect.bottom); | |
| 48 | + let ret = this.checkType(type); | |
| 49 | + if (false == ret) { | |
| 50 | + console.error("【CDispObj XX】 create() object type error. type = " + type); | |
| 51 | + return false; | |
| 52 | + } | |
| 53 | + this.type = type; | |
| 54 | + | |
| 55 | + // ObjIDMgrへ 自身の登録 | |
| 56 | + this.ObjID = window.ObjIDMgr.registerDispObj(this); | |
| 57 | + if (this.ObjID < 0) { | |
| 58 | + console.error("【CDispObj XX】 create() ObjID error. ObjID = " + this.ObjID); | |
| 59 | + return false; | |
| 60 | + } | |
| 61 | + // サイズ設定 | |
| 62 | + this.x = rect.left; | |
| 63 | + this.y = rect.top; | |
| 64 | + this.width = rect.right - rect.left; | |
| 65 | + this.height = rect.bottom - rect.top; | |
| 66 | + this.originalWidth = this.width; | |
| 67 | + this.originalHeight = this.height; | |
| 68 | + | |
| 69 | + // 画面に影響しない範囲で作成できるところまで Dom objectを作成する | |
| 70 | + let elType = (null != type.match(/imagebox/)) ? 'img' : 'div'; | |
| 71 | + this.DOMobject = document.createElement(elType); | |
| 72 | + this.DOMobject.dataset.objid = this.ObjID; | |
| 73 | + this.DOMobject.dataset.orgwidth = this.originalWidth; // transform: scaleの基準サイズ | |
| 74 | + this.DOMobject.dataset.orgheight = this.originalHeight; | |
| 75 | + this.DOMobject.dataset.degree = 0; | |
| 76 | + this.DOMobject.addEventListener('mousedown', this.onMouseDown.bind(this), false); | |
| 77 | + if (null != type.match(/imagebox/)) { | |
| 78 | + // imageの場合、画像読み込み完了後に描画する必要がある | |
| 79 | + this.loadImage(opt1); | |
| 80 | + } | |
| 81 | + else { | |
| 82 | + if (null != opt1) { | |
| 83 | + this.loadText(opt1); | |
| 84 | + } | |
| 85 | + else { | |
| 86 | + // 描画呼び出し時に呼び出す関数を登録 | |
| 87 | + this.renderFunc.enqueue(this.renderCreate.bind(this)); | |
| 88 | + } | |
| 89 | + } | |
| 90 | + return true; | |
| 91 | + } | |
| 92 | + loadText(file) { | |
| 93 | + let reader = new FileReader(); | |
| 94 | + // fileを読み込み | |
| 95 | + reader.readAsText(file); // UTF-8として読み込み | |
| 96 | + reader.onload = function (evt) { | |
| 97 | + this.text = evt.target.result; | |
| 98 | + // 描画呼び出し時に呼び出す関数を登録 | |
| 99 | + this.renderFunc.enqueue(this.renderCreate.bind(this)); | |
| 100 | + }.bind(this); | |
| 101 | + } | |
| 102 | + loadImage(file) { | |
| 103 | + let reader = new FileReader(); | |
| 104 | + // fileを読み込み | |
| 105 | + reader.readAsDataURL(file); | |
| 106 | + reader.onload = function (evt) { | |
| 107 | + // src属性にURLをセットして、画像として再度読み込み | |
| 108 | + this.DOMobject.src = evt.target.result; | |
| 109 | + this.DOMobject.onload = function (evt) { | |
| 110 | + // 画像としての読み込み完了後に幅と高さが取れる | |
| 111 | + // 大きすぎ/小さすぎても困るため初期サイズに収まるように拡大/縮小 | |
| 112 | + let rect = this.calcImageWH(parseInt(evt.target.naturalWidth), parseInt(evt.target.naturalHeight)); | |
| 113 | + this.width = rect.right - rect.left; | |
| 114 | + this.height = rect.bottom - rect.top; | |
| 115 | + this.originalWidth = this.width; | |
| 116 | + this.originalHeight = this.height; | |
| 117 | + this.DOMobject.dataset.orgwidth = this.originalWidth; // transform: scaleの基準サイズ | |
| 118 | + this.DOMobject.dataset.orgheight = this.originalHeight; | |
| 119 | + // 表示サイズ取得完了したので画面に表示 | |
| 120 | + this.renderFunc.enqueue(this.renderCreate.bind(this)); | |
| 121 | + }.bind(this); | |
| 122 | + }.bind(this); | |
| 123 | + } | |
| 124 | + calcImageWH(srcW, srcH) { | |
| 125 | + let destW = 0; | |
| 126 | + let destH = 0; | |
| 127 | + let isLongWidth = (srcW < srcH) ? false : true; | |
| 128 | + if (isLongWidth) { | |
| 129 | + let ratio = this.dropinitsize / srcW; | |
| 130 | + destW = this.dropinitsize; | |
| 131 | + destH = srcH * ratio; | |
| 132 | + } | |
| 133 | + else { | |
| 134 | + let ratio = this.dropinitsize / srcH; | |
| 135 | + destH = this.dropinitsize; | |
| 136 | + destW = srcW * ratio; | |
| 137 | + } | |
| 138 | + return new rectData(0, 0, destW, destH); | |
| 139 | + } | |
| 140 | + renderCreate() { | |
| 141 | + this.DOMobject.style.position = "absolute"; // 決め打ち | |
| 142 | + this.DOMobject.style.left = this.x.toString() + "px"; | |
| 143 | + this.DOMobject.style.top = this.y.toString() + "px"; | |
| 144 | + this.DOMobject.style.width = this.width.toString() + "px"; | |
| 145 | + this.DOMobject.style.height = this.height.toString() + "px"; | |
| 146 | + this.DOMobject.style.border = "1px solid black"; // 指定するI/Fが必要 | |
| 147 | +// this.DOMobject.style.backgroundColor = "#cdcdcd"; | |
| 148 | + if (null != this.text) this.DOMobject.innerHTML = this.text; | |
| 149 | + | |
| 150 | + document.getElementById('DispField').appendChild(this.DOMobject); | |
| 151 | + | |
| 152 | + this.debuglog("renderCreate() left=" + this.DOMobject.style.left | |
| 153 | + + ", top=" + this.DOMobject.style.top | |
| 154 | + + ", width=" + this.DOMobject.style.width | |
| 155 | + + ", height=" + this.DOMobject.style.height | |
| 156 | + + ", border=" + this.DOMobject.style.border); | |
| 157 | + } | |
| 158 | + | |
| 159 | + // DIV box 移動 (移動先確定後の移動) | |
| 160 | + // ※ Drag中の表示は別で行っている | |
| 161 | + movebox(x, y) { | |
| 162 | + this.x = x; | |
| 163 | + this.y = y; | |
| 164 | + this.renderFunc.enqueue(this.rendermove.bind(this)); | |
| 165 | + | |
| 166 | + this.debuglog("movebox() x=" + this.x + ", y=" + this.y + ", renderFunc size=" + this.renderFunc.size()); | |
| 167 | + } | |
| 168 | + rendermove() { | |
| 169 | + this.DOMobject.style.left = this.x.toString() + "px"; | |
| 170 | + this.DOMobject.style.top = this.y.toString() + "px"; | |
| 171 | + this.DOMobject.style.opacity = this.opacity.toString(); | |
| 172 | + | |
| 173 | + this.debuglog("rendermove() left=" + this.DOMobject.style.left | |
| 174 | + + ", top=" + this.DOMobject.style.top | |
| 175 | + + ", width=" + this.DOMobject.style.width | |
| 176 | + + ", height=" + this.DOMobject.style.height | |
| 177 | + + ", border=" + this.DOMobject.style.border); | |
| 178 | + } | |
| 179 | + | |
| 180 | + scalebox(rect, fontscale) { | |
| 181 | + this.x = rect.left; | |
| 182 | + this.y = rect.top; | |
| 183 | + this.width = rect.right - rect.left; | |
| 184 | + this.height = rect.bottom - rect.top; | |
| 185 | + this.renderFunc.enqueue(this.renderscalebox.bind(this)); | |
| 186 | + this.fontsize = fontscale; | |
| 187 | + } | |
| 188 | + renderscalebox() { | |
| 189 | + this.DOMobject.style.left = this.x.toString() + "px"; | |
| 190 | + this.DOMobject.style.top = this.y.toString() + "px"; | |
| 191 | + this.DOMobject.style.width = this.width.toString() + "px"; | |
| 192 | + this.DOMobject.style.height = this.height.toString() + "px"; | |
| 193 | + this.DOMobject.style.opacity = this.opacity.toString(); | |
| 194 | + this.DOMobject.style.fontSize = this.fontsize + '%'; | |
| 195 | + } | |
| 196 | + | |
| 197 | + rollbox(degree) { | |
| 198 | + this.degree = degree; | |
| 199 | + this.DOMobject.dataset.degree = degree; | |
| 200 | + this.renderFunc.enqueue(this.renderrollbox.bind(this)); | |
| 201 | + } | |
| 202 | + renderrollbox() { | |
| 203 | + this.DOMobject.style.transform = 'rotateZ(' + this.degree + 'deg);'; | |
| 204 | + } | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + checkType(str) { | |
| 209 | + return true; | |
| 210 | + } | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + // イベント処理関数 --------------------------- | |
| 217 | + onMouseDown(evt) { | |
| 218 | + this.debuglog("onMouseDown"); | |
| 219 | + if (0 == (evt.buttons & 0x0001)) { // 左クリックチェック | |
| 220 | + return; | |
| 221 | + } | |
| 222 | + // Mouse eventをDisplayFieldからScalerに渡してもらうように設定 | |
| 223 | + window.displayField.setMouseEventObj(this.mouseMove.bind(this), this.mouseUp.bind(this)); | |
| 224 | + | |
| 225 | + | |
| 226 | + // Focus設定 | |
| 227 | + evt.target.dataset.focus = "true"; | |
| 228 | + // 移動元として座標を保持 | |
| 229 | + this.startDragX = evt.pageX; | |
| 230 | + this.startDragY = evt.pageY; | |
| 231 | + | |
| 232 | + // Focus表示 | |
| 233 | + window.partsFocus.setClingingPartner(this.DOMobject); | |
| 234 | + | |
| 235 | + } | |
| 236 | + mouseMove(evt) { | |
| 237 | + // 画像の仮移動 | |
| 238 | + this.endDragX = evt.pageX; | |
| 239 | + this.endDragY = evt.pageY; | |
| 240 | + // 移動量取得 | |
| 241 | + let moveX = this.endDragX - this.startDragX; | |
| 242 | + let moveY = this.endDragY - this.startDragY; | |
| 243 | + // dispObjがあった位置からマウス移動分移動させた後の位置取得 | |
| 244 | + moveX = this.x + moveX; | |
| 245 | + moveY = this.y + moveY; | |
| 246 | + | |
| 247 | + this.renderFunc.enqueue(this.renderMoveDragging.bind(this, moveX, moveY)); | |
| 248 | + } | |
| 249 | + renderMoveDragging(x, y) { | |
| 250 | + this.DOMobject.style.left = x + "px"; | |
| 251 | + this.DOMobject.style.top = y + "px"; | |
| 252 | + this.DOMobject.style.opacity = 0.4; | |
| 253 | + } | |
| 254 | + mouseUp(evt) { | |
| 255 | + this.debuglog("mouseUp"); | |
| 256 | + // Mouse event処理対象をクリア | |
| 257 | + window.displayField.setMouseEventObj(null, null); | |
| 258 | + | |
| 259 | + | |
| 260 | + // 移動元として座標を保持 | |
| 261 | + this.endDragX = evt.pageX; | |
| 262 | + this.endDragY = evt.pageY; | |
| 263 | + // 移動量取得 | |
| 264 | + let moveX = this.endDragX - this.startDragX; | |
| 265 | + let moveY = this.endDragY - this.startDragY; | |
| 266 | + // dispObjがあった位置からマウス移動分移動させた後の位置取得 | |
| 267 | + let rect = new rectData(this.x + moveX, this.y + moveY, 0, 0); | |
| 268 | + | |
| 269 | + // 移動 Command発行 | |
| 270 | + let cmd = new CCommandObj(); | |
| 271 | + cmd.createCommand(cmdType.request, cmdAddress.ObjIDMgr, cmdAddress.ObjIDMgr, cmdCmd.movebox, rect, this.ObjID, null, null, 4); | |
| 272 | + this.debuglog("postToWorker"); | |
| 273 | + window.postToWorker.post(cmd); | |
| 274 | + } | |
| 275 | + | |
| 276 | + | |
| 277 | +} // class CDispObj | |
| 278 | + | |
| 279 | + |
| @@ -0,0 +1,132 @@ | ||
| 1 | + | |
| 2 | + | |
| 3 | +class CDisplayField { | |
| 4 | + constructor(dom) { | |
| 5 | + this.DOMobject = dom; | |
| 6 | + this.renderFunc = new Queue(); | |
| 7 | + this.mouseMoveFunc = null; | |
| 8 | + this.mouseUpFunc = null; | |
| 9 | + } | |
| 10 | + | |
| 11 | + debuglog(str) { | |
| 12 | + debuglog("【DisplayField】" + str); | |
| 13 | + } | |
| 14 | + | |
| 15 | + // ■ 初期化 | |
| 16 | + initialize() { | |
| 17 | + if (null == this.DOMobject) { | |
| 18 | + console.log("【DisplayField】 initialize() DOMobject is null."); | |
| 19 | + return false; | |
| 20 | + } | |
| 21 | + this.debuglog("initialize"); | |
| 22 | + this.DOMobject.addEventListener('mousemove', this.onMouseMove.bind(this), false); | |
| 23 | + this.DOMobject.addEventListener('mousedown', this.onMouseDown.bind(this), false); | |
| 24 | + this.DOMobject.addEventListener('mouseup', this.onMouseUp.bind(this), false); | |
| 25 | + this.DOMobject.addEventListener('dragstart', this.onDragStart.bind(this), false); | |
| 26 | + this.DOMobject.addEventListener('dragover', this.onDragover.bind(this), false); | |
| 27 | + this.DOMobject.addEventListener('drop', this.onDrop.bind(this), false); | |
| 28 | + } | |
| 29 | + | |
| 30 | + | |
| 31 | + // 操作関数 ----------------------------------- | |
| 32 | + | |
| 33 | + // Mouse eventを処理するObj | |
| 34 | + setMouseEventObj(mouseMove, mouseUp) { | |
| 35 | + this.debuglog('setMouseEventObj'); | |
| 36 | + | |
| 37 | + this.mouseMoveFunc = mouseMove; | |
| 38 | + this.mouseUpFunc = mouseUp; | |
| 39 | + } | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + // ブラウザ上への描画 ------------------------- | |
| 44 | + render() { | |
| 45 | + while (0 < this.renderFunc.size()) { | |
| 46 | + // this.debuglog("render() renderFunc size=" + this.renderFunc.size()); | |
| 47 | + let renderFunction = this.renderFunc.dequeue(); | |
| 48 | + renderFunction(); | |
| 49 | + } | |
| 50 | + } | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + // Event handler ------------------- | |
| 55 | + | |
| 56 | + // ■マウス左ボタン押下 (Drag処理) | |
| 57 | + onMouseDown(evt) { | |
| 58 | + } | |
| 59 | + // ■ マウス移動 (ドラッグ中) | |
| 60 | + onMouseMove(evt) { | |
| 61 | + // ★ evt.targetが期待するelementかチェックする必要がある | |
| 62 | + // ★ 期待するelementではない場合、DOM treeを辿って親elementから該当elementを探す必要がある | |
| 63 | + | |
| 64 | + if (null != this.mouseMoveFunc) { | |
| 65 | + this.mouseMoveFunc(evt); | |
| 66 | + return; | |
| 67 | + } | |
| 68 | + } | |
| 69 | + // ■ ドロップ処理 | |
| 70 | + onMouseUp(evt) { | |
| 71 | + // ★ evt.targetが期待するelementかチェックする必要がある | |
| 72 | + // ★ 期待するelementではない場合、DOM treeを辿って親elementから該当elementを探す必要がある | |
| 73 | + | |
| 74 | + if (null != this.mouseUpFunc) { | |
| 75 | + this.mouseUpFunc(evt); | |
| 76 | + return; | |
| 77 | + } | |
| 78 | + } | |
| 79 | + | |
| 80 | + // 表示要素の drag & drop禁止 | |
| 81 | + onDragStart(evt) { | |
| 82 | + evt.preventDefault(); | |
| 83 | + } | |
| 84 | + onDragover(evt) { | |
| 85 | + evt.preventDefault(); | |
| 86 | + evt.dataTransfer.dropEffect = "move"; | |
| 87 | + } | |
| 88 | + onDrop(evt) { | |
| 89 | + let ret = false; | |
| 90 | + this.debuglog('onDrop'); | |
| 91 | + evt.stopPropagation(); // event伝播を自分のところで止める(上位に行かなくなる) | |
| 92 | + evt.stopImmediatePropagation(); // 処理中要素の他のevent listenerを止める | |
| 93 | + evt.preventDefault(); // 要素既定のdefault動作を止める | |
| 94 | + | |
| 95 | + getDropFile(evt, this.requestCmdTxtbox.bind(this), this.requestCmdImgbox.bind(this)); | |
| 96 | + } | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + // private関数 ---------------------------------------- | |
| 103 | + | |
| 104 | + requestCmdImgbox(dropfile) { | |
| 105 | + // 画像box 作成 command要求 | |
| 106 | + let rect = new rectData(205, 205, 255, 255); | |
| 107 | + var cmd = new CCommandObj(); | |
| 108 | + // Image box 新規作成 command(新規なので objidを指定する箇所はない) 出力先rect, img blob | |
| 109 | + cmd.createCommand(cmdType.request, cmdAddress.DisplayField, cmdAddress.ObjIDMgr, cmdCmd.createImagebox, rect, dropfile, null, null, 6); | |
| 110 | + window.postToWorker.post(cmd); | |
| 111 | + } | |
| 112 | + requestCmdTxtbox(dropfile) { | |
| 113 | + // Textbox作成 command要求 | |
| 114 | + let rect = new rectData(205, 205, 255, 255); | |
| 115 | + var cmd = new CCommandObj(); | |
| 116 | + // Text box 新規作成 command(新規なので objidを指定する箇所はない) 出力先rect, txt blob | |
| 117 | + cmd.createCommand(cmdType.request, cmdAddress.DisplayField, cmdAddress.ObjIDMgr, cmdCmd.createTextbox, rect, dropfile, null, null, 6); | |
| 118 | + window.postToWorker.post(cmd); | |
| 119 | + } | |
| 120 | + | |
| 121 | + // DOM obj → 対応する dispObjへ変換 | |
| 122 | + getDOMtoDispObj(dom) { | |
| 123 | + if (true == /^DisplayField/.test(dom.dataset.objid)) return null; // DisplayFieldを指しているのでreturn | |
| 124 | + var dispObj = window.ObjIDMgr.getIDtoDispObj(dom.dataset.objid); | |
| 125 | + if (null == dispObj) { | |
| 126 | + console.log("dispObj取得失敗 dom.dataset.objid=" + dom.dataset.objid); | |
| 127 | + return null; | |
| 128 | + } | |
| 129 | + return dispObj; | |
| 130 | + } | |
| 131 | + | |
| 132 | +} // class CDisplayField |
| @@ -0,0 +1,83 @@ | ||
| 1 | +class CObjIDMgr { | |
| 2 | + constructor() { | |
| 3 | + this.ObjIDLen = 0; | |
| 4 | + this.ObjIDarray = { '0': null }; | |
| 5 | + } | |
| 6 | + | |
| 7 | + debuglog(str) { | |
| 8 | + debuglog("【ObjIDMgr】 " + str); | |
| 9 | + } | |
| 10 | + | |
| 11 | + | |
| 12 | + // DispObj.createから呼び出される | |
| 13 | + registerDispObj(DispObj) { | |
| 14 | + if (null == DispObj) { | |
| 15 | + console.error("RegisterDispObj error. DispObj == null."); | |
| 16 | + return -1; | |
| 17 | + } | |
| 18 | + // 今回作成するDispObjのNumberを保存 | |
| 19 | + let objNumber = this.ObjIDLen; | |
| 20 | + this.ObjIDarray[objNumber] = DispObj; | |
| 21 | + // 1件分の登録が完了したら、登録済みObjID数を更新 | |
| 22 | + this.ObjIDLen++; | |
| 23 | + | |
| 24 | + // 返すのは登録されているNumberになる | |
| 25 | + return objNumber; | |
| 26 | + } | |
| 27 | + | |
| 28 | + renderAll() { | |
| 29 | + for (let i = 0; i < this.ObjIDLen; i++) { | |
| 30 | + this.ObjIDarray[i].render(); | |
| 31 | + } | |
| 32 | + } | |
| 33 | + | |
| 34 | + // 指定されたIDの実体(への参照)を返す | |
| 35 | + getIDtoDispObj(id) { | |
| 36 | + let numId = parseInt(id); | |
| 37 | + if (this.ObjIDLen <= numId) { | |
| 38 | + console.error("getIDtoDispObj() 指定されたIDが範囲外 id=" + id + ", numId=" + numId + ", this.ObjIDLen=" + this.ObjIDLen); | |
| 39 | + return null; | |
| 40 | + } | |
| 41 | + return this.ObjIDarray[numId]; | |
| 42 | + } | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + // Command処理 ---------------------- | |
| 48 | + createDispObj(type, rect, opt) { | |
| 49 | + this.debuglog("createDispObj"); | |
| 50 | + var obj = new CDispObj(); | |
| 51 | + obj.create(type, rect, opt); | |
| 52 | + } | |
| 53 | + | |
| 54 | + movebox(id, rect) { | |
| 55 | + this.debuglog("movebox id=" + id); | |
| 56 | + if (id < this.ObjIDLen) { | |
| 57 | + this.ObjIDarray[id].movebox(rect.left, rect.top); | |
| 58 | + } | |
| 59 | + } | |
| 60 | + | |
| 61 | + scalebox(id, rect, fontscale) { | |
| 62 | + this.debuglog("scalebox id=" + id + "fontscale=" + fontscale); | |
| 63 | + if (id < this.ObjIDLen) { | |
| 64 | + this.ObjIDarray[id].scalebox(rect, fontscale); | |
| 65 | + } | |
| 66 | + } | |
| 67 | + | |
| 68 | + rollbox(id, degree) { | |
| 69 | + this.debuglog('rollbox id=' + id + ', deg=' + degree); | |
| 70 | + if (id < this.ObjIDLen) { | |
| 71 | + this.ObjIDarray[id].rollbox(degree); | |
| 72 | + } | |
| 73 | + } | |
| 74 | + | |
| 75 | + deletebox(id) { | |
| 76 | + // 要素を画面から隠す。削除はしない。Undoに対応するため。 | |
| 77 | + // 要素を DOM treeから 切り離すことで表示されないようにする | |
| 78 | + if (id < this.ObjIDLen) { | |
| 79 | + let displayField = document.getElementById('DispField'); | |
| 80 | + displayField.removeChild(this.ObjIDarray[id].DOMobject); | |
| 81 | + } | |
| 82 | + } | |
| 83 | +} // class CObjIDMgr |
| @@ -0,0 +1,29 @@ | ||
| 1 | +// http://keicode.com/script/scr25.php | |
| 2 | +// からの貰い物 ;´Д`) | |
| 3 | + | |
| 4 | +// | |
| 5 | +// Queue (FIFO) | |
| 6 | +// | |
| 7 | + | |
| 8 | +function Queue() { | |
| 9 | + this.__a = new Array(); | |
| 10 | +}; | |
| 11 | + | |
| 12 | +Queue.prototype.enqueue = function (o) { | |
| 13 | + this.__a.push(o); | |
| 14 | +}; | |
| 15 | + | |
| 16 | +Queue.prototype.dequeue = function () { | |
| 17 | + if (this.__a.length > 0) { | |
| 18 | + return this.__a.shift(); | |
| 19 | + } | |
| 20 | + return null; | |
| 21 | +}; | |
| 22 | + | |
| 23 | +Queue.prototype.size = function () { | |
| 24 | + return this.__a.length; | |
| 25 | +}; | |
| 26 | + | |
| 27 | +Queue.prototype.toString = function () { | |
| 28 | + return '[' + this.__a.join(',') + ']'; | |
| 29 | +}; |
| @@ -0,0 +1,51 @@ | ||
| 1 | +// importScripts()での読み込みは、先に定義がないとエラーになるためこのファイルを作成 | |
| 2 | +// (JavaScriptは実行時 型チェックのため定義が前後しても基本的には問題ないが | |
| 3 | +// worker thread用 import関数は読み込みと同時に実行も行うため) | |
| 4 | + | |
| 5 | + | |
| 6 | +// UI thread用 定義 | |
| 7 | +// Worker thead起動, post message | |
| 8 | +function postToWorker() { | |
| 9 | + this.src = "js/worker_thread.js"; | |
| 10 | + this.workerMain = new Worker(this.src); | |
| 11 | + this.workerMain.onmessage = null; | |
| 12 | +}; | |
| 13 | +postToWorker.prototype.setMessageHandler = function (func) { | |
| 14 | + this.workerMain.onmessage = func; | |
| 15 | +}; | |
| 16 | +postToWorker.prototype.post = function (cmd) { | |
| 17 | + if (null == cmd) { | |
| 18 | + console.error("postToUI.post() cmd == null."); | |
| 19 | + return; | |
| 20 | + } | |
| 21 | + if (null == this.workerMain.onmessage) { | |
| 22 | + console.error("■■ Workerからの Msg handler未設定のまま Workerへ postMessage"); | |
| 23 | + } | |
| 24 | + debuglog("== UI --> Worker =============\ntype=" + cmd.type + ", msgID=" + cmd.msgID + ",\nfrom=" + cmd.from + ", to=" + cmd.to + ",\ncmd=" + cmd.cmd + ", praram1=" + cmd.param1 + ", param2=" + cmd.param2 + ", param3=" + cmd.param3 + "\n========================="); | |
| 25 | + this.workerMain.postMessage(cmd); | |
| 26 | +}; | |
| 27 | + | |
| 28 | + | |
| 29 | +// Worker thread用 定義 | |
| 30 | +// Post to UI thread | |
| 31 | +function postToUI() { | |
| 32 | + self.onmessage = null; | |
| 33 | +}; | |
| 34 | +postToUI.prototype.setMessageHandler = function (func) { | |
| 35 | + self.onmessage = func; | |
| 36 | +}; | |
| 37 | +postToUI.prototype.post = function (cmd) { | |
| 38 | + if (null == cmd) { | |
| 39 | + console.log("postToUI.post() cmd == null."); | |
| 40 | + return; | |
| 41 | + } | |
| 42 | + if (undefined == cmd) { | |
| 43 | + console.log("★★ postToUI.post() cmd == undefined"); | |
| 44 | + return; | |
| 45 | + } | |
| 46 | + if (null == self.onmessage) { | |
| 47 | + debuglog("■■ UI threadからの Msg handler未設定のまま UI threadへ postMessage"); | |
| 48 | + } | |
| 49 | + debuglog("__ Worker --> UI ________________" + "\ntype=" + cmd.type + ", msgID=" + cmd.msgID + ",\nfrom=" + cmd.from + ", to=" + cmd.to + ",\ncmd=" + cmd.cmd + ", praram1=" + cmd.param1 + ", param2=" + cmd.param2 + ", param3=" + cmd.param3 + "\n_______________________________"); | |
| 50 | + self.postMessage(cmd); | |
| 51 | +}; | |
| \ No newline at end of file |
| @@ -0,0 +1,376 @@ | ||
| 1 | + | |
| 2 | +// [data-focus="true"] の場合のみ CSSで borderを変更したかったが | |
| 3 | +// DOMに直接 style指定するとその指定が最優先となるため CSSで上書きできない | |
| 4 | +// また、図形として borderを指定したい場合もあるため border: noneにもできない | |
| 5 | +// そのため Focus図形を描く専用の DOMを用意する | |
| 6 | +class CPartsFocus { | |
| 7 | + constructor() { | |
| 8 | + this.lineWidth = 2; | |
| 9 | + this.markWidth = 20; | |
| 10 | + this.num2str = ['focusleft', 'focustop', 'focusright', 'focusbottom']; | |
| 11 | + this.clingingPartner = null; | |
| 12 | + this.DOM = [null, null, null, null]; // focus表示用 | |
| 13 | + this.domScaler = null; | |
| 14 | + this.domRoller = null; | |
| 15 | + this.renderFunc = new Queue(); | |
| 16 | + } | |
| 17 | + | |
| 18 | + debuglog(str) { | |
| 19 | + var focused = (null == this.clingingPartner) ? "null" : this.clingingPartner.dataset.objid; | |
| 20 | + debuglog("【PartsFocus】 focused objid=" + focused + ", " + str); | |
| 21 | + } | |
| 22 | + | |
| 23 | + | |
| 24 | + // ブラウザ上への描画 ------------------------- | |
| 25 | + | |
| 26 | + // domの淵を囲むように Focus lineを表示する | |
| 27 | + // requestAnimationFrameからの呼び出しを想定 | |
| 28 | + render() { | |
| 29 | + while (0 < this.renderFunc.size()) { | |
| 30 | + // this.debuglog("render() renderFunc size=" + this.renderFunc.size()); | |
| 31 | + let renderFunction = this.renderFunc.dequeue(); | |
| 32 | + renderFunction(); | |
| 33 | + } | |
| 34 | + | |
| 35 | + // Drag & Dropを追いかけるための処理 | |
| 36 | + this.renderClinging(); | |
| 37 | + } | |
| 38 | + renderClinging() { | |
| 39 | + if (null == this.clingingPartner) return; | |
| 40 | + | |
| 41 | + let originX = parseInt(this.clingingPartner.style.width) / 2; | |
| 42 | + let originY = parseInt(this.clingingPartner.style.height) / 2; | |
| 43 | + // DOM 描画先rect 回転の中心位置 | |
| 44 | + this.renderClingingSetPosition(this.DOM[0], this.getRectLeft(), (originX + this.lineWidth / 2) + 'px', '50%'); | |
| 45 | + this.renderClingingSetPosition(this.DOM[1], this.getRectTop(), '50%', (originY + this.lineWidth / 2) + 'px'); | |
| 46 | + this.renderClingingSetPosition(this.DOM[2], this.getRectRight(), (originX - this.lineWidth / 2) * -1 + 'px', '50%'); | |
| 47 | + this.renderClingingSetPosition(this.DOM[3], this.getRectBottom(), '50%', (originY - this.lineWidth / 2) * -1 + 'px'); | |
| 48 | + this.renderClingingSetPosition(this.domScaler, this.getRectScaler(), (originX - this.markWidth / 2) * -1 + 'px', (originY - this.markWidth / 2) * -1 + 'px'); | |
| 49 | + // this.renderClingingSetPosition( this.domRoller, this.getRectRoller(), (originX - this.markWidth / 2) * -1 + 'px', (originY + this.markWidth / 2) + 'px'); | |
| 50 | + this.renderClingingSetPosition(this.domRoller, this.getRectRoller(), '50%', (originY + this.markWidth / 2) + 'px'); | |
| 51 | + } | |
| 52 | + renderClingingSetPosition(dom, rect, ox, oy) { | |
| 53 | + dom.style.left = rect.left.toString() + "px"; | |
| 54 | + dom.style.top = rect.top.toString() + "px"; | |
| 55 | + dom.style.width = (rect.right - rect.left).toString() + "px"; | |
| 56 | + dom.style.height = (rect.bottom - rect.top).toString() + "px"; | |
| 57 | + // dom.style.border = "1px solid blue"; | |
| 58 | + dom.style.transform = this.clingingPartner.style.transform; | |
| 59 | + dom.style.transformOrigin = ox + ' ' + oy + ';'; // 回転の中心を focus対象の中心点に合わせる | |
| 60 | + } | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + // Elementの描画 size取得関数 ------------------------- | |
| 65 | + | |
| 66 | + // Focusとして描画する4つのbar それぞれの サイズ取得 | |
| 67 | + getRectLeft() { | |
| 68 | + if (null == this.clingingPartner) return new rectData(0, 0, 0, 0); | |
| 69 | + let rect = new rectData(); | |
| 70 | + rect.setLTWH(this.clingingPartner.style.left, this.clingingPartner.style.top, this.clingingPartner.style.width, this.clingingPartner.style.height); | |
| 71 | + rect.left -= this.lineWidth / 2; rect.top -= this.lineWidth / 2; | |
| 72 | + rect.right = rect.left + this.lineWidth; rect.bottom += this.lineWidth / 2; | |
| 73 | + return rect; | |
| 74 | + } | |
| 75 | + getRectTop() { | |
| 76 | + if (null == this.clingingPartner) return new rectData(0, 0, 0, 0); | |
| 77 | + let rect = new rectData(); | |
| 78 | + rect.setLTWH(this.clingingPartner.style.left, this.clingingPartner.style.top, this.clingingPartner.style.width, this.clingingPartner.style.height); | |
| 79 | + rect.left += this.lineWidth / 2; rect.top -= this.lineWidth / 2; | |
| 80 | + rect.right -= this.lineWidth / 2; rect.bottom = rect.top + this.lineWidth; | |
| 81 | + return rect; | |
| 82 | + } | |
| 83 | + getRectRight() { | |
| 84 | + if (null == this.clingingPartner) return new rectData(0, 0, 0, 0); | |
| 85 | + let rect = new rectData(); | |
| 86 | + rect.setLTWH(this.clingingPartner.style.left, this.clingingPartner.style.top, this.clingingPartner.style.width, this.clingingPartner.style.height); | |
| 87 | + rect.right += this.lineWidth / 2; rect.bottom += this.lineWidth / 2; | |
| 88 | + rect.left = rect.right - this.lineWidth; rect.top -= this.lineWidth / 2; | |
| 89 | + return rect; | |
| 90 | + } | |
| 91 | + getRectBottom() { | |
| 92 | + if (null == this.clingingPartner) return new rectData(0, 0, 0, 0); | |
| 93 | + let rect = new rectData(); | |
| 94 | + rect.setLTWH(this.clingingPartner.style.left, this.clingingPartner.style.top, this.clingingPartner.style.width, this.clingingPartner.style.height); | |
| 95 | + rect.right -= this.lineWidth / 2; rect.bottom += this.lineWidth / 2; | |
| 96 | + rect.left += this.lineWidth / 2; rect.top = rect.bottom - this.lineWidth; | |
| 97 | + return rect; | |
| 98 | + } | |
| 99 | + // 拡大縮小用 右下マーカーの rect取得 | |
| 100 | + getRectScaler() { | |
| 101 | + if (null == this.clingingPartner) return new rectData(0, 0, 0, 0); | |
| 102 | + let centerX = parseInt(this.clingingPartner.style.left) + parseInt(this.clingingPartner.style.width); | |
| 103 | + let centerY = parseInt(this.clingingPartner.style.top) + parseInt(this.clingingPartner.style.height); | |
| 104 | + let rect = new rectData(); | |
| 105 | + rect.left = centerX - this.markWidth / 2; rect.top = centerY - this.markWidth / 2; | |
| 106 | + rect.right = centerX + this.markWidth / 2; rect.bottom = centerY + this.markWidth / 2; | |
| 107 | + return rect; | |
| 108 | + } | |
| 109 | + // 回転用 上辺中心部 マーカーの rect取得 | |
| 110 | + getRectRoller() { | |
| 111 | + if (null == this.clingingPartner) return new rectData(0, 0, 0, 0); | |
| 112 | + let centerX = parseInt(this.clingingPartner.style.left) + parseInt(this.clingingPartner.style.width) / 2; | |
| 113 | + let centerY = parseInt(this.clingingPartner.style.top); | |
| 114 | + let rect = new rectData(); | |
| 115 | + rect.left = centerX - this.markWidth / 2; rect.top = centerY - this.markWidth / 2; | |
| 116 | + rect.right = centerX + this.markWidth / 2; rect.bottom = centerY + this.markWidth / 2; | |
| 117 | + return rect; | |
| 118 | + } | |
| 119 | + | |
| 120 | + // 表示関数----------------------------------- | |
| 121 | + // Focus作成 | |
| 122 | + create() { | |
| 123 | + let getRectProperty = [this.getRectLeft.bind(this), this.getRectTop.bind(this), this.getRectRight.bind(this), this.getRectBottom.bind(this)]; | |
| 124 | + for (let cnt = 0; cnt < this.num2str.length; cnt++) { | |
| 125 | + this.DOM[cnt] = document.createElement('div'); | |
| 126 | + this.DOM[cnt].dataset.objid = this.num2str[cnt]; | |
| 127 | + this.DOM[cnt].classList.add('focusimage'); | |
| 128 | + this.DOM[cnt].classList.add(this.num2str[cnt]); | |
| 129 | + this.renderFunc.enqueue(this.renderCreateOneFocusbar.bind(this, this.DOM[cnt], getRectProperty[cnt]())); | |
| 130 | + } | |
| 131 | + // this.debuglog("create() renderFunc size=" + this.renderFunc.size()); | |
| 132 | + | |
| 133 | + this.createScaler(); | |
| 134 | + this.createRoller(); | |
| 135 | + } | |
| 136 | + renderCreateOneFocusbar(dom, rect) { | |
| 137 | + dom.style.display = (null == this.clingingPartner) ? "none" : "block"; | |
| 138 | + dom.style.position = "absolute"; | |
| 139 | + dom.style.left = rect.left.toString() + "px"; | |
| 140 | + dom.style.top = rect.top.toString() + "px"; | |
| 141 | + dom.style.width = (rect.right - rect.left).toString() + "px"; | |
| 142 | + dom.style.height = (rect.bottom - rect.top).toString() + "px"; | |
| 143 | + // dom.style.border = "1px solid blue"; | |
| 144 | + document.getElementById('DispField').appendChild(dom); | |
| 145 | + } | |
| 146 | + | |
| 147 | + | |
| 148 | + // 拡大縮小操作マーカー作成 | |
| 149 | + createScaler() { | |
| 150 | + this.domScaler = document.createElement('div'); | |
| 151 | + this.domScaler.dataset.objid = 'scaler'; | |
| 152 | + this.domScaler.classList.add('scaler'); | |
| 153 | + this.domScaler.addEventListener('mousedown', this.onMouseDownScale.bind(this), false); | |
| 154 | + this.renderFunc.enqueue(this.renderScaler.bind(this, this.getRectScaler())); | |
| 155 | + } | |
| 156 | + renderScaler(rect) { | |
| 157 | + this.domScaler.style.display = (null == this.clingingPartner) ? "none" : "block"; | |
| 158 | + this.domScaler.style.position = 'absolute'; | |
| 159 | + this.domScaler.style.left = rect.left.toString() + "px"; | |
| 160 | + this.domScaler.style.top = rect.top.toString() + "px"; | |
| 161 | + this.domScaler.style.width = (rect.right - rect.left).toString() + "px"; | |
| 162 | + this.domScaler.style.height = (rect.bottom - rect.top).toString() + "px"; | |
| 163 | + // this.domScaler.style.border = "1px solid blue"; | |
| 164 | + document.getElementById('DispField').appendChild(this.domScaler); | |
| 165 | + } | |
| 166 | + | |
| 167 | + // 回転操作マーカー作成 | |
| 168 | + createRoller() { | |
| 169 | + this.domRoller = document.createElement('div'); | |
| 170 | + this.domRoller.dataset.objid = 'roller'; | |
| 171 | + this.domRoller.classList.add('roller'); | |
| 172 | + this.domRoller.addEventListener('mousedown', this.onMouseDownRoll.bind(this), false); | |
| 173 | + this.renderFunc.enqueue(this.renderRoller.bind(this, this.getRectRoller())); | |
| 174 | + } | |
| 175 | + renderRoller(rect) { | |
| 176 | + this.domRoller.style.display = (null == this.clingingPartner) ? "none" : "block"; | |
| 177 | + this.domRoller.style.position = 'absolute'; | |
| 178 | + this.domRoller.style.left = rect.left.toString() + "px"; | |
| 179 | + this.domRoller.style.top = rect.top.toString() + "px"; | |
| 180 | + this.domRoller.style.width = (rect.right - rect.left).toString() + "px"; | |
| 181 | + this.domRoller.style.height = (rect.bottom - rect.top).toString() + "px"; | |
| 182 | + // this.domRoller.style.border = "1px solid blue"; | |
| 183 | + document.getElementById('DispField').appendChild(this.domRoller); | |
| 184 | + } | |
| 185 | + | |
| 186 | + // 操作関数----------------------------------- | |
| 187 | + // Focus中の objid取得 | |
| 188 | + // 非選択: nullを返す | |
| 189 | + getFocusedObjid() { | |
| 190 | + this.debuglog("getFocusedObjid()."); | |
| 191 | + let ret = null; | |
| 192 | + if (null != this.clingingPartner) { | |
| 193 | + ret = this.clingingPartner.dataset.objid; | |
| 194 | + } | |
| 195 | + return ret; | |
| 196 | + } | |
| 197 | + | |
| 198 | + // Forcus先 クリア (focus 非表示) | |
| 199 | + clearClingingPartner() { | |
| 200 | + this.debuglog("setClingingPartner() clear focus."); | |
| 201 | + this.clingingPartner = null; | |
| 202 | + // requestAnimationFrameでの描画タイミング中は DOM.outerHTMLを変更できないため | |
| 203 | + // 処理ロジック上のまま削除処理を実行する | |
| 204 | + // this.renderFunc.enqueue( this.renderClearClingingPartner.bind(this) ); | |
| 205 | + this.debuglog("clearClingingPartner() renderFunc size=" + this.renderFunc.size()); | |
| 206 | + | |
| 207 | + this.renderClearClingingPartner(); | |
| 208 | + } | |
| 209 | + renderClearClingingPartner() { | |
| 210 | + this.debuglog("renderClearClingingPartner()"); | |
| 211 | + | |
| 212 | + for (let cnt = 0; cnt < this.num2str.length; cnt++) { | |
| 213 | + if (null != this.DOM[cnt]) { | |
| 214 | + this.DOM[cnt].outerHTML = ""; | |
| 215 | + delete this.DOM[cnt]; | |
| 216 | + this.DOM[cnt] = null; | |
| 217 | + } | |
| 218 | + } | |
| 219 | + if (null != this.domScaler) { | |
| 220 | + this.domScaler.outerHTML = ""; | |
| 221 | + delete this.domScaler; | |
| 222 | + this.domScaler = null; | |
| 223 | + } | |
| 224 | + if (null != this.domRoller) { | |
| 225 | + this.domRoller.outerHTML = ""; | |
| 226 | + delete this.domRoller; | |
| 227 | + this.domRoller = null; | |
| 228 | + } | |
| 229 | + } | |
| 230 | + | |
| 231 | + // Forcus先設定 | |
| 232 | + setClingingPartner(dom) { | |
| 233 | + this.debuglog("setClingingPartner()"); | |
| 234 | + | |
| 235 | + // Focus先 クリア | |
| 236 | + if (null == dom) { | |
| 237 | + this.clearClingingPartner(); | |
| 238 | + return; | |
| 239 | + } | |
| 240 | + // Focus先 変更 | |
| 241 | + else if (this.clingingPartner != dom) { | |
| 242 | + // 現在の情報をクリア | |
| 243 | + this.clearClingingPartner(); | |
| 244 | + // 新しいFocus先に変更 | |
| 245 | + this.clingingPartner = dom; | |
| 246 | + this.create(); | |
| 247 | + } | |
| 248 | + } | |
| 249 | + | |
| 250 | + | |
| 251 | + // Event handler ------------------------- | |
| 252 | + onMouseDownScale(evt) { | |
| 253 | + this.debuglog('onMouseDownScale'); | |
| 254 | + | |
| 255 | + // Mouse eventをDisplayFieldからScalerに渡してもらうように設定 | |
| 256 | + window.displayField.setMouseEventObj(this.mouseMoveScale.bind(this), this.mouseUpScale.bind(this)); | |
| 257 | + | |
| 258 | + // 移動元として座標を保持 | |
| 259 | + this.scaleStartWidth = parseInt(this.clingingPartner.style.width); | |
| 260 | + this.scaleStartHeight = parseInt(this.clingingPartner.style.height); | |
| 261 | + this.startDragX = evt.pageX; | |
| 262 | + this.startDragY = evt.pageY; | |
| 263 | + } | |
| 264 | + mouseMoveScale(evt) { | |
| 265 | + // 画像の仮変形 | |
| 266 | + this.endDragX = evt.pageX; | |
| 267 | + this.endDragY = evt.pageY; | |
| 268 | + // 移動量取得 | |
| 269 | + let moveX = this.endDragX - this.startDragX; | |
| 270 | + let moveY = this.endDragY - this.startDragY; | |
| 271 | + | |
| 272 | + switch(1){ | |
| 273 | + case 0: // 領域サイズ変更のみ | |
| 274 | + this.renderFunc.enqueue(this.renderMouseMoveScale.bind(this, this.scaleStartWidth + moveX, this.scaleStartHeight + moveY)); | |
| 275 | + break; | |
| 276 | + case 1: // 縦倍率に合わせfont sizeも変更 | |
| 277 | + { | |
| 278 | + let orgwidth = parseInt(this.clingingPartner.dataset.orgwidth); | |
| 279 | + let orgheight = parseInt(this.clingingPartner.dataset.orgheight); | |
| 280 | + let scaleY = (this.scaleStartHeight + moveY) / orgheight * 100; // ★さらに初期倍率設定値を掛ける必要がある | |
| 281 | + this.renderFunc.enqueue(this.renderMouseMoveScale.bind(this, this.scaleStartWidth + moveX, this.scaleStartHeight + moveY, scaleY)); | |
| 282 | + } | |
| 283 | + break; | |
| 284 | + } | |
| 285 | + } | |
| 286 | + renderMouseMoveScale(width, height, scalefont) { | |
| 287 | + this.clingingPartner.style.opacity = 0.4; | |
| 288 | + | |
| 289 | + switch(1){ | |
| 290 | + case 0: | |
| 291 | + this.clingingPartner.style.width = width + "px"; | |
| 292 | + this.clingingPartner.style.height = height + "px"; | |
| 293 | + break; | |
| 294 | + case 1: | |
| 295 | + this.clingingPartner.style.width = width + "px"; | |
| 296 | + this.clingingPartner.style.height = height + "px"; | |
| 297 | + this.clingingPartner.style.fontSize = scalefont + '%'; | |
| 298 | + break; | |
| 299 | + } | |
| 300 | + } | |
| 301 | + mouseUpScale(evt) { | |
| 302 | + this.debuglog('mouseUpScale'); | |
| 303 | + // Mouse event callback設定をクリア | |
| 304 | + window.displayField.setMouseEventObj(null, null); | |
| 305 | + | |
| 306 | + // 画像の仮変形 | |
| 307 | + this.endDragX = evt.pageX; | |
| 308 | + this.endDragY = evt.pageY; | |
| 309 | + // 移動量取得 | |
| 310 | + let moveX = this.endDragX - this.startDragX; | |
| 311 | + let moveY = this.endDragY - this.startDragY; | |
| 312 | + | |
| 313 | + let rectFrom = new rectData(); | |
| 314 | + let rectTo = new rectData(); | |
| 315 | + rectFrom.setLTWH(parseInt(this.clingingPartner.style.left), parseInt(this.clingingPartner.style.top), this.scaleStartWidth, this.scaleStartHeight); | |
| 316 | + rectTo.setLTWH(rectFrom.left, rectFrom.top, this.scaleStartWidth + moveX, this.scaleStartHeight + moveY); | |
| 317 | + | |
| 318 | + let scaleY = 1.0; | |
| 319 | + switch (1) { | |
| 320 | + case 0: // 領域サイズ変更のみ | |
| 321 | + break; | |
| 322 | + case 1: // 縦倍率に合わせfont sizeも変更 | |
| 323 | + { | |
| 324 | + let orgwidth = parseInt(this.clingingPartner.dataset.orgwidth); | |
| 325 | + let orgheight = parseInt(this.clingingPartner.dataset.orgheight); | |
| 326 | + scaleY = (this.scaleStartHeight + moveY) / orgheight * 100; // ★さらに初期倍率設定値を掛ける必要がある | |
| 327 | + } | |
| 328 | + break; | |
| 329 | + } | |
| 330 | + | |
| 331 | + // Scale Command発行 | |
| 332 | + let cmd = new CCommandObj(); | |
| 333 | + cmd.createCommand(cmdType.request, cmdAddress.Focus, cmdAddress.ObjIDMgr, cmdCmd.scalebox, this.clingingPartner.dataset.objid, rectFrom, rectTo, scaleY, 5); | |
| 334 | + this.debuglog("postToWorker"); | |
| 335 | + window.postToWorker.post(cmd); | |
| 336 | + } | |
| 337 | + | |
| 338 | + onMouseDownRoll(evt) { | |
| 339 | + this.debuglog('onMouseDownRoll'); | |
| 340 | + | |
| 341 | + // Mouse eventをDisplayFieldからRollerに渡してもらうように設定 | |
| 342 | + window.displayField.setMouseEventObj(this.mouseMoveRoll.bind(this), this.mouseUpRoll.bind(this)); | |
| 343 | + } | |
| 344 | + mouseMoveRoll(evt) { | |
| 345 | + let x1 = parseInt(this.clingingPartner.style.left) + parseInt(this.clingingPartner.style.width) / 2; | |
| 346 | + let y1 = parseInt(this.clingingPartner.style.top) + parseInt(this.clingingPartner.style.height) / 2; | |
| 347 | + let x2 = evt.pageX; | |
| 348 | + let y2 = evt.pageY; | |
| 349 | + let degree = angle(x2, y2, x1, y1); | |
| 350 | + | |
| 351 | + this.renderFunc.enqueue(this.renderMouseMoveRoll.bind(this, degree)); | |
| 352 | + } | |
| 353 | + renderMouseMoveRoll(degree) { | |
| 354 | + this.clingingPartner.style.transform = 'rotateZ(' + degree + 'deg);'; | |
| 355 | + } | |
| 356 | + mouseUpRoll(evt) { | |
| 357 | + this.debuglog('mouseUpRoll'); | |
| 358 | + // Mouse event callback設定をクリア | |
| 359 | + window.displayField.setMouseEventObj(null, null); | |
| 360 | + | |
| 361 | + let x1 = parseInt(this.clingingPartner.style.left) + parseInt(this.clingingPartner.style.width) / 2; | |
| 362 | + let y1 = parseInt(this.clingingPartner.style.top) + parseInt(this.clingingPartner.style.height) / 2; | |
| 363 | + let x2 = evt.pageX; | |
| 364 | + let y2 = evt.pageY; | |
| 365 | + let degree = angle(x2, y2, x1, y1); | |
| 366 | + // this.debuglog('■■ x1=' + x1 + ', y1=' + y1 + ',\nx2=' + x2 + ', y2=' + y2 + '\nangle=' + degree); | |
| 367 | + // window.ObjIDMgr.rollbox( this.clingingPartner.dataset.objid, degree ); // debug用 設定情報で直接表示 | |
| 368 | + | |
| 369 | + // Rotate command発行 | |
| 370 | + let cmd = new CCommandObj(); | |
| 371 | + cmd.createCommand(cmdType.request, cmdAddress.Focus, cmdAddress.ObjIDMgr, cmdCmd.rollbox, this.clingingPartner.dataset.objid, degree, null, null, 6); | |
| 372 | + this.debuglog("postToWorker"); | |
| 373 | + window.postToWorker.post(cmd); | |
| 374 | + } | |
| 375 | + | |
| 376 | +} // class CPartsFocus |
| @@ -0,0 +1,201 @@ | ||
| 1 | +class CSSPalette { | |
| 2 | + constructor() { | |
| 3 | + this.DOMobject = []; | |
| 4 | + this.draggingDOM = null; | |
| 5 | + } | |
| 6 | + | |
| 7 | + debuglog(str) { | |
| 8 | + debuglog('【CSSPalette】 ' + str); | |
| 9 | + } | |
| 10 | + | |
| 11 | + initialize() { | |
| 12 | + // CSS 情報定義先を保持 | |
| 13 | + this.stylebg = document.getElementById('stylepalbg'); | |
| 14 | + this.styletxtcol = document.getElementById('stylepaltxtcol'); | |
| 15 | + this.styleact = document.getElementById('stylepalact'); | |
| 16 | + | |
| 17 | + // palette要素を保持 | |
| 18 | + // 背景設定パレット | |
| 19 | + this.DOMpalbg = document.getElementsByClassName('palbg'); | |
| 20 | + for (let cnt = 0; cnt < this.DOMpalbg.length; cnt++) { | |
| 21 | + this.DOMpalbg[cnt].addEventListener('mousedown', this.onMouseDown.bind(this), false); | |
| 22 | + this.DOMpalbg[cnt].addEventListener('dragstart', this.onDragStart.bind(this), false); | |
| 23 | + this.DOMpalbg[cnt].addEventListener('dragover', this.onDragOver.bind(this), false); | |
| 24 | + this.DOMpalbg[cnt].addEventListener('drop', this.onDrop.bind(this), false); | |
| 25 | + } | |
| 26 | + // テキストカラーパレット | |
| 27 | + this.DOMpaltxtcol = document.getElementsByClassName('paltxtcol'); | |
| 28 | + for (let cnt = 0; cnt < this.DOMpaltxtcol.length; cnt++) { | |
| 29 | + this.DOMpaltxtcol[cnt].addEventListener('mousedown', this.onMouseDown.bind(this), false); | |
| 30 | + this.DOMpaltxtcol[cnt].addEventListener('dragstart', this.onDragStart.bind(this), false); | |
| 31 | + this.DOMpaltxtcol[cnt].addEventListener('dragover', this.onDragOver.bind(this), false); | |
| 32 | + this.DOMpaltxtcol[cnt].addEventListener('drop', this.onDrop.bind(this), false); | |
| 33 | + } | |
| 34 | + // アクションパレット | |
| 35 | + this.DOMpalact = document.getElementsByClassName('palact'); | |
| 36 | + for (let cnt = 0; cnt < this.DOMpalact.length; cnt++) { | |
| 37 | + this.DOMpalact[cnt].addEventListener('mousedown', this.onMouseDown.bind(this), false); | |
| 38 | + this.DOMpalact[cnt].addEventListener('dragstart', this.onDragStart.bind(this), false); | |
| 39 | + this.DOMpalact[cnt].addEventListener('dragover', this.onDragOver.bind(this), false); | |
| 40 | + this.DOMpalact[cnt].addEventListener('drop', this.onDrop.bind(this), false); | |
| 41 | + } | |
| 42 | + } | |
| 43 | + | |
| 44 | + // 操作関数 ---------------------------- | |
| 45 | + definepalbg( | |
| 46 | + id, // bg palette要素番号 | |
| 47 | + file // 画像を指しているfile object | |
| 48 | + ) { | |
| 49 | + let cssstr1 = '.palbg' + id + ' { background-image: url('; | |
| 50 | + let cssstr2 = '); }'; | |
| 51 | + setImageFileToCSS(this.stylebg, id, cssstr1, cssstr2, file); | |
| 52 | + } | |
| 53 | + | |
| 54 | + // text color ('#000000, rgba(0,0,0,0) など) | |
| 55 | + definepaltxtcolText( | |
| 56 | + id, // txtcol palette要素番号 | |
| 57 | + file // Textを指しているfile object | |
| 58 | + ) { | |
| 59 | + let cssstr1 = '.paltxtcol' + id + ' {\ncolor: '; | |
| 60 | + let cssstr2 = ';\n}'; | |
| 61 | + setTextFileToCSS(this.styletxtcol, id, cssstr1, cssstr2, file); | |
| 62 | + }; | |
| 63 | + // 指定された画像を font colorとして設定する | |
| 64 | + definepaltxtcolImage( | |
| 65 | + id, // txtcol palette要素番号 | |
| 66 | + file // 画像を指しているfile object | |
| 67 | + ) { | |
| 68 | + let cssstr1 = '.paltxtcol' + id + ' { background: url('; | |
| 69 | + let cssstr2 = '); background-size: contain; color: #fff; -webkit-text-fill-color: transparent; -webkit-background-clip: text; }'; | |
| 70 | + setImageFileToCSS(this.styletxtcol, id, cssstr1, cssstr2, file); | |
| 71 | + }; | |
| 72 | + // 指定された Text fileを CSS animation定義として保持する | |
| 73 | + // Text fileには下記2つの定義が含まれていること | |
| 74 | + // 1. 「animation:」で始まり 「;」で終わる animation定義 | |
| 75 | + // 2. 「@keyframe」で始まり 「}」で終わる keyframe定義 (定義不要ならdummy定義) | |
| 76 | + definepalactText( | |
| 77 | + id, // act palette要素番号 | |
| 78 | + file // Textを指しているfile object | |
| 79 | + ) { | |
| 80 | + let cssstr1 = '.palact' + id + ' { '; | |
| 81 | + let cssstr2 = '}'; | |
| 82 | + | |
| 83 | + // drop fileの読み込み | |
| 84 | + let reader = new FileReader(); | |
| 85 | + // Text fileを読み込み | |
| 86 | + reader.readAsText(file); | |
| 87 | + reader.onload = function (ele, num, cssstr1, cssstr2, evt) { | |
| 88 | + let cssdata = evt.target.result; // 読み込んだ文字列 | |
| 89 | + | |
| 90 | + // 読み込んだ文字列を 「animation定義」と「keyframe定義」に分割 | |
| 91 | + let keyframeStartIndex = cssdata.indexOf('@keyframe'); | |
| 92 | + let strAnimation = cssdata.slice(0, keyframeStartIndex - 1); | |
| 93 | + let strKeyframe = cssdata.slice(keyframeStartIndex); | |
| 94 | + | |
| 95 | + // CSS定義の差し替え | |
| 96 | + let defAnimNum = id * 2; // CSS定義が 'animation' と '@keyframe'のため | |
| 97 | + let cssAnimation = String(cssstr1) + strAnimation + String(cssstr2); | |
| 98 | + let cssKeyframe = strKeyframe; | |
| 99 | + // animation定義置き換え | |
| 100 | + ele.sheet.deleteRule(defAnimNum); | |
| 101 | + ele.sheet.insertRule(cssAnimation, defAnimNum); | |
| 102 | + // keyframe定義置き換え | |
| 103 | + ele.sheet.deleteRule(defAnimNum + 1); | |
| 104 | + ele.sheet.insertRule(cssKeyframe, defAnimNum + 1); | |
| 105 | + }.bind(this, this.styleact, id, cssstr1, cssstr2); | |
| 106 | + }; | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + // Event handler ----------------------- | |
| 112 | + | |
| 113 | + // Drag&Drop event : Application外からのfileのやり取り | |
| 114 | + // Mouse event : Elementに対する操作 | |
| 115 | + | |
| 116 | + // Drag&Drop event | |
| 117 | + // Applicationの外からFile Dropされたときに | |
| 118 | + // File内容情報を読み込み、CSSに反映させる | |
| 119 | + onDragStart(evt) { | |
| 120 | + evt.preventDefault(); | |
| 121 | + } | |
| 122 | + onDragOver(evt) { | |
| 123 | + evt.preventDefault(); | |
| 124 | + evt.dataTransfer.dropEffect = "move"; | |
| 125 | + } | |
| 126 | + onDrop(evt) { | |
| 127 | + this.debuglog('onDrop'); | |
| 128 | + evt.stopPropagation(); // event伝播を自分のところで止める(上位に行かなくなる) | |
| 129 | + evt.stopImmediatePropagation(); // 処理中要素の他のevent listenerを止める | |
| 130 | + evt.preventDefault(); // 要素既定のdefault動作を止める | |
| 131 | + | |
| 132 | + | |
| 133 | + // drop対象 elementを特定 | |
| 134 | + let objid = evt.target.dataset.objid; | |
| 135 | + let palid = parseInt(evt.target.dataset.palid);; | |
| 136 | + | |
| 137 | + // Dropされたfileを読み込み、CSSに反映 | |
| 138 | + if (null != objid.match(/^palbg/)) { | |
| 139 | + getDropFile(evt, null, this.definepalbg.bind(this, palid), null); | |
| 140 | + } | |
| 141 | + else if (null != objid.match(/^paltxtcol/)) { | |
| 142 | + getDropFile(evt, this.definepaltxtcolText.bind(this, palid), this.definepaltxtcolImage.bind(this, palid), null); | |
| 143 | + } | |
| 144 | + else if (null != objid.match(/^palact/)) { | |
| 145 | + getDropFile(evt, this.definepalactText.bind(this, palid), null, null); | |
| 146 | + } | |
| 147 | + | |
| 148 | + } | |
| 149 | + | |
| 150 | + | |
| 151 | + // Mouse event | |
| 152 | + // 自elementをDragし、Drop時にTarget elementに自分のCSS classを適用する | |
| 153 | + onMouseDown(evt) { | |
| 154 | + this.draggingDOM = evt.target; | |
| 155 | + | |
| 156 | + // Mouse eventをDisplayFieldからCSSPalに渡してもらうように設定 | |
| 157 | + window.displayField.setMouseEventObj(this.mouseMove.bind(this), this.mouseUp.bind(this)); | |
| 158 | + } | |
| 159 | + mouseMove(evt) { | |
| 160 | + if (null == this.draggingDOM) return; | |
| 161 | + | |
| 162 | + | |
| 163 | + } | |
| 164 | + mouseUp(evt) { | |
| 165 | + let palobjid = this.draggingDOM.dataset.objid; | |
| 166 | + let palid = this.draggingDOM.dataset.palid; | |
| 167 | + | |
| 168 | + // Drag中 element情報をクリア | |
| 169 | + this.draggingDOM = null; | |
| 170 | + // Mouse event callback設定をクリア | |
| 171 | + window.displayField.setMouseEventObj(null, null); | |
| 172 | + | |
| 173 | + // Drag中 palette elementから target element へ CSS classを追加する | |
| 174 | + // 同じ種類のCSS class(Text color, BG imgなど)が既にある場合は上書き | |
| 175 | + | |
| 176 | + this.replaceCSSclassToElement(palobjid, evt.target); | |
| 177 | + } | |
| 178 | + | |
| 179 | + // Target element へ CSS classを追加する | |
| 180 | + // 同じ種類のCSS class(Text color, BG imgなど)が既にある場合は上書き | |
| 181 | + replaceCSSclassToElement( | |
| 182 | + CSSname, // 追加(上書き)する CSSclass名称文字列 | |
| 183 | + targetEle // 追加先 element | |
| 184 | + ) { | |
| 185 | + // Drag中の palette elementから 追加する CSS classを取得 (objidと同じ名前にしている) | |
| 186 | + let result = /[a-zA-Z]+/.exec(CSSname); // objid末の数字を除く | |
| 187 | + let DraggingPaletteType = result[0]; | |
| 188 | + | |
| 189 | + // Drop target elementに 同じ種類の CSS classがないかチェック | |
| 190 | + let reg = new RegExp(DraggingPaletteType + '[0-9]+'); // 数字は1回以上発生する。数字なしは別class | |
| 191 | + result = reg.exec(targetEle.className); | |
| 192 | + let DropEleOldClass = (null != result) ? result[0] : null; | |
| 193 | + | |
| 194 | + // 同じ種類の CSS classがあれば削除 | |
| 195 | + if (null != DropEleOldClass) | |
| 196 | + targetEle.classList.remove(DropEleOldClass); | |
| 197 | + | |
| 198 | + // Drop target elementに Drag elementの CSS class定義を追加 | |
| 199 | + targetEle.classList.add(CSSname); | |
| 200 | + } | |
| 201 | +} // class CSSPalette |
| @@ -0,0 +1,46 @@ | ||
| 1 | + | |
| 2 | +// worker threadでのcommand処理に必要な class fileの読み込みと実行 | |
| 3 | +// (引数のjs内容の実行も行われる) | |
| 4 | +importScripts('Common.js'); | |
| 5 | +importScripts('Queue.js'); | |
| 6 | +importScripts('CommandObj.js'); | |
| 7 | +importScripts('ThreadMessage.js'); | |
| 8 | +importScripts('CommandMgr.js'); | |
| 9 | + | |
| 10 | + | |
| 11 | +self.postToUI = new postToUI(); | |
| 12 | +self.postToUI.setMessageHandler( receiveUIMessage ); | |
| 13 | + | |
| 14 | + | |
| 15 | +var data = new Object(); | |
| 16 | +// Worker threadのGrobal object上にpropertyを追加 | |
| 17 | +// (window objectではないため、UI threadには見えない) | |
| 18 | +var cmdMgr = new CCommandMgr(); | |
| 19 | + | |
| 20 | +/* | |
| 21 | +onmessage = function (evt) { | |
| 22 | +*/ | |
| 23 | +function receiveUIMessage(evt) { | |
| 24 | + "use strict"; | |
| 25 | + console.log("[Worker thread] Message received."); | |
| 26 | + console.log(evt.data); | |
| 27 | + | |
| 28 | + // cmdQueに1件追加 | |
| 29 | + cmdMgr.requestCommand(evt.data); | |
| 30 | + | |
| 31 | + // Command処理 | |
| 32 | + cmdMgr.processCommands(); | |
| 33 | +}; | |
| 34 | + | |
| 35 | + | |
| 36 | +/* | |
| 37 | + while ( true ) { | |
| 38 | + // Command処理 | |
| 39 | + cmdMgr.processCommand(); | |
| 40 | + | |
| 41 | + // 終了条件を作成したい | |
| 42 | + // postMessageで終了要求受信時 | |
| 43 | + // cmdQue消化完了してから | |
| 44 | + // Loopを抜ける | |
| 45 | + } | |
| 46 | +*/ |
| @@ -34,7 +34,7 @@ | ||
| 34 | 34 | <build:Metadata> |
| 35 | 35 | <build:Item Name="VisualStudio" Version="14.0" /> |
| 36 | 36 | <build:Item Name="VisualStudioEdition" Value="Microsoft Visual Studio Community 2015" /> |
| 37 | - <build:Item Name="OperatingSystem" Version="10.0.14959.1000 (rs_prerelease.161026-1700)" /> | |
| 37 | + <build:Item Name="OperatingSystem" Version="10.0.14971.1000 (rs_prerelease.161111-1700)" /> | |
| 38 | 38 | <build:Item Name="Microsoft.Build.AppxPackage.dll" Version="14.0.25431.1" /> |
| 39 | 39 | <build:Item Name="ProjectGUID" Value="284de86f-bd39-49ec-b61a-983818f9b461" /> |
| 40 | 40 | <build:Item Name="OptimizingToolset" Value="None" /> |
| @@ -14,3 +14,19 @@ | ||
| 14 | 14 | C:\Work\Projects\WebApp\HTMLDrawApp\HTMLDrawApp\bld\x64\Debug\qualifiers.txt.intermediate |
| 15 | 15 | C:\Work\Projects\WebApp\HTMLDrawApp\HTMLDrawApp\bld\x64\Debug\MultipleQualifiersPerDimensionFound.txt |
| 16 | 16 | C:\Work\Projects\WebApp\HTMLDrawApp\HTMLDrawApp\bld\x64\Debug\ProjectArchitectures.txt |
| 17 | +C:\Work\takoyaki_umaaaaHideout\HtmlDrawApp\HTMLDrawApp\bin\x64\Debug\ReverseMap\resources.pri | |
| 18 | +C:\Work\takoyaki_umaaaaHideout\HtmlDrawApp\HTMLDrawApp\bin\x64\Debug\AppxManifest.xml | |
| 19 | +C:\Work\takoyaki_umaaaaHideout\HtmlDrawApp\HTMLDrawApp\bin\x64\Debug\HTMLDrawApp.build.appxrecipe | |
| 20 | +C:\Work\takoyaki_umaaaaHideout\HtmlDrawApp\HTMLDrawApp\bld\x64\Debug\ResourceHandlingTask.state | |
| 21 | +C:\Work\takoyaki_umaaaaHideout\HtmlDrawApp\HTMLDrawApp\bld\x64\Debug\priconfig.xml | |
| 22 | +C:\Work\takoyaki_umaaaaHideout\HtmlDrawApp\HTMLDrawApp\bld\x64\Debug\priconfig.xml.intermediate | |
| 23 | +C:\Work\takoyaki_umaaaaHideout\HtmlDrawApp\HTMLDrawApp\bld\x64\Debug\layout.resfiles | |
| 24 | +C:\Work\takoyaki_umaaaaHideout\HtmlDrawApp\HTMLDrawApp\bld\x64\Debug\layout.resfiles.intermediate | |
| 25 | +C:\Work\takoyaki_umaaaaHideout\HtmlDrawApp\HTMLDrawApp\bld\x64\Debug\resources.resfiles | |
| 26 | +C:\Work\takoyaki_umaaaaHideout\HtmlDrawApp\HTMLDrawApp\bld\x64\Debug\resources.resfiles.intermediate | |
| 27 | +C:\Work\takoyaki_umaaaaHideout\HtmlDrawApp\HTMLDrawApp\bld\x64\Debug\pri.resfiles | |
| 28 | +C:\Work\takoyaki_umaaaaHideout\HtmlDrawApp\HTMLDrawApp\bld\x64\Debug\pri.resfiles.intermediate | |
| 29 | +C:\Work\takoyaki_umaaaaHideout\HtmlDrawApp\HTMLDrawApp\bld\x64\Debug\qualifiers.txt | |
| 30 | +C:\Work\takoyaki_umaaaaHideout\HtmlDrawApp\HTMLDrawApp\bld\x64\Debug\qualifiers.txt.intermediate | |
| 31 | +C:\Work\takoyaki_umaaaaHideout\HtmlDrawApp\HTMLDrawApp\bld\x64\Debug\MultipleQualifiersPerDimensionFound.txt | |
| 32 | +C:\Work\takoyaki_umaaaaHideout\HtmlDrawApp\HTMLDrawApp\bld\x64\Debug\ProjectArchitectures.txt |
| @@ -1 +1 @@ | ||
| 1 | -C:\Work\Projects\WebApp\HTMLDrawApp\HTMLDrawApp\HTMLDrawApp.jsproj;x64 | |
| 1 | +C:\Work\takoyaki_umaaaaHideout\HtmlDrawApp\HTMLDrawApp\HTMLDrawApp.jsproj;x64 |
| @@ -20,31 +20,38 @@ | ||
| 20 | 20 | } |
| 21 | 21 | */ |
| 22 | 22 | |
| 23 | + /* キャンバス要素の定義 */ | |
| 23 | 24 | #DispField{ |
| 24 | 25 | display:block; |
| 25 | 26 | width:400px; height:300px; |
| 26 | 27 | border:1px solid black; |
| 28 | + margin: 10px; | |
| 27 | 29 | } |
| 28 | 30 | |
| 29 | - .palbg { | |
| 31 | + | |
| 32 | + /* パレット要素の定義 */ | |
| 33 | + .palbg, | |
| 34 | + .paltxtcol, | |
| 35 | + .palact { | |
| 30 | 36 | display: inline-block; |
| 31 | 37 | width: 25px; height: 25px; |
| 32 | 38 | border: 2px solid blue; |
| 33 | - margin: 10px; | |
| 39 | + margin: 2px; | |
| 34 | 40 | } |
| 35 | - | |
| 41 | + .palbg { | |
| 42 | + border: 2px solid black; | |
| 43 | + } | |
| 36 | 44 | .paltxtcol { |
| 37 | - display: inline-block; | |
| 38 | - width: 25px; height: 25px; | |
| 39 | - border: 2px solid brown; | |
| 40 | - margin: 10px; | |
| 45 | + border: 2px solid blue; | |
| 41 | 46 | text-align: center; |
| 42 | 47 | font-size: 100%; |
| 43 | 48 | } |
| 49 | + .palact { | |
| 50 | + border: 2px solid brown; | |
| 51 | + } | |
| 44 | 52 | |
| 45 | 53 | |
| 46 | - | |
| 47 | - | |
| 54 | + /* フォーカス枠と拡大縮小・回転用マーカー定義 */ | |
| 48 | 55 | .scaler { |
| 49 | 56 | border: 2px solid black; |
| 50 | 57 | border-radius: 50%; |
| @@ -13,11 +13,11 @@ | ||
| 13 | 13 | </div> |
| 14 | 14 | <!-- 固定ボタン (選択要素の削除, 保存, …) --> |
| 15 | 15 | <button type=button class="pal" data-objid="pal" data-palid="0" data-value="0xff000001">削除</button> |
| 16 | - <button type=button class="pal" data-objid="pal" data-palid="1" data-value="0x00ff0001">button2</button> | |
| 17 | - <button type=button class="pal" data-objid="pal" data-palid="2" data-value="0x0000ff01">button3</button> | |
| 18 | - <button type=button class="pal" data-objid="pal" data-palid="3" data-value="0xffffff01">button4</button> | |
| 16 | + <button type=button class="pal" data-objid="pal" data-palid="1" data-value="0x00ff0001">設定保存</button> | |
| 17 | + <button type=button class="pal" data-objid="pal" data-palid="2" data-value="0x0000ff01">設定Drop</button> | |
| 18 | + <button type=button class="pal" data-objid="pal" data-palid="3" data-value="0xffffff01">アニメ停止</button> | |
| 19 | 19 | <button type=button class="pal" data-objid="pal" data-palid="4" data-value="0x00000000">button5</button> |
| 20 | - <a href="#" id="save" download="savefilename.txt">Save</a><br /> | |
| 20 | + <a href="#" id="save" download="savefilename.txt">画像保存</a><br /> | |
| 21 | 21 | |
| 22 | 22 | <!-- Palette --> |
| 23 | 23 | <style id="stylepalbg"> |
| @@ -51,8 +51,25 @@ | ||
| 51 | 51 | 90% {transform: translateY(0px) translateX(-5px);} |
| 52 | 52 | 100% {transform: translateY(0px) translateX(0px);} |
| 53 | 53 | } |
| 54 | - .palact1 { animation: animeY1 2s ease-in 0.3s 1 normal; } | |
| 55 | 54 | |
| 55 | + .palact1 { animation: animeact1 2s ease-in 0.3s 1 normal; } | |
| 56 | + @keyframes animeact1 { to {color:black;} } | |
| 57 | + | |
| 58 | + .palact2 { animation: animeact2 2s ease-in 0.3s 1 normal; } | |
| 59 | + @keyframes animeact2 { to {color:black;} } | |
| 60 | + | |
| 61 | + .palact3 { animation: animeact3 2s ease-in 0.3s 1 normal; } | |
| 62 | + @keyframes animeact3 { to {color:black;} } | |
| 63 | + | |
| 64 | + .palact4 { animation: animeact4 2s ease-in 0.3s 1 normal; } | |
| 65 | + @keyframes animeact4 { to {color:black;} } | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 56 | 73 | </style> |
| 57 | 74 | <div class="palbg palbg0" data-objid="palbg0" data-palid="0"></div> |
| 58 | 75 | <div class="palbg palbg1" data-objid="palbg1" data-palid="1"></div> |
| @@ -60,6 +77,8 @@ | ||
| 60 | 77 | <div class="palbg palbg3" data-objid="palbg3" data-palid="3"></div> |
| 61 | 78 | <div class="palbg palbg4" data-objid="palbg4" data-palid="4"></div> |
| 62 | 79 | |
| 80 | + <br /> | |
| 81 | + | |
| 63 | 82 | <div class="paltxtcol paltxtcol0" data-objid="paltxtcol0" data-palid="0">あ</div> |
| 64 | 83 | <div class="paltxtcol paltxtcol1" data-objid="paltxtcol1" data-palid="1">あ</div> |
| 65 | 84 | <div class="paltxtcol paltxtcol2" data-objid="paltxtcol2" data-palid="2">あ</div> |
| @@ -66,6 +85,14 @@ | ||
| 66 | 85 | <div class="paltxtcol paltxtcol3" data-objid="paltxtcol3" data-palid="3">あ</div> |
| 67 | 86 | <div class="paltxtcol paltxtcol4" data-objid="paltxtcol4" data-palid="4">あ</div> |
| 68 | 87 | |
| 88 | + <br /> | |
| 89 | + | |
| 90 | + <div class="palact palact0" data-objid="palact0" data-palid="0"></div> | |
| 91 | + <div class="palact palact1" data-objid="palact1" data-palid="1"></div> | |
| 92 | + <div class="palact palact2" data-objid="palact2" data-palid="2"></div> | |
| 93 | + <div class="palact palact3" data-objid="palact3" data-palid="3"></div> | |
| 94 | + <div class="palact palact4" data-objid="palact4" data-palid="4"></div> | |
| 95 | + | |
| 69 | 96 | <script type="text/javascript" src="js/Common.js"></script> |
| 70 | 97 | <script type="text/javascript" src="js/Queue.js"></script> |
| 71 | 98 | <script type="text/javascript" src="js/CommandObj.js"></script> |
| @@ -15,6 +15,7 @@ | ||
| 15 | 15 | this.styleact = document.getElementById('stylepalact'); |
| 16 | 16 | |
| 17 | 17 | // palette要素を保持 |
| 18 | + // 背景設定パレット | |
| 18 | 19 | this.DOMpalbg = document.getElementsByClassName('palbg'); |
| 19 | 20 | for (let cnt = 0; cnt < this.DOMpalbg.length; cnt++) { |
| 20 | 21 | this.DOMpalbg[cnt].addEventListener('mousedown', this.onMouseDown.bind(this), false); |
| @@ -22,6 +23,7 @@ | ||
| 22 | 23 | this.DOMpalbg[cnt].addEventListener('dragover', this.onDragOver.bind(this), false); |
| 23 | 24 | this.DOMpalbg[cnt].addEventListener('drop', this.onDrop.bind(this), false); |
| 24 | 25 | } |
| 26 | + // テキストカラーパレット | |
| 25 | 27 | this.DOMpaltxtcol = document.getElementsByClassName('paltxtcol'); |
| 26 | 28 | for (let cnt = 0; cnt < this.DOMpaltxtcol.length; cnt++) { |
| 27 | 29 | this.DOMpaltxtcol[cnt].addEventListener('mousedown', this.onMouseDown.bind(this), false); |
| @@ -29,6 +31,14 @@ | ||
| 29 | 31 | this.DOMpaltxtcol[cnt].addEventListener('dragover', this.onDragOver.bind(this), false); |
| 30 | 32 | this.DOMpaltxtcol[cnt].addEventListener('drop', this.onDrop.bind(this), false); |
| 31 | 33 | } |
| 34 | + // アクションパレット | |
| 35 | + this.DOMpalact = document.getElementsByClassName('palact'); | |
| 36 | + for (let cnt = 0; cnt < this.DOMpalact.length; cnt++) { | |
| 37 | + this.DOMpalact[cnt].addEventListener('mousedown', this.onMouseDown.bind(this), false); | |
| 38 | + this.DOMpalact[cnt].addEventListener('dragstart', this.onDragStart.bind(this), false); | |
| 39 | + this.DOMpalact[cnt].addEventListener('dragover', this.onDragOver.bind(this), false); | |
| 40 | + this.DOMpalact[cnt].addEventListener('drop', this.onDrop.bind(this), false); | |
| 41 | + } | |
| 32 | 42 | } |
| 33 | 43 | |
| 34 | 44 | // 操作関数 ---------------------------- |
| @@ -55,21 +65,45 @@ | ||
| 55 | 65 | id, // txtcol palette要素番号 |
| 56 | 66 | file // 画像を指しているfile object |
| 57 | 67 | ) { |
| 58 | -let cssstr1 = '\ | |
| 59 | -.paltxtcol' + id + ' {\n\ | |
| 60 | -background: url('; | |
| 68 | + let cssstr1 = '.paltxtcol' + id + ' { background: url('; | |
| 69 | + let cssstr2 = '); background-size: contain; color: #fff; -webkit-text-fill-color: transparent; -webkit-background-clip: text; }'; | |
| 70 | + setImageFileToCSS(this.styletxtcol, id, cssstr1, cssstr2, file); | |
| 71 | + }; | |
| 72 | + // 指定された Text fileを CSS animation定義として保持する | |
| 73 | + // Text fileには下記2つの定義が含まれていること | |
| 74 | + // 1. 「animation:」で始まり 「;」で終わる animation定義 | |
| 75 | + // 2. 「@keyframe」で始まり 「}」で終わる keyframe定義 (定義不要ならdummy定義) | |
| 76 | + definepalactText( | |
| 77 | + id, // act palette要素番号 | |
| 78 | + file // Textを指しているfile object | |
| 79 | + ) { | |
| 80 | + let cssstr1 = '.palact' + id + ' { '; | |
| 81 | + let cssstr2 = '}'; | |
| 61 | 82 | |
| 62 | -let cssstr2 = '\ | |
| 63 | -);\n\ | |
| 64 | -background-size: contain;\n\ | |
| 65 | -color: #fff;\n\ | |
| 66 | --webkit-text-fill-color: transparent;\n\ | |
| 67 | --webkit-background-clip: text;\n\ | |
| 68 | -}'; | |
| 83 | + // drop fileの読み込み | |
| 84 | + let reader = new FileReader(); | |
| 85 | + // Text fileを読み込み | |
| 86 | + reader.readAsText(file); | |
| 87 | + reader.onload = function (ele, num, cssstr1, cssstr2, evt) { | |
| 88 | + let cssdata = evt.target.result; // 読み込んだ文字列 | |
| 69 | 89 | |
| 70 | - setImageFileToCSS(this.styletxtcol, id, cssstr1, cssstr2, file); | |
| 71 | - } | |
| 90 | + // 読み込んだ文字列を 「animation定義」と「keyframe定義」に分割 | |
| 91 | + let keyframeStartIndex = cssdata.indexOf('@keyframe'); | |
| 92 | + let strAnimation = cssdata.slice(0, keyframeStartIndex - 1); | |
| 93 | + let strKeyframe = cssdata.slice(keyframeStartIndex); | |
| 72 | 94 | |
| 95 | + // CSS定義の差し替え | |
| 96 | + let defAnimNum = id * 2; // CSS定義が 'animation' と '@keyframe'のため | |
| 97 | + let cssAnimation = String(cssstr1) + strAnimation + String(cssstr2); | |
| 98 | + let cssKeyframe = strKeyframe; | |
| 99 | + // animation定義置き換え | |
| 100 | + ele.sheet.deleteRule(defAnimNum); | |
| 101 | + ele.sheet.insertRule(cssAnimation, defAnimNum); | |
| 102 | + // keyframe定義置き換え | |
| 103 | + ele.sheet.deleteRule(defAnimNum + 1); | |
| 104 | + ele.sheet.insertRule(cssKeyframe, defAnimNum + 1); | |
| 105 | + }.bind(this, this.styleact, id, cssstr1, cssstr2); | |
| 106 | + }; | |
| 73 | 107 | |
| 74 | 108 | |
| 75 | 109 |
| @@ -79,6 +113,9 @@ | ||
| 79 | 113 | // Drag&Drop event : Application外からのfileのやり取り |
| 80 | 114 | // Mouse event : Elementに対する操作 |
| 81 | 115 | |
| 116 | + // Drag&Drop event | |
| 117 | + // Applicationの外からFile Dropされたときに | |
| 118 | + // File内容情報を読み込み、CSSに反映させる | |
| 82 | 119 | onDragStart(evt) { |
| 83 | 120 | evt.preventDefault(); |
| 84 | 121 | } |
| @@ -93,22 +130,26 @@ | ||
| 93 | 130 | evt.preventDefault(); // 要素既定のdefault動作を止める |
| 94 | 131 | |
| 95 | 132 | |
| 96 | - let palid = 0; | |
| 97 | 133 | // drop対象 elementを特定 |
| 98 | 134 | let objid = evt.target.dataset.objid; |
| 135 | + let palid = parseInt(evt.target.dataset.palid);; | |
| 136 | + | |
| 137 | + // Dropされたfileを読み込み、CSSに反映 | |
| 99 | 138 | if (null != objid.match(/^palbg/)) { |
| 100 | - palid = parseInt(evt.target.dataset.palid); | |
| 101 | - getDropFile(evt, null, this.definepalbg.bind(this, palid)); | |
| 139 | + getDropFile(evt, null, this.definepalbg.bind(this, palid), null); | |
| 102 | 140 | } |
| 103 | 141 | else if (null != objid.match(/^paltxtcol/)) { |
| 104 | - palid = parseInt(evt.target.dataset.palid); | |
| 105 | - getDropFile(evt, this.definepaltxtcolText.bind(this, palid), this.definepaltxtcolImage.bind(this, palid)); | |
| 142 | + getDropFile(evt, this.definepaltxtcolText.bind(this, palid), this.definepaltxtcolImage.bind(this, palid), null); | |
| 106 | 143 | } |
| 144 | + else if (null != objid.match(/^palact/)) { | |
| 145 | + getDropFile(evt, this.definepalactText.bind(this, palid), null, null); | |
| 146 | + } | |
| 107 | 147 | |
| 108 | 148 | } |
| 109 | 149 | |
| 110 | 150 | |
| 111 | - | |
| 151 | + // Mouse event | |
| 152 | + // 自elementをDragし、Drop時にTarget elementに自分のCSS classを適用する | |
| 112 | 153 | onMouseDown(evt) { |
| 113 | 154 | this.draggingDOM = evt.target; |
| 114 | 155 |
| @@ -0,0 +1,14 @@ | ||
| 1 | +animation: animeY1 1.5s ease-in 0.3s infinite alternate; | |
| 2 | +@keyframes animeY1 { | |
| 3 | + 0% {transform: translateY(-60px) translateX(-30px);} | |
| 4 | + 10% {transform: translateY(20px) translateX(30px);} | |
| 5 | + 20% {transform: translateY(-40px) translateX(-20px);} | |
| 6 | + 30% {transform: translateY(50px) translateX(-10px);} | |
| 7 | + 40% {transform: translateY(-40px) translateX(20px);} | |
| 8 | + 50% {transform: translateY(30px) translateX(-15px);} | |
| 9 | + 60% {transform: translateY(-25px) translateX(0px);} | |
| 10 | + 70% {transform: translateY(15px) translateX(-15px);} | |
| 11 | + 80% {transform: translateY(-10px) translateX(10px);} | |
| 12 | + 90% {transform: translateY(0px) translateX(-5px);} | |
| 13 | + 100% {transform: translateY(0px) translateX(0px);} | |
| 14 | +} | |
| \ No newline at end of file |