move object logic to composable
This commit is contained in:
parent
1cdf93c48f
commit
72dd514322
8 changed files with 239 additions and 239 deletions
102
src/App.vue
102
src/App.vue
|
@ -4,23 +4,10 @@
|
||||||
@select:font="setFont($event)"
|
@select:font="setFont($event)"
|
||||||
@select:theme="setTheme($event)"
|
@select:theme="setTheme($event)"
|
||||||
/>
|
/>
|
||||||
<SystemDiagram v-bind="{ star, objects, selectedObject }"
|
<SystemDiagram />
|
||||||
@select="selectObject"
|
|
||||||
@update="updateSelectedObject"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<section id="settings">
|
<section id="settings">
|
||||||
<ObjectSettings v-if="selectedObject"
|
<ObjectSettings v-if="selectedObject" />
|
||||||
v-model:name="selectedObject.name"
|
|
||||||
v-model:distance="selectedObject.distance"
|
|
||||||
v-model:type="selectedObject.type"
|
|
||||||
v-model:radius="selectedObject.radius"
|
|
||||||
v-model:rings="selectedObject.rings"
|
|
||||||
v-model:satellites="selectedObject.satellites"
|
|
||||||
:auto-name="autoName(selectedObject)"
|
|
||||||
@delete="deleteObject"
|
|
||||||
@close="editObject(null)"
|
|
||||||
/>
|
|
||||||
<Tips>
|
<Tips>
|
||||||
<li>Edit planets by clicking directly inside the graphic or in the table below.</li>
|
<li>Edit planets by clicking directly inside the graphic or in the table below.</li>
|
||||||
<li>Drag planets around to change their distance.</li>
|
<li>Drag planets around to change their distance.</li>
|
||||||
|
@ -28,8 +15,8 @@
|
||||||
<li>The last removed planet can be restored from the table.</li>
|
<li>The last removed planet can be restored from the table.</li>
|
||||||
<li><strong>ONLY THE LAST</strong> removed planet can be restored.</li>
|
<li><strong>ONLY THE LAST</strong> removed planet can be restored.</li>
|
||||||
</Tips>
|
</Tips>
|
||||||
<SystemSettings v-model:designation="star.designation" v-model:radius="star.radius" />
|
<SystemSettings />
|
||||||
<ObjectList v-bind="{ objects, deletedObject, addObject, editObject, deleteObject, restoreDeleted }" />
|
<ObjectList />
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
@ -43,89 +30,12 @@ import Tips from './components/Tips.vue'
|
||||||
import SystemSettings from './components/SystemSettings.vue'
|
import SystemSettings from './components/SystemSettings.vue'
|
||||||
import ObjectList from './components/ObjectList.vue'
|
import ObjectList from './components/ObjectList.vue'
|
||||||
import ObjectSettings from './components/ObjectSettings.vue'
|
import ObjectSettings from './components/ObjectSettings.vue'
|
||||||
import { MAX_DISTANCE_PLANET } from './constants'
|
import useObjects from './useObjects'
|
||||||
|
|
||||||
const star = reactive({
|
const { selectedObject } = useObjects()
|
||||||
designation: 'Sol',
|
|
||||||
radius: 400,
|
|
||||||
})
|
|
||||||
|
|
||||||
const objects = reactive(exampleData)
|
|
||||||
const labelFonts = ['xolonium', 'douar', 'lack']
|
const labelFonts = ['xolonium', 'douar', 'lack']
|
||||||
const themes = ['default', 'retro', 'inverse', 'paper']
|
const themes = ['default', 'retro', 'inverse', 'paper']
|
||||||
|
|
||||||
const selectedObject = ref(null)
|
|
||||||
const deletedObject = ref(null) // { index: Number, object: Object }
|
|
||||||
|
|
||||||
function addObject() {
|
|
||||||
const amount = objects.length
|
|
||||||
let distance = 100
|
|
||||||
|
|
||||||
if (amount) {
|
|
||||||
const lastObject = objects[amount - 1]
|
|
||||||
distance = Math.min(MAX_DISTANCE_PLANET, lastObject.distance + 2*lastObject.radius + 10)
|
|
||||||
}
|
|
||||||
|
|
||||||
objects.push({
|
|
||||||
type: 'planet',
|
|
||||||
name: `${star.designation}-${amount + 1}`,
|
|
||||||
radius: 1,
|
|
||||||
distance,
|
|
||||||
satellites: [],
|
|
||||||
rings: 0,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function editObject (object) {
|
|
||||||
if (object) {
|
|
||||||
document.documentElement.scrollTop = 0
|
|
||||||
document.body.scrollTop = 0
|
|
||||||
}
|
|
||||||
selectedObject.value = object
|
|
||||||
}
|
|
||||||
function selectObject (object) {
|
|
||||||
selectedObject.value = object
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateSelectedObject (payload) {
|
|
||||||
for (const key in payload) {
|
|
||||||
selectedObject.value[key] = payload[key]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function deleteObject (object) {
|
|
||||||
if (deletedObject.value) {
|
|
||||||
const lost = deletedObject.value.object.name
|
|
||||||
const confirmed = confirm(`
|
|
||||||
Attention! Only the LAST deleted object can be restored.
|
|
||||||
${lost} will be lost forever! Proceed anyway?`
|
|
||||||
)
|
|
||||||
if (!confirmed) return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!object) object = selectedObject.value
|
|
||||||
const index = objects.indexOf(object)
|
|
||||||
|
|
||||||
console.debug('deleting object at index', index)
|
|
||||||
|
|
||||||
if (index >= 0) objects.splice(index, 1)
|
|
||||||
if (object === selectedObject.value) selectedObject.value = null
|
|
||||||
|
|
||||||
deletedObject.value = { index, object }
|
|
||||||
}
|
|
||||||
|
|
||||||
function restoreDeleted () {
|
|
||||||
const { index, object } = deletedObject.value
|
|
||||||
console.debug('restoring deleted object', index)
|
|
||||||
objects.splice(index, 0, object)
|
|
||||||
deletedObject.value = null
|
|
||||||
}
|
|
||||||
|
|
||||||
function autoName (obj) {
|
|
||||||
const index = objects.indexOf(obj)
|
|
||||||
return `${star.designation}-${index}`
|
|
||||||
}
|
|
||||||
|
|
||||||
function setTheme (theme) {
|
function setTheme (theme) {
|
||||||
const classes = document.body.className.split(' ')
|
const classes = document.body.className.split(' ')
|
||||||
const currentTheme = classes.find(c => c.startsWith('theme-'))
|
const currentTheme = classes.find(c => c.startsWith('theme-'))
|
||||||
|
|
|
@ -210,6 +210,9 @@ h1 {
|
||||||
padding: .25em 1em;
|
padding: .25em 1em;
|
||||||
border-bottom: 2px solid var(--fg-app);
|
border-bottom: 2px solid var(--fg-app);
|
||||||
}
|
}
|
||||||
|
#object-list tr.selected {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
#object-list .cell {
|
#object-list .cell {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-around;
|
justify-content: space-around;
|
||||||
|
|
|
@ -4,14 +4,15 @@
|
||||||
<th scope="col" v-for="col in columns">{{ col }}</th>
|
<th scope="col" v-for="col in columns">{{ col }}</th>
|
||||||
<th scope="col">actions</th>
|
<th scope="col">actions</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr :class="{ deleted: i === deletedObject?.index }" v-for="o,i in objectList">
|
<tr v-for="o,i in objectList" :class="{ selected: o === selectedObject }">
|
||||||
<td v-for="value in values">
|
<td v-for="value in values">
|
||||||
<div class="cell">{{ o[value] }}</div>
|
<div class="cell">{{ o[value] }}</div>
|
||||||
</td>
|
</td>
|
||||||
<td><div class="cell">{{ o.satellites.length }}</div></td>
|
<td><div class="cell">{{ o.satellites.length }}</div></td>
|
||||||
<td><div class="cell">
|
<td><div class="cell">
|
||||||
<button class="settings" @click="editObject(o)"> </button>
|
<button class="settings" title="Configure Object" @click="editObject(o)"> </button>
|
||||||
<button class="delete" @click="deleteObject(o)"> </button>
|
<button class="dice" title="Randomize Object Values" @click="randomizeObject(o)"> </button>
|
||||||
|
<button class="delete" title="Delete Object" @click="deleteObject(o)"> </button>
|
||||||
</div></td>
|
</div></td>
|
||||||
<button v-if="i === deletedObject?.index"
|
<button v-if="i === deletedObject?.index"
|
||||||
class="deleted-overlay"
|
class="deleted-overlay"
|
||||||
|
@ -20,30 +21,41 @@
|
||||||
RESTORE DELETED OBJECT
|
RESTORE DELETED OBJECT
|
||||||
</button>
|
</button>
|
||||||
</tr>
|
</tr>
|
||||||
<button class="add" @click="addObject"> </button>
|
<button class="add" title="Add New Object" @click="addObject"> </button>
|
||||||
</table>
|
</table>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
|
import useObjects from '../useObjects'
|
||||||
|
|
||||||
const props = defineProps({
|
const {
|
||||||
objects: Array,
|
objects,
|
||||||
deletedObject: [Object, null],
|
selectedObject,
|
||||||
addObject: Function,
|
deletedObject,
|
||||||
editObject: Function,
|
addObject,
|
||||||
deleteObject: Function,
|
deleteObject,
|
||||||
restoreDeleted: Function,
|
restoreDeleted,
|
||||||
})
|
randomizeObject,
|
||||||
|
} = useObjects()
|
||||||
|
|
||||||
const columns = ['Δ', 'Name', 'Type', 'Radius', 'Rings', 'Satellites']
|
const columns = ['Δ', 'Name', 'Type', 'Radius', 'Rings', 'Satellites']
|
||||||
const values = ['distance', 'name', 'type', 'radius', 'rings']
|
const values = ['distance', 'name', 'type', 'radius', 'rings']
|
||||||
const objectList = computed(() => {
|
const objectList = computed(() => {
|
||||||
if (!props.deletedObject) return props.objects
|
if (!deletedObject.value) return objects
|
||||||
|
|
||||||
const { index, object } = props.deletedObject
|
const { index, object } = deletedObject.value
|
||||||
const objects = [ ...props.objects ]
|
const objects_ = [ ...objects ]
|
||||||
objects.splice(index, 0, object)
|
objects_.splice(index, 0, object)
|
||||||
return objects
|
return objects_
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function editObject (object) {
|
||||||
|
if (object) {
|
||||||
|
document.documentElement.scrollTop = 0
|
||||||
|
document.body.scrollTop = 0
|
||||||
|
}
|
||||||
|
selectedObject.value = object
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -8,51 +8,50 @@
|
||||||
<section class="main">
|
<section class="main">
|
||||||
<div>
|
<div>
|
||||||
<input type="text" class="big"
|
<input type="text" class="big"
|
||||||
:value="name"
|
:value="selectedObject.name"
|
||||||
@input="checkName($event.target.value)"
|
@input="update('name', $event.target.value)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
Distance Δ:
|
Distance Δ:
|
||||||
<input type="number" :min="MIN_DISTANCE_PLANET" :max="MAX_DISTANCE_PLANET"
|
<input type="number" :min="MIN_DISTANCE_PLANET" :max="MAX_DISTANCE_PLANET"
|
||||||
:value="distance"
|
:value="selectedObject.distance"
|
||||||
@input="update('distance', $event.target.value)"
|
@input="update('distance', $event.target.value)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
Radius r:
|
Radius r:
|
||||||
<input type="number" :min="MIN_SIZE_PLANET" :max="MAX_SIZE_PLANET"
|
<input type="number" :min="MIN_SIZE_PLANET" :max="MAX_SIZE_PLANET"
|
||||||
:value="radius"
|
:value="selectedObject.radius"
|
||||||
@input="update('radius', $event.target.value)"
|
@input="update('radius', $event.target.value)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
Rings:
|
Rings:
|
||||||
<input type="number" :min="MIN_AMOUNT_RINGS" :max="MAX_AMOUNT_RINGS"
|
<input type="number" :min="MIN_AMOUNT_RINGS" :max="MAX_AMOUNT_RINGS"
|
||||||
:value="rings"
|
:value="selectedObject.rings"
|
||||||
@input="update('rings', $event.target.value)"
|
@input="update('rings', $event.target.value)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<button class="close" title="close" @click="$emit('close')"> </button>
|
<button class="close" title="close" @click="close"> </button>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<SatelliteSettings :satellites="satellites" @update:satellites="update('satellites', $event)" />
|
<SatelliteSettings :satellites="selectedObject.satellites" @update:satellites="update('satellites', $event)" />
|
||||||
|
|
||||||
<section class="additional-options">
|
<section class="additional-options">
|
||||||
Other options:
|
Other options:
|
||||||
<button class="cta danger" @click="$emit('delete')">REMOVE OBJECT</button>
|
<button class="cta danger" @click="deleteObject()">REMOVE OBJECT</button>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed } from 'vue'
|
import { ref, computed } from 'vue'
|
||||||
|
import useObjects from '../useObjects'
|
||||||
import Tips from './Tips.vue'
|
import Tips from './Tips.vue'
|
||||||
import SatelliteSettings from './SatelliteSettings.vue'
|
import SatelliteSettings from './SatelliteSettings.vue'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
MIN_SIZE_STAR,
|
|
||||||
MAX_SIZE_STAR,
|
|
||||||
MIN_SIZE_PLANET,
|
MIN_SIZE_PLANET,
|
||||||
MAX_SIZE_PLANET,
|
MAX_SIZE_PLANET,
|
||||||
MIN_DISTANCE_PLANET,
|
MIN_DISTANCE_PLANET,
|
||||||
|
@ -61,36 +60,22 @@ import {
|
||||||
MAX_AMOUNT_RINGS,
|
MAX_AMOUNT_RINGS,
|
||||||
} from '../constants'
|
} from '../constants'
|
||||||
|
|
||||||
const props = defineProps({
|
const {
|
||||||
distance: Number,
|
selectedObject,
|
||||||
name: String,
|
deleteObject,
|
||||||
type: String,
|
updateSelectedObject,
|
||||||
radius: Number,
|
} = useObjects()
|
||||||
rings: Number,
|
|
||||||
satellites: Array,
|
|
||||||
autoName: String, // auto generated name, like Sol-3
|
|
||||||
})
|
|
||||||
const emit = defineEmits([
|
|
||||||
'update:distance',
|
|
||||||
'update:name',
|
|
||||||
'update:type',
|
|
||||||
'update:radius',
|
|
||||||
'update:rings',
|
|
||||||
'update:satellites',
|
|
||||||
'delete',
|
|
||||||
'close',
|
|
||||||
])
|
|
||||||
|
|
||||||
const numberTargets = ['distance', 'radius', 'rings']
|
const numberTargets = ['distance', 'radius', 'rings']
|
||||||
|
|
||||||
function update (target, value) {
|
function update (target, value) {
|
||||||
console.debug('updating', target, 'with', value)
|
console.debug('updating', target, 'with', value)
|
||||||
if (numberTargets.indexOf(target) >= 0) value = parseInt(value)
|
if (numberTargets.indexOf(target) >= 0) value = parseInt(value)
|
||||||
emit(`update:${target}`, value)
|
|
||||||
|
updateSelectedObject({ [target]: value })
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkName (name) {
|
function close () {
|
||||||
if (!name.trim().length) name = props.autoName
|
selectedObject.value = null
|
||||||
update('name', name)
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -34,26 +34,15 @@
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed } from 'vue'
|
import { ref, computed } from 'vue'
|
||||||
import { steepCurve } from '../utils'
|
import useObjects from '../useObjects'
|
||||||
import {
|
|
||||||
MIN_SIZE_PLANET,
|
|
||||||
MAX_SIZE_PLANET,
|
|
||||||
MIN_DISTANCE_PLANET,
|
|
||||||
MAX_DISTANCE_PLANET,
|
|
||||||
} from '../constants'
|
|
||||||
|
|
||||||
const props = defineProps({
|
const {
|
||||||
star: Object,
|
star,
|
||||||
objects: Array,
|
starCX,
|
||||||
selectedObject: Object,
|
objects,
|
||||||
})
|
selectedObject,
|
||||||
|
updateSelectedObject,
|
||||||
const emit = defineEmits([ 'select', 'update' ])
|
} = useObjects()
|
||||||
|
|
||||||
const starCX = computed(() => {
|
|
||||||
const r = props.star.radius
|
|
||||||
return -1 * r * steepCurve(r, 50, 0.955)
|
|
||||||
})
|
|
||||||
|
|
||||||
const draggedObject = ref(null)
|
const draggedObject = ref(null)
|
||||||
const draggingDelta = ref(0)
|
const draggingDelta = ref(0)
|
||||||
|
@ -69,12 +58,8 @@ function stopDragging (event) {
|
||||||
event.target.removeEventListener('pointerup', stopDragging)
|
event.target.removeEventListener('pointerup', stopDragging)
|
||||||
console.debug('stop draggin', draggedObject.value.name)
|
console.debug('stop draggin', draggedObject.value.name)
|
||||||
|
|
||||||
let distance = draggedObject.value.distance + draggingDelta.value
|
const distance = draggedObject.value.distance + draggingDelta.value
|
||||||
|
updateSelectedObject({ distance })
|
||||||
if (distance < MIN_DISTANCE_PLANET) distance = MIN_DISTANCE_PLANET
|
|
||||||
if (distance > MAX_DISTANCE_PLANET) distance = MAX_DISTANCE_PLANET
|
|
||||||
|
|
||||||
emit('update', { distance })
|
|
||||||
|
|
||||||
dragStart = 0
|
dragStart = 0
|
||||||
draggingDelta.value = 0
|
draggingDelta.value = 0
|
||||||
|
@ -88,8 +73,7 @@ function updateDelta (event) {
|
||||||
|
|
||||||
function startDragging (event, object) {
|
function startDragging (event, object) {
|
||||||
console.debug('start draggin', object.name)
|
console.debug('start draggin', object.name)
|
||||||
|
selectedObject.value = object
|
||||||
emit('select', object)
|
|
||||||
|
|
||||||
// we can savely assume that the windows width is not changing while dragging
|
// we can savely assume that the windows width is not changing while dragging
|
||||||
pixelFactor = 1000 / document.body.offsetWidth
|
pixelFactor = 1000 / document.body.offsetWidth
|
||||||
|
@ -104,23 +88,16 @@ function startDragging (event, object) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function resizeObject (event) {
|
function resizeObject (event) {
|
||||||
if (!props.selectedObject) return
|
if (!selectedObject.value) return
|
||||||
|
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
|
|
||||||
let radius = props.selectedObject.radius
|
let radius = selectedObject.value.radius
|
||||||
radius = radius + event.deltaY * -0.01
|
radius = radius + event.deltaY * -0.01
|
||||||
|
|
||||||
if (event.deltaY > 0) radius = Math.floor(radius)
|
if (event.deltaY > 0) radius = Math.floor(radius)
|
||||||
else radius = Math.ceil(radius)
|
else radius = Math.ceil(radius)
|
||||||
|
|
||||||
if (radius < MIN_SIZE_PLANET) radius = MIN_SIZE_PLANET
|
updateSelectedObject({ radius })
|
||||||
if (radius > MAX_SIZE_PLANET) radius = MAX_SIZE_PLANET
|
|
||||||
|
|
||||||
emit('update', { radius })
|
|
||||||
}
|
|
||||||
|
|
||||||
function onDragEnter (event) {
|
|
||||||
console.log('SystemDiagram onDragEnter', event)
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -4,20 +4,17 @@
|
||||||
<menu id="system-settings">
|
<menu id="system-settings">
|
||||||
<label>
|
<label>
|
||||||
Name
|
Name
|
||||||
<input type="text"
|
<input type="text" v-model="star.designation" />
|
||||||
:value="designation"
|
|
||||||
@input="update('designation', $event.target.value)"
|
|
||||||
/>
|
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
Star Size
|
Star Size
|
||||||
<input type="range"
|
<input type="range"
|
||||||
:min="MIN_SIZE_STAR"
|
:min="MIN_SIZE_STAR"
|
||||||
:max="MAX_SIZE_STAR"
|
:max="MAX_SIZE_STAR"
|
||||||
:value="radius"
|
:value="star.radius"
|
||||||
@input="update('radius', $event.target.value)"
|
@input="updateRadius($event.target.value)"
|
||||||
/>
|
/>
|
||||||
({{ radius }})
|
({{ star.radius }})
|
||||||
</label>
|
</label>
|
||||||
</menu>
|
</menu>
|
||||||
</header>
|
</header>
|
||||||
|
@ -25,22 +22,15 @@
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
|
import useObjects from '../useObjects'
|
||||||
import {
|
import {
|
||||||
MIN_SIZE_STAR,
|
MIN_SIZE_STAR,
|
||||||
MAX_SIZE_STAR,
|
MAX_SIZE_STAR,
|
||||||
} from '../constants'
|
} from '../constants'
|
||||||
|
|
||||||
const props = defineProps({
|
const { star } = useObjects()
|
||||||
designation: String,
|
|
||||||
radius: Number,
|
|
||||||
})
|
|
||||||
const emit = defineEmits([
|
|
||||||
'update:designation',
|
|
||||||
'update:radius',
|
|
||||||
])
|
|
||||||
|
|
||||||
function update (target, value) {
|
function updateRadius (radius) {
|
||||||
if (target === 'radius') value = parseInt(value)
|
star.radius = parseInt(radius)
|
||||||
emit(`update:${target}`, value)
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,38 +1,44 @@
|
||||||
export default [
|
export default {
|
||||||
{ type: 'planet', name: 'Mercury', radius: 1, distance: 100, satellites: [], rings: 0 },
|
star: {
|
||||||
{ type: 'planet', name: 'Venus', radius: 4, distance: 120, satellites: [], rings: 0 },
|
designation: 'Sol',
|
||||||
{ type: 'planet', name: 'Terra', radius: 4, distance: 140, satellites: [
|
radius: 400,
|
||||||
{ name: 'ISS', radius: 1, type: 'station' },
|
},
|
||||||
{ name: 'Luna', radius: 2, type: 'moon' },
|
objects: [
|
||||||
], rings: 0 },
|
{ type: 'planet', name: 'Mercury', designation: 'Sol-1', radius: 1, distance: 100, satellites: [], rings: 0 },
|
||||||
{ type: 'planet', name: 'Mars', radius: 2, distance: 160, satellites: [
|
{ type: 'planet', name: 'Venus', designation: 'Sol-2', radius: 4, distance: 120, satellites: [], rings: 0 },
|
||||||
{ name: 'MTO', radius: 1, type: 'station' },
|
{ type: 'planet', name: 'Terra', designation: 'Sol-3', radius: 4, distance: 140, satellites: [
|
||||||
{ name: 'Phobos', radius: 1, type: 'moon' },
|
{ name: 'ISS', radius: 1, type: 'station' },
|
||||||
{ name: 'Daimos', radius: 1, type: 'moon' },
|
{ name: 'Luna', radius: 2, type: 'moon' },
|
||||||
], rings: 0 },
|
], rings: 0 },
|
||||||
{ type: 'planet', name: 'Jupiter', radius: 40, distance: 260, satellites: [
|
{ type: 'planet', name: 'Mars', designation: 'Sol-4', radius: 2, distance: 160, satellites: [
|
||||||
{ name: 'Io', radius: 2, type: 'moon' },
|
{ name: 'MTO', radius: 1, type: 'station' },
|
||||||
{ name: 'Europa', radius: 2, type: 'moon' },
|
{ name: 'Phobos', radius: 1, type: 'moon' },
|
||||||
{ name: 'Ganymede', radius: 4, type: 'moon' },
|
{ name: 'Daimos', radius: 1, type: 'moon' },
|
||||||
{ name: 'Callisto', radius: 3, type: 'moon' },
|
], rings: 0 },
|
||||||
], rings: 1 },
|
{ type: 'planet', name: 'Jupiter', designation: 'Sol-5', radius: 40, distance: 260, satellites: [
|
||||||
{ type: 'planet', name: 'Saturn', radius: 36, distance: 410, satellites: [
|
{ name: 'Io', radius: 2, type: 'moon' },
|
||||||
{ name: 'Mimas', radius: 1, type: 'moon' },
|
{ name: 'Europa', radius: 2, type: 'moon' },
|
||||||
{ name: 'Enceladus', radius: 1, type: 'moon' },
|
{ name: 'Ganymede', radius: 4, type: 'moon' },
|
||||||
{ name: 'Tethys', radius: 1, type: 'moon' },
|
{ name: 'Callisto', radius: 3, type: 'moon' },
|
||||||
{ name: 'Dione', radius: 1, type: 'moon' },
|
], rings: 1 },
|
||||||
{ name: 'Rhea', radius: 1, type: 'moon' },
|
{ type: 'planet', name: 'Saturn', designation: 'Sol-6', radius: 36, distance: 410, satellites: [
|
||||||
{ name: 'Titan', radius: 3, type: 'moon' },
|
{ name: 'Mimas', radius: 1, type: 'moon' },
|
||||||
{ name: 'Iapetus', radius: 1, type: 'moon' },
|
{ name: 'Enceladus', radius: 1, type: 'moon' },
|
||||||
], rings: 5 },
|
{ name: 'Tethys', radius: 1, type: 'moon' },
|
||||||
{ type: 'planet', name: 'Uranus', radius: 16, distance: 680, satellites: [
|
{ name: 'Dione', radius: 1, type: 'moon' },
|
||||||
{ name: 'Miranda', radius: 1, type: 'moon' },
|
{ name: 'Rhea', radius: 1, type: 'moon' },
|
||||||
{ name: 'Ariel', radius: 1, type: 'moon' },
|
{ name: 'Titan', radius: 3, type: 'moon' },
|
||||||
{ name: 'Umbriel', radius: 1, type: 'moon' },
|
{ name: 'Iapetus', radius: 1, type: 'moon' },
|
||||||
{ name: 'Titania', radius: 1, type: 'moon' },
|
], rings: 5 },
|
||||||
{ name: 'Oberon', radius: 1, type: 'moon' },
|
{ type: 'planet', name: 'Uranus', designation: 'Sol-7', radius: 16, distance: 680, satellites: [
|
||||||
], rings: 2 },
|
{ name: 'Miranda', radius: 1, type: 'moon' },
|
||||||
{ type: 'planet', name: 'Neptune', radius: 15, distance: 950, satellites: [
|
{ name: 'Ariel', radius: 1, type: 'moon' },
|
||||||
{ name: 'Triton', radius: 1, type: 'moon' },
|
{ name: 'Umbriel', radius: 1, type: 'moon' },
|
||||||
], rings: 0 },
|
{ name: 'Titania', radius: 1, type: 'moon' },
|
||||||
]
|
{ name: 'Oberon', radius: 1, type: 'moon' },
|
||||||
|
], rings: 2 },
|
||||||
|
{ type: 'planet', name: 'Neptune', designation: 'Sol-8', radius: 15, distance: 950, satellites: [
|
||||||
|
{ name: 'Triton', radius: 1, type: 'moon' },
|
||||||
|
], rings: 0 },
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
117
src/useObjects.js
Normal file
117
src/useObjects.js
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
import { reactive, ref, computed } from 'vue'
|
||||||
|
import {
|
||||||
|
MIN_SIZE_STAR,
|
||||||
|
MAX_SIZE_STAR,
|
||||||
|
MIN_SIZE_PLANET,
|
||||||
|
MAX_SIZE_PLANET,
|
||||||
|
MIN_DISTANCE_PLANET,
|
||||||
|
MAX_DISTANCE_PLANET,
|
||||||
|
MIN_AMOUNT_RINGS,
|
||||||
|
MAX_AMOUNT_RINGS,
|
||||||
|
} from './constants'
|
||||||
|
import { steepCurve } from './utils'
|
||||||
|
import exampleData from './example-data.js'
|
||||||
|
|
||||||
|
|
||||||
|
const star = reactive(exampleData.star)
|
||||||
|
const objects = reactive(exampleData.objects)
|
||||||
|
const selectedObject = ref(null)
|
||||||
|
const deletedObject = ref(null) // { index: Number, object: Object }
|
||||||
|
|
||||||
|
const starCX = computed(() => {
|
||||||
|
const r = star.radius
|
||||||
|
return -1 * r * steepCurve(r, 50, 0.955)
|
||||||
|
})
|
||||||
|
|
||||||
|
export default function useObjects () {
|
||||||
|
|
||||||
|
function addObject() {
|
||||||
|
const amount = objects.length
|
||||||
|
let distance = 100
|
||||||
|
|
||||||
|
if (amount) {
|
||||||
|
const lastObject = objects[amount - 1]
|
||||||
|
distance = Math.min(MAX_DISTANCE_PLANET, lastObject.distance + 2*lastObject.radius + 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
objects.push({
|
||||||
|
type: 'planet',
|
||||||
|
name: `${star.designation}-${amount + 1}`,
|
||||||
|
radius: 1,
|
||||||
|
distance,
|
||||||
|
satellites: [],
|
||||||
|
rings: 0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateSelectedObject (payload) {
|
||||||
|
if (payload.name && !payload.name.trim().length) {
|
||||||
|
payload.name = selectedObject.value.designation
|
||||||
|
}
|
||||||
|
if (payload.distance) {
|
||||||
|
payload.distance = Math.max(MIN_DISTANCE_PLANET, payload.distance)
|
||||||
|
payload.distance = Math.min(MAX_DISTANCE_PLANET, payload.distance)
|
||||||
|
}
|
||||||
|
if (payload.radius) {
|
||||||
|
payload.radius = Math.max(MIN_SIZE_PLANET, payload.radius)
|
||||||
|
payload.radius = Math.min(MAX_SIZE_PLANET, payload.radius)
|
||||||
|
}
|
||||||
|
if (payload.rings) {
|
||||||
|
payload.rings = Math.max(MIN_AMOUNT_RINGS, payload.rings)
|
||||||
|
payload.rings = Math.min(MAX_AMOUNT_RINGS, payload.rings)
|
||||||
|
}
|
||||||
|
for (const key in payload) {
|
||||||
|
selectedObject.value[key] = payload[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteObject (object) {
|
||||||
|
if (deletedObject.value) {
|
||||||
|
const lost = deletedObject.value.object.name
|
||||||
|
const confirmed = confirm(`
|
||||||
|
Attention! Only the LAST deleted object can be restored.
|
||||||
|
${lost} will be lost forever! Proceed anyway?`
|
||||||
|
)
|
||||||
|
if (!confirmed) return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!object) object = selectedObject.value
|
||||||
|
const index = objects.indexOf(object)
|
||||||
|
|
||||||
|
console.debug('deleting object at index', index)
|
||||||
|
|
||||||
|
if (index >= 0) objects.splice(index, 1)
|
||||||
|
if (object === selectedObject.value) selectedObject.value = null
|
||||||
|
|
||||||
|
deletedObject.value = { index, object }
|
||||||
|
}
|
||||||
|
|
||||||
|
function restoreDeleted () {
|
||||||
|
const { index, object } = deletedObject.value
|
||||||
|
console.debug('restoring deleted object', index)
|
||||||
|
objects.splice(index, 0, object)
|
||||||
|
deletedObject.value = null
|
||||||
|
}
|
||||||
|
|
||||||
|
function autoName (object) {
|
||||||
|
const index = objects.indexOf(object)
|
||||||
|
return `${star.designation}-${index}`
|
||||||
|
}
|
||||||
|
|
||||||
|
function randomizeObject (object) {
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
star,
|
||||||
|
starCX,
|
||||||
|
objects,
|
||||||
|
selectedObject,
|
||||||
|
deletedObject,
|
||||||
|
addObject,
|
||||||
|
deleteObject,
|
||||||
|
updateSelectedObject,
|
||||||
|
restoreDeleted,
|
||||||
|
randomizeObject,
|
||||||
|
autoName,
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue