feat(wip): 순수 vue3로 작성하는 지도 모듈
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
<template>
|
||||
<div
|
||||
:class="['city_base', `city_base_${city.id}`, `city_level_${city.level}`]"
|
||||
:style="{
|
||||
left: `${city.x - 20}px`,
|
||||
top: `${city.y - 15}px`,
|
||||
}"
|
||||
>
|
||||
<a
|
||||
class="city_link"
|
||||
:data-text="city.text"
|
||||
:data-nation="city.nation"
|
||||
:data-id="city.id"
|
||||
:href="props.href"
|
||||
@click="clicked"
|
||||
>
|
||||
<div
|
||||
class="city_img"
|
||||
:style="{
|
||||
backgroundColor: city.color,
|
||||
}"
|
||||
>
|
||||
<div :class="['city_filler', props.isMyCity ? 'my_city' : '']"></div>
|
||||
<div v-if="city.state > 0" :class="['city_state', `city_state_${getCityState()}`]"></div>
|
||||
<div v-if="city.nationID && city.nationID > 0" class="city_flag">
|
||||
<div v-if="city.isCapital" class="city_capital"></div>
|
||||
</div>
|
||||
<span class="city_detail_name">{{ city.name }}</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { MapCityParsed } from "@/map";
|
||||
import { toRef, type PropType } from "vue";
|
||||
const emit = defineEmits<{
|
||||
(event: "click", evnet: 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,
|
||||
},
|
||||
});
|
||||
const city = toRef(props, "city");
|
||||
|
||||
function getCityState(): string {
|
||||
const state = city.value.state;
|
||||
if (state < 10) {
|
||||
return "good";
|
||||
}
|
||||
if (state < 40) {
|
||||
return "bad";
|
||||
}
|
||||
if (state < 50) {
|
||||
return "war";
|
||||
}
|
||||
return "wrong";
|
||||
}
|
||||
|
||||
function clicked(event: MouseEvent) {
|
||||
emit("click", event);
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,76 @@
|
||||
<template>
|
||||
<div
|
||||
:class="['city_base', `city_base_${city.id}`, `city_level_${city.level}`]"
|
||||
:style="{
|
||||
left: `${city.x - 20}px`,
|
||||
top: `${city.y - 15}px`,
|
||||
}"
|
||||
>
|
||||
<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"
|
||||
@click="clicked"
|
||||
>
|
||||
<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 { toRef, type PropType } from "vue";
|
||||
const emit = defineEmits<{
|
||||
(event: "click", evnet: 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,
|
||||
},
|
||||
});
|
||||
const city = toRef(props, "city");
|
||||
const imagePath = toRef(props, "imagePath");
|
||||
|
||||
function clicked(event: MouseEvent) {
|
||||
emit("click", event);
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,621 @@
|
||||
<template>
|
||||
<div
|
||||
:id="uuid"
|
||||
:class="[
|
||||
'world_map',
|
||||
`map_theme_${mapTheme}`,
|
||||
drawableMap ? '' : 'draw_required',
|
||||
props.isDetailMap ? 'map_detail' : 'map_basic',
|
||||
getMapSeasonClassName(),
|
||||
]"
|
||||
>
|
||||
<div
|
||||
v-my-tooltip.hover.top="{
|
||||
class: 'map_title_tooltiptext',
|
||||
}"
|
||||
class="map_title"
|
||||
:title="getTitleTooltip()"
|
||||
>
|
||||
<span class="map_title_text" :style="{ color: getTitleColor() }"
|
||||
>{{ mapResult?.year }}年 {{ mapResult?.month }}月</span
|
||||
>
|
||||
<span class="tooltiptext" />
|
||||
</div>
|
||||
<div class="map_body">
|
||||
<div class="map_bglayer1" />
|
||||
<div class="map_bglayer2" />
|
||||
<div class="map_bgroad" />
|
||||
<div class="map_button_stack">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary map_toggle_cityname btn-sm btn-minimum"
|
||||
data-bs-toggle="button"
|
||||
aria-pressed="false"
|
||||
autocomplete="off"
|
||||
>
|
||||
도시명 표기</button
|
||||
><br />
|
||||
<button
|
||||
v-if="deviceType != 'mouseOnly'"
|
||||
type="button"
|
||||
class="btn btn-secondary map_toggle_single_tap btn-sm btn-minimum"
|
||||
data-bs-toggle="button"
|
||||
aria-pressed="false"
|
||||
autocomplete="off"
|
||||
>
|
||||
두번 탭 해 도시 이동
|
||||
</button>
|
||||
</div>
|
||||
<template v-if="drawableMap === undefined"><!--로딩중?--></template>
|
||||
<template v-else-if="props.isDetailMap">
|
||||
<MapCityDetail
|
||||
v-for="city of drawableMap.cityList"
|
||||
:key="city.id"
|
||||
:city="city"
|
||||
:image-path="imagePath"
|
||||
:is-my-city="city.id === drawableMap.myCity"
|
||||
@click="emit('city-click', city, $event)"
|
||||
/>
|
||||
</template>
|
||||
<template v-else
|
||||
><MapCityBasic
|
||||
v-for="city of drawableMap.cityList"
|
||||
:key="city.id"
|
||||
:city="city"
|
||||
:is-my-city="city.id === drawableMap.myCity"
|
||||
@click="emit('city-click', city, $event)"
|
||||
/></template>
|
||||
</div>
|
||||
<div class="city_tooltip">
|
||||
<div class="city_name" />
|
||||
<div class="nation_name" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export type MapCityParsedRaw = {
|
||||
id: number;
|
||||
level: number;
|
||||
state: number;
|
||||
nationID?: number;
|
||||
region: number;
|
||||
supply: boolean;
|
||||
};
|
||||
|
||||
type MapCityParsedName = MapCityParsedRaw & {
|
||||
name: string;
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
|
||||
type MapCityParsedNation = MapCityParsedName & {
|
||||
nationID?: number;
|
||||
nation?: string;
|
||||
color?: string;
|
||||
isCapital: boolean;
|
||||
};
|
||||
|
||||
type MapCityParsedClickable = MapCityParsedNation & {
|
||||
clickable: number;
|
||||
};
|
||||
|
||||
type MapCityParsedRegionLevelText = MapCityParsedClickable & {
|
||||
region_str: string;
|
||||
level_str: string;
|
||||
text: string;
|
||||
};
|
||||
|
||||
export type MapCityParsed = MapCityParsedRegionLevelText;
|
||||
|
||||
type MapCityDrawable = {
|
||||
cityList: MapCityParsed[];
|
||||
myCity?: number;
|
||||
};
|
||||
|
||||
type MapNationParsed = {
|
||||
id: number;
|
||||
name: string;
|
||||
color: string;
|
||||
capital: number;
|
||||
};
|
||||
|
||||
export type CityPositionMap = {
|
||||
[cityID: number]: [string, number, number];
|
||||
};
|
||||
</script>
|
||||
<script lang="ts" setup>
|
||||
import "@/../css/map.css";
|
||||
import type { loadMapOption } from "@/map";
|
||||
import { type PropType, toRef, inject, type Ref, ref, watch } from "vue";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import type { MapResult } from "@/defs";
|
||||
import { joinYearMonth } from "@/util/joinYearMonth";
|
||||
import { parseYearMonth } from "@/util/parseYearMonth";
|
||||
import vMyTooltip from "@/directives/vMyTooltip";
|
||||
import type { GameConstStore } from "@/GameConstStore";
|
||||
import { unwrap_err } from "@/util/unwrap_err";
|
||||
import { getMaxRelativeTechLevel, TECH_LEVEL_YEAR_GAP } from "@/utilGame/techLevel";
|
||||
import { deviceType } from "detect-it";
|
||||
import { unwrap } from "@/util/unwrap";
|
||||
import MapCityBasic from "./MapCityBasic.vue";
|
||||
import MapCityDetail from "./MapCityDetail.vue";
|
||||
import { convertDictById } from "@/common_legacy";
|
||||
const uuid = uuidv4();
|
||||
const gameConstStore = unwrap_err(
|
||||
inject<Ref<GameConstStore>>("gameConstStore"),
|
||||
Error,
|
||||
"gameConstStore가 주입되지 않았습니다."
|
||||
);
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: "city-click", city: MapCityParsed, e: MouseEvent): void;
|
||||
(event: "parsed", drawable: MapCityDrawable): void;
|
||||
}>();
|
||||
|
||||
const props = defineProps({
|
||||
serverNick: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
serverID: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
imagePath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
mapName: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
isDetailMap: { type: Boolean, default: undefined, required: false },
|
||||
clickableAll: { type: Boolean, default: undefined, required: false },
|
||||
hrefTemplate: { type: String, default: "#", required: false },
|
||||
/// clickable, 소속 국가, 첩보 여부 등을 반환여부를 설정
|
||||
neutralView: { type: Boolean, default: false, required: false },
|
||||
///반환 값에 본인이 위치한 도시 값을 반환하도록 설정. neutralView와 별개
|
||||
showMe: { type: Boolean, default: true, required: false },
|
||||
|
||||
callback: {
|
||||
type: Function as PropType<loadMapOption["callback"]>,
|
||||
default: undefined,
|
||||
},
|
||||
startYear: { type: Number, default: undefined, required: false },
|
||||
|
||||
cityPosition: {
|
||||
type: Object as PropType<CityPositionMap>,
|
||||
required: true,
|
||||
},
|
||||
formatCityInfo: {
|
||||
type: Function as PropType<(city: MapCityParsed) => MapCityParsed>,
|
||||
required: true,
|
||||
},
|
||||
|
||||
modelValue: {
|
||||
type: Object as PropType<MapResult>,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const mapResult = toRef(props, "modelValue");
|
||||
|
||||
const mapTheme = toRef(props, "mapName");
|
||||
function getTitleColor(): string | undefined {
|
||||
const { startYear, year } = mapResult.value;
|
||||
|
||||
if (year < startYear + 1) {
|
||||
return "magenta";
|
||||
}
|
||||
if (year < startYear + 2) {
|
||||
return "orange";
|
||||
}
|
||||
if (year < startYear + 3) {
|
||||
return "yellow";
|
||||
}
|
||||
}
|
||||
|
||||
const drawableMap = ref<MapCityDrawable>(convertCityObjs(props.modelValue));
|
||||
|
||||
function getBeginGameLimitTooltip(): string | undefined {
|
||||
const { startYear, year, month } = mapResult.value;
|
||||
if (year > startYear + 3) return undefined;
|
||||
|
||||
const [remainYear, remainMonth] = parseYearMonth(joinYearMonth(startYear + 3, 0) - joinYearMonth(year, month));
|
||||
|
||||
return `초반제한 기간 : ${remainYear}년${remainMonth > 0 ? ` ${remainMonth}개월` : ""} (${startYear + 3}년)`;
|
||||
}
|
||||
|
||||
function getTitleTooltip(): string {
|
||||
const result: string[] = [];
|
||||
const beginLimit = getBeginGameLimitTooltip();
|
||||
if (beginLimit) {
|
||||
result.push(beginLimit);
|
||||
}
|
||||
|
||||
const { startYear, year } = mapResult.value;
|
||||
|
||||
const maxTechLevel = gameConstStore.value.gameConst.maxTechLevel;
|
||||
const currentTechLimit = getMaxRelativeTechLevel(startYear, year, maxTechLevel);
|
||||
|
||||
if (currentTechLimit == maxTechLevel) {
|
||||
result.push(`기술등급 제한 : ${currentTechLimit}등급 (최종)`);
|
||||
} else {
|
||||
const nextTechLimitYear = currentTechLimit * TECH_LEVEL_YEAR_GAP + startYear;
|
||||
result.push(`기술등급 제한 : ${currentTechLimit}등급 (${nextTechLimitYear}년 해제)`);
|
||||
}
|
||||
|
||||
return result.join("<br>");
|
||||
}
|
||||
|
||||
function getMapSeasonClassName(): string {
|
||||
const { month } = mapResult.value;
|
||||
|
||||
if (month <= 3) {
|
||||
return "map_spring";
|
||||
}
|
||||
if (month <= 6) {
|
||||
return "map_summer";
|
||||
}
|
||||
if (month <= 9) {
|
||||
return "map_fall";
|
||||
}
|
||||
return "map_winter";
|
||||
}
|
||||
|
||||
function convertCityObjs(obj: MapResult): MapCityDrawable {
|
||||
//원본 Obj는 굉장히 간소하게 온다, Object 형태로 변환해서 사용한다.
|
||||
|
||||
function toCityObj([id, level, state, nationID, region, supply]: MapResult["cityList"][0]): MapCityParsedRaw {
|
||||
return {
|
||||
id: id,
|
||||
level: level,
|
||||
state: state,
|
||||
nationID: nationID > 0 ? nationID : undefined,
|
||||
region: region,
|
||||
supply: supply != 0,
|
||||
};
|
||||
}
|
||||
|
||||
function toNationObj([id, name, color, capital]: MapResult["nationList"][0]): MapNationParsed {
|
||||
return {
|
||||
id,
|
||||
name,
|
||||
color,
|
||||
capital,
|
||||
};
|
||||
}
|
||||
|
||||
const nationList = convertDictById(obj.nationList.map(toNationObj)); //array of object -> dict
|
||||
|
||||
const spyList = obj.spyList;
|
||||
const shownByGeneralList = new Set(obj.shownByGeneralList);
|
||||
|
||||
const myCity = obj.myCity;
|
||||
const myNation = obj.myNation;
|
||||
|
||||
function mergePositionInfo(city: MapCityParsedRaw): MapCityParsedName {
|
||||
const id = city.id;
|
||||
if (!(id in props.cityPosition)) {
|
||||
throw TypeError(`알수 없는 cityID: ${id}`);
|
||||
}
|
||||
const [name, x, y] = props.cityPosition[id];
|
||||
|
||||
return {
|
||||
...city,
|
||||
name,
|
||||
x,
|
||||
y,
|
||||
};
|
||||
}
|
||||
|
||||
function mergeNationInfo(city: MapCityParsedName): MapCityParsedNation {
|
||||
//nationID 값으로 isCapital, color, nation을 통합
|
||||
|
||||
const nationID = city.nationID;
|
||||
if (nationID === undefined || !(nationID in nationList)) {
|
||||
return {
|
||||
...city,
|
||||
isCapital: false,
|
||||
};
|
||||
}
|
||||
|
||||
const nationObj = nationList[nationID];
|
||||
return {
|
||||
...city,
|
||||
nation: nationObj.name,
|
||||
color: nationObj.color,
|
||||
isCapital: nationObj.capital == city.id,
|
||||
};
|
||||
}
|
||||
|
||||
function mergeClickable(city: MapCityParsedNation): MapCityParsedClickable {
|
||||
//clickable = (defaultCity << 4 ) | (remainSpy << 3) | (ourCity << 2) | (shownByGeneral << 1) | clickableAll
|
||||
const id = city.id;
|
||||
const nationID = city.nationID;
|
||||
let clickable = 16;
|
||||
if (id in spyList) {
|
||||
clickable |= spyList[id] << 3;
|
||||
}
|
||||
if (myNation !== null && nationID == myNation) {
|
||||
clickable |= 4;
|
||||
}
|
||||
if (shownByGeneralList.has(id)) {
|
||||
clickable |= 2;
|
||||
}
|
||||
if (myCity !== null && id == myCity) {
|
||||
clickable |= 2;
|
||||
}
|
||||
if (props.clickableAll) {
|
||||
clickable |= 1;
|
||||
}
|
||||
|
||||
return {
|
||||
...city,
|
||||
clickable,
|
||||
};
|
||||
}
|
||||
|
||||
const cityList = obj.cityList
|
||||
.map(toCityObj)
|
||||
.map(mergePositionInfo)
|
||||
.map(mergeNationInfo)
|
||||
.map(mergeClickable)
|
||||
.map(window.formatCityInfo);
|
||||
|
||||
const result = {
|
||||
cityList: cityList,
|
||||
myCity: myCity,
|
||||
};
|
||||
emit("parsed", result);
|
||||
|
||||
return result;
|
||||
}
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(mapInfo) => {
|
||||
drawableMap.value = convertCityObjs(mapInfo);
|
||||
}
|
||||
);
|
||||
/*
|
||||
function setMouseWork(obj: MapCityDrawable) {
|
||||
initTooltip($(drawTarget));
|
||||
|
||||
const $tooltip = $(drawTarget + " .city_tooltip");
|
||||
const $tooltip_city = $tooltip.find(".city_name");
|
||||
const $tooltip_nation = $tooltip.find(".nation_name");
|
||||
|
||||
const $objs = $(drawTarget + " .city_link");
|
||||
|
||||
const $map_body = $(drawTarget + " .map_body");
|
||||
|
||||
//터치스크린 탭
|
||||
|
||||
if (!option.neutralView && is_touch_device()) {
|
||||
$objs.on("touchstart", function () {
|
||||
if (window.sam_toggleSingleTap) {
|
||||
return true;
|
||||
}
|
||||
const $this = $(this);
|
||||
|
||||
const touchMode = $this.data("touchMode") as number;
|
||||
if ($tooltip_city.data("target") != $this.data("id")) {
|
||||
$this.data("touchMode", 1);
|
||||
} else if (touchMode === undefined) {
|
||||
$this.data("touchMode", 1);
|
||||
} else {
|
||||
$this.data("touchMode", touchMode + 1);
|
||||
}
|
||||
$map_body.data("touchMode", 1);
|
||||
|
||||
$tooltip_city.data("target", $this.data("id"));
|
||||
});
|
||||
|
||||
$objs.on("touchend", function () {
|
||||
if (window.sam_toggleSingleTap) {
|
||||
return true;
|
||||
}
|
||||
const $this = $(this);
|
||||
const position = $this.parent().position();
|
||||
$tooltip_city.html($this.data("text") as string);
|
||||
|
||||
const nation_text = $this.data("nation") as string;
|
||||
if (nation_text) {
|
||||
$tooltip_nation.html(nation_text).show();
|
||||
} else {
|
||||
$tooltip_nation.html("").hide();
|
||||
}
|
||||
|
||||
const left = position.left;
|
||||
const top = position.top;
|
||||
|
||||
const tooltipWidth = unwrap($tooltip.width());
|
||||
|
||||
if (left + tooltipWidth + 35 > window.innerWidth) {
|
||||
$tooltip.css({ top: top + 45, left: left - tooltipWidth - 10 }).show();
|
||||
} else {
|
||||
$tooltip.css({ top: top + 45, left: left + 35 }).show();
|
||||
}
|
||||
|
||||
const touchMode = $this.data("touchMode") as number;
|
||||
if (touchMode <= 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//xxx: touchend 다음 click 이벤트가 갈 수도 있고, 안 갈 수도 있다.
|
||||
$this.data("touchMode", 0);
|
||||
});
|
||||
|
||||
$map_body.on("touchend", function () {
|
||||
if (window.sam_toggleSingleTap) {
|
||||
return true;
|
||||
}
|
||||
//위의 touchend bind에 해당하지 않는 경우 -> 빈 지도 터치
|
||||
$tooltip.hide();
|
||||
});
|
||||
}
|
||||
|
||||
//Mouse over 모드 작동
|
||||
|
||||
$map_body.on("mousemove", function (e) {
|
||||
if ($(this).data("touchMode")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const rect = this.getBoundingClientRect();
|
||||
const left = e.clientX - rect.left - this.clientLeft + this.scrollLeft;
|
||||
const top = e.clientY - rect.top - this.clientTop + this.scrollTop;
|
||||
|
||||
const tooltipWidth = unwrap($tooltip.width());
|
||||
|
||||
if (e.clientX + rect.left + tooltipWidth + 10 > window.innerWidth) {
|
||||
$tooltip.css({ top: top + 30, left: left - tooltipWidth - 10 });
|
||||
} else {
|
||||
$tooltip.css({ top: top + 30, left: left + 10 });
|
||||
}
|
||||
});
|
||||
|
||||
$objs.on("mouseenter", function () {
|
||||
if ($map_body.data("touchMode")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const $this = $(this);
|
||||
|
||||
$tooltip_city.data("target", $this.data("id"));
|
||||
$tooltip_city.html($this.data("text"));
|
||||
const nation_text = $this.data("nation");
|
||||
if (nation_text) {
|
||||
$tooltip_nation.html(nation_text).show();
|
||||
} else {
|
||||
$tooltip_nation.html("").hide();
|
||||
}
|
||||
|
||||
$tooltip.show();
|
||||
});
|
||||
|
||||
$objs.on("mouseleave", function () {
|
||||
$tooltip.hide();
|
||||
});
|
||||
|
||||
$objs.on("click", function () {
|
||||
//xxx: touchend 다음 click 이벤트가 갈 수도 있고, 안 갈 수도 있다.
|
||||
const touchMode = $(this).data("touchMode") as number | undefined;
|
||||
if (touchMode === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (touchMode === 1) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
function setCityClickable(obj: MapCityDrawable) {
|
||||
obj.cityList.forEach(function (city) {
|
||||
const $cityLink = $world_map.find(`.city_base_${city.id} .city_link`);
|
||||
|
||||
if ("clickable" in city && city.clickable > 0) {
|
||||
$cityLink.attr("href", stringFormat(hrefTemplate, city.id));
|
||||
}
|
||||
|
||||
if (selectCallback) {
|
||||
$cityLink.on("click", function (e) {
|
||||
e.preventDefault();
|
||||
return selectCallback(city);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
async function reloadWorldMap(option: loadMapOption, drawTarget = ".world_map"): Promise<void> {
|
||||
const $world_map = $(drawTarget);
|
||||
|
||||
const defaultOption: loadMapOption = {
|
||||
isDetailMap: true, //복잡 지도, 단순 지도
|
||||
clickableAll: false, //어떤 경우든 클릭을 가능하게 함. 해당 동작의 동작 가능성 여부와는 별도.
|
||||
selectCallback: undefined, //callback을 지정시 clickable과 관계 없이 해당 함수를 실행.
|
||||
hrefTemplate: "#", //도시가 클릭가능할 경우 지정할 href값. {0}은 도시 id로 변환됨
|
||||
|
||||
//아래부터는 post query에 들어갈 녀석
|
||||
year: undefined, //year값, 연감등에 사용
|
||||
month: undefined, //month값, 연감등에 사용
|
||||
neutralView: false, //clickable, 소속 국가, 첩보 여부 등을 반환여부를 설정
|
||||
showMe: true, //반환 값에 본인이 위치한 도시 값을 반환하도록 설정. neutralView와 별개
|
||||
|
||||
callback: undefined,
|
||||
|
||||
//기타 보조 값
|
||||
startYear: undefined,
|
||||
};
|
||||
|
||||
const isDetailMap = props.isDetailMap ?? true;
|
||||
const clickableAll = props.clickableAll ?? false;
|
||||
const selectCallback = props.selectCallback;
|
||||
const hrefTemplate = props.hrefTemplate;
|
||||
|
||||
const cityPosition = window.getCityPosition();
|
||||
|
||||
const storedOldMapKey = `sam.${props.serverNick}.map`;
|
||||
const storedStartYear = `sam.${props.serverNick}.startYear`;
|
||||
//OBJ : startYear, year, month, cityList, nationList, spyList, shownByGeneralList, myCity
|
||||
|
||||
const $hideCityNameBtn = $world_map.find(".map_toggle_cityname");
|
||||
if (localStorage.getItem("sam.hideMapCityName") == "yes") {
|
||||
$world_map.addClass("hide_cityname");
|
||||
$hideCityNameBtn.addClass("active").attr("aria-pressed", "true");
|
||||
}
|
||||
|
||||
$hideCityNameBtn.on("click", function () {
|
||||
//이전 상태 확인
|
||||
const state = localStorage.getItem("sam.hideMapCityName") == "no";
|
||||
if (state) {
|
||||
$world_map.addClass("hide_cityname");
|
||||
localStorage.setItem("sam.hideMapCityName", "yes");
|
||||
} else {
|
||||
$world_map.removeClass("hide_cityname");
|
||||
localStorage.setItem("sam.hideMapCityName", "no");
|
||||
}
|
||||
});
|
||||
|
||||
const $toggleSingleTapBtn = $world_map.find(".map_toggle_single_tap");
|
||||
if (localStorage.getItem("sam.toggleSingleTap") == "yes") {
|
||||
window.sam_toggleSingleTap = true;
|
||||
$toggleSingleTapBtn.addClass("active").attr("aria-pressed", "true");
|
||||
} else {
|
||||
window.sam_toggleSingleTap = false;
|
||||
}
|
||||
|
||||
const $map_body = $(drawTarget + " .map_body");
|
||||
|
||||
$toggleSingleTapBtn.on("click", function () {
|
||||
//이전 상태 확인
|
||||
const state = localStorage.getItem("sam.toggleSingleTap") == "no";
|
||||
if (state) {
|
||||
$map_body.removeData("touchMode");
|
||||
localStorage.setItem("sam.toggleSingleTap", "yes");
|
||||
window.sam_toggleSingleTap = true;
|
||||
} else {
|
||||
localStorage.setItem("sam.toggleSingleTap", "no");
|
||||
window.sam_toggleSingleTap = false;
|
||||
}
|
||||
});
|
||||
|
||||
const computedResult = await convertCityObjs(rawObject)
|
||||
.then(isDetailMap ? drawDetailWorldMap : drawBasicWorldMap)
|
||||
.then(setMouseWork)
|
||||
.then(setCityClickable);
|
||||
|
||||
if (option.callback) {
|
||||
option.callback(computedResult, rawObject);
|
||||
}
|
||||
}
|
||||
*/
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
Reference in New Issue
Block a user