Files
core/hwe/ts/components/MapCityDetail.vue
T
Hide_D 14be16ce74 feat: Vue3로 작성된 지도 렌더러 (#216)
- 기존의 jQuery 기반 지도 렌더러를 Vue3로 재작성.
  - ajax로 호출하는 부분은 외부에서 처리하고, 다시 그리는 부분만 생성
  - 기능상으론 거의 동일.
- 일반 렌더러의 700px에, 500px모드용 모드 추가
  - 아이콘의 크기는 작아지지만, 글자 크기는 작아지지 않도록 조정

dep: vueuse, detect-it 추가

Reviewed-on: https://storage.hided.net/gitea/devsam/core/pulls/216
2022-04-20 03:34:12 +09:00

155 lines
3.3 KiB
Vue

<template>
<div
:class="['city_base', `city_base_${city.id}`, `city_level_${city.level}`]"
:style="cityPos"
@mouseenter="silent"
@mouseleave="silent"
>
<div
v-if="city.color"
class="city_bg"
:style="{
backgroundImage: `url(${imagePath}/b${city.color.substring(1).toUpperCase()}.png)`,
}"
></div>
<a
class="city_link"
:data-text="city.text"
:data-nation="city.nation"
:data-id="city.id"
:href="props.href"
:style="{
cursor: city.clickable ? 'pointer' : 'default',
}"
@click="clicked"
@touchend="touchend"
@mouseenter="mouseenter"
@mouseleave="mouseleave"
>
<div class="city_img">
<img :src="`${imagePath}/cast_${city.level}.gif`" />
<div :class="['city_filler', props.isMyCity ? 'my_city' : '']"></div>
<div v-if="city.nationID && city.nationID > 0" class="city_flag">
<img :src="`${imagePath}/${city.supply ? 'f' : 'd'}${city.color.substring(1).toUpperCase()}.gif`" />
<div v-if="city.isCapital" class="city_capital">
<img :src="`${imagePath}/event51.gif`" />
</div>
</div>
<span class="city_detail_name">{{ city.name }}</span>
</div>
<div v-if="city.state > 0" class="city_state">
<img :src="`${imagePath}/event${city.state}.gif`" />
</div>
</a>
</div>
</template>
<script lang="ts" setup>
import type { MapCityParsed } from "@/map";
import { ref, toRef, watch, type PropType } from "vue";
const emit = defineEmits<{
(event: "click", e: MouseEvent | TouchEvent): void;
(event: "mouseenter", e: MouseEvent): void;
(event: "mouseleave", e: MouseEvent): void;
}>();
const props = defineProps({
city: {
type: Object as PropType<MapCityParsed>,
required: true,
},
href: {
type: String,
default: undefined,
required: false,
},
isMyCity: {
type: Boolean,
required: false,
defeault: false,
},
imagePath: {
type: String,
required: true,
},
isFullWidth: {
type: Boolean,
required: true,
},
});
const city = toRef(props, "city");
const cityPos = ref({
left: "0px",
top: "0px",
});
watch(
() => props.isFullWidth,
(isFullWidth) => {
const { x, y } = city.value;
if (isFullWidth) {
cityPos.value = {
left: `${x - 20}px`,
top: `${y - 15}px`,
};
} else {
cityPos.value = {
left: `${(x * 5) / 7 - 20}px`,
top: `${(y * 5) / 7 - 18}px`,
};
}
},
{ immediate: true }
);
const imagePath = toRef(props, "imagePath");
function clicked(event: MouseEvent) {
emit("click", event);
}
function mouseenter(event: MouseEvent) {
event.stopPropagation();
emit("mouseenter", event);
}
function mouseleave(event: MouseEvent) {
event.stopPropagation();
emit("mouseleave", event);
}
function touchend(event: TouchEvent) {
event.stopPropagation();
emit("click", event);
}
function silent(event: MouseEvent) {
event.stopPropagation();
}
</script>
<style lang="scss" scoped>
.full_width_map{
a,
div,
img,
span {
line-height: 1.3;
font-size: 14px;
}
}
.small_width_map {
a,
div,
img {
line-height: 1.3;
font-size: 14px;
}
span {
line-height: 1.0;
font-size: 11px;
}
}
</style>