scene designer
This commit is contained in:
Generated
+70
-70
@@ -26,8 +26,8 @@
|
|||||||
"sharp": "^0.33.5",
|
"sharp": "^0.33.5",
|
||||||
"three": "^0.169.0",
|
"three": "^0.169.0",
|
||||||
"uuid": "^11.0.2",
|
"uuid": "^11.0.2",
|
||||||
"vue": "^3.4.31",
|
"vue": "^3.5.13",
|
||||||
"vuetify": "^3.6.11"
|
"vuetify": "^3.7.16"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vitejs/plugin-vue": "^5.0.5",
|
"@vitejs/plugin-vue": "^5.0.5",
|
||||||
@@ -1544,53 +1544,53 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/compiler-core": {
|
"node_modules/@vue/compiler-core": {
|
||||||
"version": "3.5.12",
|
"version": "3.5.13",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.12.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.13.tgz",
|
||||||
"integrity": "sha512-ISyBTRMmMYagUxhcpyEH0hpXRd/KqDU4ymofPgl2XAkY9ZhQ+h0ovEZJIiPop13UmR/54oA2cgMDjgroRelaEw==",
|
"integrity": "sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/parser": "^7.25.3",
|
"@babel/parser": "^7.25.3",
|
||||||
"@vue/shared": "3.5.12",
|
"@vue/shared": "3.5.13",
|
||||||
"entities": "^4.5.0",
|
"entities": "^4.5.0",
|
||||||
"estree-walker": "^2.0.2",
|
"estree-walker": "^2.0.2",
|
||||||
"source-map-js": "^1.2.0"
|
"source-map-js": "^1.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/compiler-dom": {
|
"node_modules/@vue/compiler-dom": {
|
||||||
"version": "3.5.12",
|
"version": "3.5.13",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.12.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.13.tgz",
|
||||||
"integrity": "sha512-9G6PbJ03uwxLHKQ3P42cMTi85lDRvGLB2rSGOiQqtXELat6uI4n8cNz9yjfVHRPIu+MsK6TE418Giruvgptckg==",
|
"integrity": "sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/compiler-core": "3.5.12",
|
"@vue/compiler-core": "3.5.13",
|
||||||
"@vue/shared": "3.5.12"
|
"@vue/shared": "3.5.13"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/compiler-sfc": {
|
"node_modules/@vue/compiler-sfc": {
|
||||||
"version": "3.5.12",
|
"version": "3.5.13",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.12.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.13.tgz",
|
||||||
"integrity": "sha512-2k973OGo2JuAa5+ZlekuQJtitI5CgLMOwgl94BzMCsKZCX/xiqzJYzapl4opFogKHqwJk34vfsaKpfEhd1k5nw==",
|
"integrity": "sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/parser": "^7.25.3",
|
"@babel/parser": "^7.25.3",
|
||||||
"@vue/compiler-core": "3.5.12",
|
"@vue/compiler-core": "3.5.13",
|
||||||
"@vue/compiler-dom": "3.5.12",
|
"@vue/compiler-dom": "3.5.13",
|
||||||
"@vue/compiler-ssr": "3.5.12",
|
"@vue/compiler-ssr": "3.5.13",
|
||||||
"@vue/shared": "3.5.12",
|
"@vue/shared": "3.5.13",
|
||||||
"estree-walker": "^2.0.2",
|
"estree-walker": "^2.0.2",
|
||||||
"magic-string": "^0.30.11",
|
"magic-string": "^0.30.11",
|
||||||
"postcss": "^8.4.47",
|
"postcss": "^8.4.48",
|
||||||
"source-map-js": "^1.2.0"
|
"source-map-js": "^1.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/compiler-ssr": {
|
"node_modules/@vue/compiler-ssr": {
|
||||||
"version": "3.5.12",
|
"version": "3.5.13",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.12.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.13.tgz",
|
||||||
"integrity": "sha512-eLwc7v6bfGBSM7wZOGPmRavSWzNFF6+PdRhE+VFJhNCgHiF8AM7ccoqcv5kBXA2eWUfigD7byekvf/JsOfKvPA==",
|
"integrity": "sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/compiler-dom": "3.5.12",
|
"@vue/compiler-dom": "3.5.13",
|
||||||
"@vue/shared": "3.5.12"
|
"@vue/shared": "3.5.13"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/devtools-api": {
|
"node_modules/@vue/devtools-api": {
|
||||||
@@ -1601,53 +1601,53 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@vue/reactivity": {
|
"node_modules/@vue/reactivity": {
|
||||||
"version": "3.5.12",
|
"version": "3.5.13",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.12.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.13.tgz",
|
||||||
"integrity": "sha512-UzaN3Da7xnJXdz4Okb/BGbAaomRHc3RdoWqTzlvd9+WBR5m3J39J1fGcHes7U3za0ruYn/iYy/a1euhMEHvTAg==",
|
"integrity": "sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/shared": "3.5.12"
|
"@vue/shared": "3.5.13"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/runtime-core": {
|
"node_modules/@vue/runtime-core": {
|
||||||
"version": "3.5.12",
|
"version": "3.5.13",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.12.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.13.tgz",
|
||||||
"integrity": "sha512-hrMUYV6tpocr3TL3Ad8DqxOdpDe4zuQY4HPY3X/VRh+L2myQO8MFXPAMarIOSGNu0bFAjh1yBkMPXZBqCk62Uw==",
|
"integrity": "sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/reactivity": "3.5.12",
|
"@vue/reactivity": "3.5.13",
|
||||||
"@vue/shared": "3.5.12"
|
"@vue/shared": "3.5.13"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/runtime-dom": {
|
"node_modules/@vue/runtime-dom": {
|
||||||
"version": "3.5.12",
|
"version": "3.5.13",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.12.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.13.tgz",
|
||||||
"integrity": "sha512-q8VFxR9A2MRfBr6/55Q3umyoN7ya836FzRXajPB6/Vvuv0zOPL+qltd9rIMzG/DbRLAIlREmnLsplEF/kotXKA==",
|
"integrity": "sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/reactivity": "3.5.12",
|
"@vue/reactivity": "3.5.13",
|
||||||
"@vue/runtime-core": "3.5.12",
|
"@vue/runtime-core": "3.5.13",
|
||||||
"@vue/shared": "3.5.12",
|
"@vue/shared": "3.5.13",
|
||||||
"csstype": "^3.1.3"
|
"csstype": "^3.1.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/server-renderer": {
|
"node_modules/@vue/server-renderer": {
|
||||||
"version": "3.5.12",
|
"version": "3.5.13",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.12.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.13.tgz",
|
||||||
"integrity": "sha512-I3QoeDDeEPZm8yR28JtY+rk880Oqmj43hreIBVTicisFTx/Dl7JpG72g/X7YF8hnQD3IFhkky5i2bPonwrTVPg==",
|
"integrity": "sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/compiler-ssr": "3.5.12",
|
"@vue/compiler-ssr": "3.5.13",
|
||||||
"@vue/shared": "3.5.12"
|
"@vue/shared": "3.5.13"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"vue": "3.5.12"
|
"vue": "3.5.13"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/shared": {
|
"node_modules/@vue/shared": {
|
||||||
"version": "3.5.12",
|
"version": "3.5.13",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.12.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.13.tgz",
|
||||||
"integrity": "sha512-L2RPSAwUFbgZH20etwrXyVyCBu9OxRSi8T/38QsvnkJyvq2LufW2lDCOzm7t/U9C1mkhJGWYfCuFBCmIuNivrg==",
|
"integrity": "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@vuetify/loader-shared": {
|
"node_modules/@vuetify/loader-shared": {
|
||||||
@@ -5284,9 +5284,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/nanoid": {
|
"node_modules/nanoid": {
|
||||||
"version": "3.3.7",
|
"version": "3.3.9",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.9.tgz",
|
||||||
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
|
"integrity": "sha512-SppoicMGpZvbF1l3z4x7No3OlIjP7QJvC9XR7AhZr1kL133KHnKPztkKDc+Ir4aJ/1VhTySrtKhrsycmrMQfvg==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "github",
|
"type": "github",
|
||||||
@@ -5601,9 +5601,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/picocolors": {
|
"node_modules/picocolors": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||||
"integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==",
|
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/picomatch": {
|
"node_modules/picomatch": {
|
||||||
@@ -5726,9 +5726,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.4.47",
|
"version": "8.5.3",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz",
|
||||||
"integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==",
|
"integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
@@ -5745,8 +5745,8 @@
|
|||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nanoid": "^3.3.7",
|
"nanoid": "^3.3.8",
|
||||||
"picocolors": "^1.1.0",
|
"picocolors": "^1.1.1",
|
||||||
"source-map-js": "^1.2.1"
|
"source-map-js": "^1.2.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -7278,16 +7278,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vue": {
|
"node_modules/vue": {
|
||||||
"version": "3.5.12",
|
"version": "3.5.13",
|
||||||
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.12.tgz",
|
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.13.tgz",
|
||||||
"integrity": "sha512-CLVZtXtn2ItBIi/zHZ0Sg1Xkb7+PU32bJJ8Bmy7ts3jxXTcbfsEfBivFYYWz1Hur+lalqGAh65Coin0r+HRUfg==",
|
"integrity": "sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/compiler-dom": "3.5.12",
|
"@vue/compiler-dom": "3.5.13",
|
||||||
"@vue/compiler-sfc": "3.5.12",
|
"@vue/compiler-sfc": "3.5.13",
|
||||||
"@vue/runtime-dom": "3.5.12",
|
"@vue/runtime-dom": "3.5.13",
|
||||||
"@vue/server-renderer": "3.5.12",
|
"@vue/server-renderer": "3.5.13",
|
||||||
"@vue/shared": "3.5.12"
|
"@vue/shared": "3.5.13"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"typescript": "*"
|
"typescript": "*"
|
||||||
@@ -7353,9 +7353,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vuetify": {
|
"node_modules/vuetify": {
|
||||||
"version": "3.7.2",
|
"version": "3.7.16",
|
||||||
"resolved": "https://registry.npmjs.org/vuetify/-/vuetify-3.7.2.tgz",
|
"resolved": "https://registry.npmjs.org/vuetify/-/vuetify-3.7.16.tgz",
|
||||||
"integrity": "sha512-q0WTcRG977+a9Dqhb8TOaPm+Xmvj0oVhnBJhAdHWFSov3HhHTTxlH2nXP/GBTXZuuMHDbBeIWFuUR2/1Fx0PPw==",
|
"integrity": "sha512-Few/cBtgJYgdkzi0LWmVy67G5uc2+q7oWcadbcTUPAtEtGYNh2AM28h01Fk+ScJgfxkA077//ZDff1rh3jYG/w==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^12.20 || >=14.13"
|
"node": "^12.20 || >=14.13"
|
||||||
|
|||||||
+2
-2
@@ -28,8 +28,8 @@
|
|||||||
"sharp": "^0.33.5",
|
"sharp": "^0.33.5",
|
||||||
"three": "^0.169.0",
|
"three": "^0.169.0",
|
||||||
"uuid": "^11.0.2",
|
"uuid": "^11.0.2",
|
||||||
"vue": "^3.4.31",
|
"vue": "^3.5.13",
|
||||||
"vuetify": "^3.6.11"
|
"vuetify": "^3.7.16"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vitejs/plugin-vue": "^5.0.5",
|
"@vitejs/plugin-vue": "^5.0.5",
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<v-list>
|
<v-list>
|
||||||
<v-list-item to="/game-objects/add">Нов игрови обект</v-list-item>
|
<v-list-item to="/game-objects/add">Нов игрови обект</v-list-item>
|
||||||
<v-list-item>Нов сценарий</v-list-item>
|
<v-list-item to="/scenarios/add">Нов сценарий</v-list-item>
|
||||||
<v-list-item to="/games/add">Нова игра</v-list-item>
|
<v-list-item to="/games/add">Нова игра</v-list-item>
|
||||||
</v-list>
|
</v-list>
|
||||||
</v-menu>
|
</v-menu>
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
<v-divider></v-divider>
|
<v-divider></v-divider>
|
||||||
<v-list nav>
|
<v-list nav>
|
||||||
<v-list-item prepend-icon="mdi-database" to="/game-objects/list" :title="$l.gameObjects"></v-list-item>
|
<v-list-item prepend-icon="mdi-database" to="/game-objects/list" :title="$l.gameObjects"></v-list-item>
|
||||||
<v-list-item prepend-icon="mdi-receipt-text-edit-outline" :title="$l.gameScenarios"></v-list-item>
|
<v-list-item prepend-icon="mdi-receipt-text-edit-outline" to="/scenarios/list" :title="$l.gameScenarios"></v-list-item>
|
||||||
<v-list-item prepend-icon="mdi-cogs" :title="$l.gameRules"></v-list-item>
|
<v-list-item prepend-icon="mdi-cogs" :title="$l.gameRules"></v-list-item>
|
||||||
<v-divider></v-divider>
|
<v-divider></v-divider>
|
||||||
<v-list-item prepend-icon="mdi-controller" :title="$l.games" to="/games/list"></v-list-item>
|
<v-list-item prepend-icon="mdi-controller" :title="$l.games" to="/games/list"></v-list-item>
|
||||||
|
|||||||
@@ -0,0 +1,269 @@
|
|||||||
|
<template>
|
||||||
|
<div class="container my-3">
|
||||||
|
<v-btn-toggle variant="tonal" density="compact" class="mx-auto" v-model="listMode" color="blue">
|
||||||
|
<v-btn class="text-none" value="scene"><v-icon>mdi-panorama-outline</v-icon><span>{{ $l.addScene }}</span></v-btn>
|
||||||
|
<v-btn class="text-none" value="object"><v-icon>mdi-bird</v-icon><span>{{ $l.addScene }}</span></v-btn>
|
||||||
|
<v-btn class="text-none" value="task"><v-icon>mdi-checkbox-marked-circle-plus-outline</v-icon><span>{{ $l.addScene }}</span></v-btn>
|
||||||
|
</v-btn-toggle>
|
||||||
|
<div @wheel="onWheel" @mousedown="onMouseDown" @mouseup="onMouseUp" @mousemove="onDrag"
|
||||||
|
:class="`svg-container ${mode}`" ref="svgContainer">
|
||||||
|
<svg>
|
||||||
|
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<v-navigation-drawer location="right">
|
||||||
|
<svg-scene></svg-scene>
|
||||||
|
</v-navigation-drawer>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import SvgScene from './SvgScene.vue';
|
||||||
|
|
||||||
|
const components = {
|
||||||
|
SvgScene
|
||||||
|
}
|
||||||
|
export default {
|
||||||
|
components: { SvgScene },
|
||||||
|
props:{
|
||||||
|
modelValue: Object
|
||||||
|
},
|
||||||
|
data(){
|
||||||
|
return {
|
||||||
|
listMode: 'select'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed:{
|
||||||
|
object:()=>this.modelValue,
|
||||||
|
zoom:{
|
||||||
|
get(){
|
||||||
|
return 1 / this.scale;
|
||||||
|
},
|
||||||
|
set(v){
|
||||||
|
this.rescale(1 / v);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mode(){
|
||||||
|
return this.listMode[0];
|
||||||
|
},
|
||||||
|
components(){
|
||||||
|
return components;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods:{
|
||||||
|
rescale(scale, e){
|
||||||
|
let oldScale = this.scale;
|
||||||
|
if (!e){
|
||||||
|
this.scale = scale;
|
||||||
|
this.offset.x += (oldScale - this.scale) * (this.$refs.svgContainer.offsetWidth/2);
|
||||||
|
this.offset.y += (oldScale - this.scale) * (this.$refs.svgContainer.offsetHeight/2);
|
||||||
|
}else{
|
||||||
|
this.scale *= (1 + Math.sign(e.deltaY) / 10);
|
||||||
|
let oo = {
|
||||||
|
x: (oldScale - this.scale) * e.offsetX,
|
||||||
|
y: (oldScale - this.scale) * e.offsetY
|
||||||
|
};
|
||||||
|
if (this.target){
|
||||||
|
this.retarget(e)
|
||||||
|
}
|
||||||
|
this.offset.x += oo.x;
|
||||||
|
this.offset.y += oo.y
|
||||||
|
}
|
||||||
|
document.documentElement.style.setProperty('--svg-scale', this.scale);
|
||||||
|
},
|
||||||
|
retarget(e){
|
||||||
|
if (this.target.delta){
|
||||||
|
this.retargetDelta(e, this.target)
|
||||||
|
}else{
|
||||||
|
this.retargetAbsolute(e, this.target)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
retargetDelta(e, target){
|
||||||
|
let p = {
|
||||||
|
x: Utils.round(e.movementX*this.scale, 0),
|
||||||
|
y: Utils.round(e.movementY*this.scale, 0)
|
||||||
|
}
|
||||||
|
target.attrs.forEach(a=>{
|
||||||
|
if (Array.isArray(a)){
|
||||||
|
a[0] = p.x;
|
||||||
|
a[1] = p.y;
|
||||||
|
}else if (a.startsWith('x')){
|
||||||
|
this.target.target[a] += p.x;
|
||||||
|
}else if (a.startsWith('y')){
|
||||||
|
this.target.target[a] += p.y;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
retargetAbsolute(e, target){
|
||||||
|
let p = {
|
||||||
|
x: Utils.round(this.vb.x + e.offsetX * this.scale),
|
||||||
|
y: Utils.round(this.vb.y + e.offsetY * this.scale)
|
||||||
|
}
|
||||||
|
target.attrs.forEach(a=>{
|
||||||
|
if (Array.isArray(a)){
|
||||||
|
a[0] = p.x;
|
||||||
|
a[1] = p.y;
|
||||||
|
}else if (a.startsWith('x')){
|
||||||
|
this.target.target[a] = p.x;
|
||||||
|
}else if (a.startsWith('y')){
|
||||||
|
this.target.target[a] = p.y;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onWheel(e){
|
||||||
|
this.rescale(null, e);
|
||||||
|
},
|
||||||
|
onDrag(e){
|
||||||
|
if (this.mousedown?.button == 0 || this.modeStep > 0) {
|
||||||
|
if (this.mode == 'move'){
|
||||||
|
let p = {
|
||||||
|
x: Utils.round(e.movementX*this.scale, 0),
|
||||||
|
y: Utils.round(e.movementY*this.scale, 0)
|
||||||
|
}
|
||||||
|
this.selectedItem.forEach(i=>{
|
||||||
|
let mf = components[i.name].modifiers;
|
||||||
|
mf.filter(m=>m.match(/^x[0-9]+$/)).forEach(x=>i.data[x]+= p.x);
|
||||||
|
mf.filter(m=>m.match(/^y[0-9]+$/)).forEach(y=>i.data[y]+= p.y);
|
||||||
|
})
|
||||||
|
}else if (this.target) {
|
||||||
|
this.retarget(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (e.shiftKey ||
|
||||||
|
this.mousedown?.button == 1 ||
|
||||||
|
(this.mode == 'pan' && this.mousedown?.button == 0) ||
|
||||||
|
(this.mode == 'default' && this.mousedown?.button == 0 && !this.target)
|
||||||
|
){
|
||||||
|
this.offset.x -= e.movementX*this.scale;
|
||||||
|
this.offset.y -= e.movementY*this.scale;
|
||||||
|
}
|
||||||
|
//console.log(e);
|
||||||
|
},
|
||||||
|
onMouseDown(e){
|
||||||
|
this.mousedown = { button: e.button };
|
||||||
|
//console.log(e, this.mode, this.modeStep)
|
||||||
|
if (e.button == 0 && !['default', 'move', 'pan'].includes( this.mode )){
|
||||||
|
let cs;
|
||||||
|
if (this.mode == 'select'){
|
||||||
|
//console.log('selecting')
|
||||||
|
cs = [['x1', 'y1'], ['x2', 'y2']];
|
||||||
|
if (this.modeStep == 0){
|
||||||
|
this.target = {
|
||||||
|
target: this.selector,
|
||||||
|
attrs: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
cs = this.components[this.mode].steps;
|
||||||
|
//console.log(cs);
|
||||||
|
if (this.modeStep == 0){
|
||||||
|
this.target = {
|
||||||
|
target: {},
|
||||||
|
attrs: []
|
||||||
|
}
|
||||||
|
let id, nid = 1;
|
||||||
|
do {
|
||||||
|
id = `${this.components[this.mode].name}-${nid++}`
|
||||||
|
}while (this.items.find(i=>i.id == id))
|
||||||
|
this.items.push({
|
||||||
|
name: this.mode,
|
||||||
|
data: this.target.target,
|
||||||
|
visible: true,
|
||||||
|
id, title: id
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let p = {
|
||||||
|
x: Utils.round(this.vb.x + e.offsetX * this.scale),
|
||||||
|
y: Utils.round(this.vb.y + e.offsetY * this.scale)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = this.modeStep + 1; i <= cs.length; i++){
|
||||||
|
this.target.target[cs[i-1][0]] = p.x;
|
||||||
|
this.target.target[cs[i-1][1]] = p.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.modeStep++;
|
||||||
|
if (this.modeStep >= cs.length){
|
||||||
|
this.modeStep = 0;
|
||||||
|
if (this.mode == 'select'){
|
||||||
|
this.select();
|
||||||
|
this.selector.x1 = this.selector.y1 = this.selector.x2 = this.selector.y2 = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.modeStep ){
|
||||||
|
this.target.attrs[0] = cs[this.modeStep][0];
|
||||||
|
this.target.attrs[1] = cs[this.modeStep][1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onMouseUp(){
|
||||||
|
this.mousedown = false;
|
||||||
|
if (this.mode == 'default' && !this.target){
|
||||||
|
this.selectedItem = [];
|
||||||
|
}
|
||||||
|
if (this.modeStep == 0){
|
||||||
|
this.target = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setTarget(t, item){
|
||||||
|
this.target = t;
|
||||||
|
this.selectedItem = [item]
|
||||||
|
},
|
||||||
|
async save(){
|
||||||
|
let imageData = await Utils.blobToBase64(await (await fetch(this.imageTarget)).blob());
|
||||||
|
//console.log(imageData)
|
||||||
|
let jsonData = {
|
||||||
|
items: this.items,
|
||||||
|
viewBox: this.viewBox,
|
||||||
|
offset: this.offset,
|
||||||
|
zoom: this.zoom,
|
||||||
|
rotation: this.imgRotation,
|
||||||
|
page: this.page,
|
||||||
|
data: imageData
|
||||||
|
};
|
||||||
|
const link = document.createElement('a')
|
||||||
|
const blob = new Blob([JSON.stringify(jsonData)], {type: 'application/json'});
|
||||||
|
link.href = URL.createObjectURL(blob)
|
||||||
|
link.download = "document.json"
|
||||||
|
link.click();
|
||||||
|
},
|
||||||
|
select(){
|
||||||
|
let r = Utils.adjustMinMax(this.selector);
|
||||||
|
this.selectedItem = this.items.filter(i=>this.$refs['svg-'+i.id][0].intersect(r));
|
||||||
|
},
|
||||||
|
|
||||||
|
async processImage(){
|
||||||
|
this.processingImage = true;
|
||||||
|
await this.$nextTick();
|
||||||
|
let processor = new ImageProcessor(this.$refs.imageCanvas, this.img)
|
||||||
|
let lines = processor.identifyLines(), iw = this.img.naturalWidth;
|
||||||
|
lines.forEach((l, i)=>{
|
||||||
|
this.items.push({
|
||||||
|
name: 'SvgHorizontalLine', id: `aline-${i}`, visible: true, title: `ALine-${i}`,
|
||||||
|
data: { x1:iw*.1, y1: l, x2: iw*.9}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
this.processingImage = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.svg-container{
|
||||||
|
svg{
|
||||||
|
width: 100%;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
image{
|
||||||
|
clip-path: circle(50% at 50% 50%);
|
||||||
|
}
|
||||||
|
circle {
|
||||||
|
stroke: rgb(var(--v-theme-primary));
|
||||||
|
fill:rgba(255,255,255,.5);
|
||||||
|
stroke-width: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<template>
|
||||||
|
<circle :cx="65 + x" :cy="65 + y" :r="70"></circle>
|
||||||
|
<image :href="src" :x="x" :y="y" height="130" width="130" preserveAspectRatio="xMidYMid slice"></image>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props:['src', 'x', 'y'],
|
||||||
|
data(){
|
||||||
|
return {
|
||||||
|
target: null,
|
||||||
|
img: null,
|
||||||
|
size:{}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created(){
|
||||||
|
// this.img = new Image();
|
||||||
|
// this.img.onload = ()=>{
|
||||||
|
// this.size = {
|
||||||
|
// w: this.img.naturalWidth,
|
||||||
|
// h: this.img.naturalHeight,
|
||||||
|
// a: this.img.naturalWidth / this.img.naturalHeight
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// this.img.src= this.target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<template>
|
||||||
|
<teleport to="svg" defer>
|
||||||
|
<g>
|
||||||
|
<svg-avatar src="/asset/thumb/6.webp" :x="50" :y="50"></svg-avatar>
|
||||||
|
</g>
|
||||||
|
</teleport>
|
||||||
|
<v-list density="compact" nav>
|
||||||
|
<v-list-item prepend-icon="mdi-panorama-outline" :title="$l.addScene" value="scene"></v-list-item>
|
||||||
|
</v-list>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import SvgAvatar from './SvgAvatar.vue';
|
||||||
|
export default {
|
||||||
|
components: { SvgAvatar },
|
||||||
|
data(){
|
||||||
|
return {
|
||||||
|
active: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted(){
|
||||||
|
this.active = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -35,6 +35,7 @@ class GameEngine {
|
|||||||
// renderer.shadowMap.type = THREE.PCFSoftShadowMap; // default THREE.PCFShadowMap
|
// renderer.shadowMap.type = THREE.PCFSoftShadowMap; // default THREE.PCFShadowMap
|
||||||
renderer.outputEncoding = THREE.sRGBEncoding;
|
renderer.outputEncoding = THREE.sRGBEncoding;
|
||||||
const controls = new OrbitControls( camera, renderer.domElement );
|
const controls = new OrbitControls( camera, renderer.domElement );
|
||||||
|
//controls.enableZoom = true;
|
||||||
//const controls = new MapControls( camera, renderer.domElement );
|
//const controls = new MapControls( camera, renderer.domElement );
|
||||||
this.transformControls = new TransformControls( camera, renderer.domElement );
|
this.transformControls = new TransformControls( camera, renderer.domElement );
|
||||||
this.transformControls.addEventListener( 'dragging-changed', function ( event ) {
|
this.transformControls.addEventListener( 'dragging-changed', function ( event ) {
|
||||||
@@ -64,6 +65,12 @@ class GameEngine {
|
|||||||
scene.background = bck; //new THREE.Color(0.7,0.7,0.7);
|
scene.background = bck; //new THREE.Color(0.7,0.7,0.7);
|
||||||
scene.environment = texture;
|
scene.environment = texture;
|
||||||
console.log('GameEngine started')
|
console.log('GameEngine started')
|
||||||
|
renderer.domElement.addEventListener('wheel', (event)=>{
|
||||||
|
camera.zoom -= event.deltaY / 1000;
|
||||||
|
camera.zoom = Math.max(camera.zoom, .4);
|
||||||
|
controls.rotateSpeed = 1 / camera.zoom;
|
||||||
|
camera.updateProjectionMatrix();
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
$ = THREE;
|
$ = THREE;
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
<template>
|
||||||
|
<v-card :title="id == 'add' ? $l.createScenario : $l.editScenario" class="container my-3">
|
||||||
|
<v-form class="pa-4" v-model="valid">
|
||||||
|
<v-text-field :label="$l.name" v-model="object.name" :rules="[rules.required]"></v-text-field>
|
||||||
|
</v-form>
|
||||||
|
<!-- <v-card-actions>
|
||||||
|
<v-btn @click="saveAndPreview" :loading="loading" prepend-icon="mdi-content-save" color="primary"
|
||||||
|
:disabled="!valid">
|
||||||
|
{{ $l.saveAndPreview }}
|
||||||
|
</v-btn>
|
||||||
|
<v-btn @click="publish" prepend-icon="mdi-publish" color="success" v-if="false && object.id">{{ $l.publish
|
||||||
|
}}</v-btn>
|
||||||
|
</v-card-actions> -->
|
||||||
|
</v-card>
|
||||||
|
<SceneDesigner v-model="object"></SceneDesigner>
|
||||||
|
|
||||||
|
<div class="sceneDrawer" >
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import SceneDesigner from '@/components/SceneDesigner/SceneDesigner.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
object: {},
|
||||||
|
valid: false,
|
||||||
|
rules: {
|
||||||
|
required: v => v ? true : this.$l.fieldRequired,
|
||||||
|
requiredFile: v => (v?.length || this.id != 'add') ? true : this.$l.fieldRequired
|
||||||
|
},
|
||||||
|
loading: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
id() {
|
||||||
|
return this.$route.params?.id;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<template>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
+28
-2
@@ -23,10 +23,36 @@ const lang = {
|
|||||||
darkMode: 'Тъмен режим',
|
darkMode: 'Тъмен режим',
|
||||||
confirmDeletionOf: 'Потвърдете изтриването на',
|
confirmDeletionOf: 'Потвърдете изтриването на',
|
||||||
yes: 'Да',
|
yes: 'Да',
|
||||||
no: 'Не'
|
no: 'Не',
|
||||||
|
createScenario: 'Създаване на сценарий',
|
||||||
|
editScenario: 'Редкатиране на сценарий',
|
||||||
|
addScene: 'Добавяне на сцена'
|
||||||
},
|
},
|
||||||
en: {
|
en: {
|
||||||
|
createGameObject: 'Add game object',
|
||||||
|
editGameObject: 'Edit game object',
|
||||||
|
name: 'Name',
|
||||||
|
fieldRequired: 'Field is required',
|
||||||
|
objectType: 'Object type',
|
||||||
|
objectFile: 'File',
|
||||||
|
panorama2d: 'Panorama picture',
|
||||||
|
environment3d: 'Environment',
|
||||||
|
object3d: '3D object',
|
||||||
|
object2d: '2D object (picture)',
|
||||||
|
audio: 'Audio',
|
||||||
|
player3d: 'Player',
|
||||||
|
saveAndPreview: 'Save and preview',
|
||||||
|
preview: 'Preview',
|
||||||
|
captureThumbnail: 'Save thumbnail',
|
||||||
|
publish: 'Publish',
|
||||||
|
gameObjects: 'Objects',
|
||||||
|
gameScenarios: 'Scenarios',
|
||||||
|
gameRules: 'Rules',
|
||||||
|
games: 'Games',
|
||||||
|
darkMode: 'Dark mode',
|
||||||
|
confirmDeletionOf: 'Confirm deletion of',
|
||||||
|
yes: 'Yes',
|
||||||
|
no: 'No'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user