Bladeren bron

feat: 添加图标

bill 4 maanden geleden
bovenliggende
commit
7dd91e97cb

BIN
public/icons/m_add.png


File diff suppressed because it is too large
+ 1 - 0
public/icons/m_add.svg


BIN
public/icons/m_draw.png


File diff suppressed because it is too large
+ 1 - 0
public/icons/m_draw.svg


BIN
public/icons/m_move.png


File diff suppressed because it is too large
+ 1 - 0
public/icons/m_move.svg


BIN
public/icons/m_reduce.png


File diff suppressed because it is too large
+ 1 - 0
public/icons/m_reduce.svg


BIN
public/icons/m_zoom.png


File diff suppressed because it is too large
+ 1 - 0
public/icons/m_zoom.svg


File diff suppressed because it is too large
+ 1 - 0
public/icons/zoom_b.svg


File diff suppressed because it is too large
+ 1 - 0
public/icons/zoom_s.svg


+ 10 - 2
src/core/components/arrow/index.ts

@@ -1,5 +1,5 @@
 import { Pos } from "@/utils/math.ts";
-import { flatPositions, onlyId } from "@/utils/shared.ts";
+import { flatPositions, inRevise, onlyId } from "@/utils/shared.ts";
 import { ArrowConfig } from "konva/lib/shapes/Arrow";
 import { BaseItem, generateSnapInfos, getBaseItem } from "../util.ts";
 import { getMouseColors } from "@/utils/colors.ts";
@@ -80,7 +80,15 @@ export const interactiveToData: InteractiveTo<"arrow"> = ({
 };
 
 export const interactiveFixData: InteractiveFix<"arrow"> = ({ data, info }) => {
-  data.points = [...info.consumed, info.cur!];
+  // data.points = [...info.consumed, info.cur!];
+    const nv = [...info.consumed, info.cur!];
+    data.points.length = nv.length
+    for (let i = 0; i < nv.length; i++) {
+      if (inRevise(data.points[i], nv[i])) {
+        data.points[i] = nv[i]
+      }
+    }
+  
   return data;
 };
 

+ 12 - 3
src/core/components/polygon/index.ts

@@ -1,9 +1,10 @@
 import { Pos } from "@/utils/math.ts";
-import { themeColor, themeMouseColors } from "@/constant/help-style.ts";
+import { themeColor } from "@/constant/help-style.ts";
 import { BaseItem, generateSnapInfos, getBaseItem } from "../util.ts";
 import { getMouseColors } from "@/utils/colors.ts";
 import { InteractiveFix, InteractiveTo, MatResponseProps } from "../index.ts";
 import { Transform } from "konva/lib/Util";
+import { inRevise } from "@/utils/shared.ts";
 
 export { default as Component } from "./polygon.vue";
 export { default as TempComponent } from "./temp-polygon.vue";
@@ -19,7 +20,7 @@ export const defaultStyle = {
 export const getMouseStyle = (data: PolygonData) => {
   const fillStatus = data.fill && getMouseColors(data.fill);
   const strokeStatus = getMouseColors(data.stroke || themeColor);
-  const strokeWidth = data.strokeWidth;
+  const strokeWidth = data.strokeWidth || defaultStyle.strokeWidth;
 
   return {
     default: {
@@ -76,7 +77,15 @@ export const interactiveFixData: InteractiveFix<"polygon"> = ({
   data,
   info,
 }) => {
-  data.points = [...info.consumed, info.cur!];
+  // data.points = [...info.consumed, info.cur!];
+    const nv = [...info.consumed, info.cur!];
+    data.points.length = nv.length
+    for (let i = 0; i < nv.length; i++) {
+      if (inRevise(data.points[i], nv[i])) {
+        data.points[i] = nv[i]
+      }
+    }
+  
   return data;
 };
 

+ 6 - 4
src/core/components/share/edit-line.vue

@@ -2,7 +2,6 @@
   <v-line
     ref="line"
     :config="{
-      stroke: 'red',
       strokeWidth: data.strokeWidth,
       opacity: 0,
       points: flatPositions(points),
@@ -20,12 +19,15 @@ import { Line } from "konva/lib/shapes/Line";
 import { useShapeDrag } from "@/core/hook/use-transformer";
 import { useShapeIsHover } from "@/core/hook/use-mouse-status";
 import { useCursor } from "@/core/hook/use-global-vars";
-import { Pos } from "@/utils/math";
+import { lineCenter, Pos } from "@/utils/math";
 import { useCustomSnapInfos, useGlobalSnapInfos, useSnap } from "@/core/hook/use-snap";
 import { ComponentSnapInfo } from "..";
 import { generateSnapInfos } from "../util";
+import { getMouseColors } from "@/utils/colors";
+import { themeColor } from "@/constant/help-style";
+import { Circle } from "konva/lib/shapes/Circle";
 
-type LData = Required<Pick<LineData, "strokeWidth">>;
+type LData = Required<Pick<LineData, "strokeWidth" | "stroke">>;
 const props = defineProps<{
   data: LData;
   points: Pos[];
@@ -45,7 +47,7 @@ const [isHover] = useShapeIsHover(line);
 const cursor = useCursor();
 watch(isHover, (hover, _, onCleanup) => {
   if (hover) {
-    onCleanup(cursor.push("move"));
+    onCleanup(cursor.push("/icons/m_move.png"));
   }
 });
 const points = computed(() => {

+ 3 - 3
src/core/components/share/edit-point.vue

@@ -43,8 +43,8 @@ const style = computed(() => {
   const size = props.size || 5;
   return {
     radius: size / 2,
-    fill: color.disable,
-    stroke: color.press,
+    fill: "#fff",
+    stroke: color.pub,
     strokeWidth: size / 4,
     opacity: props.disable ? 0.5 : 1,
   };
@@ -93,7 +93,7 @@ const isHover = hResult[0];
 const cursor = useCursor();
 watch(isHover, (hover, _, onCleanup) => {
   if (hover) {
-    onCleanup(cursor.push("move"));
+    onCleanup(cursor.push("/icons/m_move.png"));
   }
 });
 

+ 9 - 0
src/core/components/share/edit-polygon.vue

@@ -18,6 +18,14 @@
         "
         @dragend="emit('update')"
       />
+      <EditSlitPoint
+        :data="data"
+        :points="data.points"
+        :id="data.id"
+        :ndx="ndx"
+        v-for="(_, ndx) in closed ? data.points.length : data.points.length - 1"
+        @dragend="emit('update')"
+      />
     </template>
   </v-group>
   <v-group>
@@ -41,6 +49,7 @@
 <script lang="ts" setup>
 import Point from "../share/edit-point.vue";
 import EditLine from "../share/edit-line.vue";
+import EditSlitPoint from "../share/edit-slit-point.vue";
 import { LineData } from "../line";
 import { DC, EntityShape } from "@/deconstruction.js";
 import { Pos } from "@/utils/math.ts";

+ 113 - 0
src/core/components/share/edit-slit-point.vue

@@ -0,0 +1,113 @@
+<template>
+  <v-circle :config="{ ...pointStyle, ...lineCenter(points) }" ref="point" />
+</template>
+
+<script lang="ts" setup>
+import { copy } from "@/utils/shared";
+import { LineData } from "../line";
+import { computed, ref, watch } from "vue";
+import { DC } from "@/deconstruction";
+import { useShapeDrag } from "@/core/hook/use-transformer";
+import { useShapeIsHover } from "@/core/hook/use-mouse-status";
+import { useCursor } from "@/core/hook/use-global-vars";
+import { lineCenter, Pos } from "@/utils/math";
+import { useCustomSnapInfos, useGlobalSnapInfos, useSnap } from "@/core/hook/use-snap";
+import { ComponentSnapInfo } from "..";
+import { generateSnapInfos } from "../util";
+import { getMouseColors } from "@/utils/colors";
+import { themeColor } from "@/constant/help-style";
+import { Circle } from "konva/lib/shapes/Circle";
+
+type LData = Required<Pick<LineData, "strokeWidth" | "stroke">>;
+
+const props = defineProps<{
+  data: LData;
+  points: Pos[];
+  id: string;
+  ndx: number;
+}>();
+
+const pointStyle = computed(() => {
+  const color = getMouseColors(props.data.stroke || themeColor);
+  const size = props.data.strokeWidth + 6 || 5;
+  return {
+    radius: size / 2,
+    fill: color.pub,
+  };
+});
+
+const emit = defineEmits<{
+  (e: "dragend"): void;
+  (e: "dragstart"): void;
+}>();
+
+const point = ref<DC<Circle>>();
+const offset = useShapeDrag(point);
+const [isHover] = useShapeIsHover(point);
+const cursor = useCursor();
+watch(isHover, (hover, _, onCleanup) => {
+  if (hover) {
+    onCleanup(cursor.push("/icons/m_add.png"));
+  }
+});
+const points = computed(() => {
+  return [props.points[props.ndx], props.points[(props.ndx + 1) % props.points.length]];
+});
+
+const infos = useCustomSnapInfos();
+const addedInfos = [] as ComponentSnapInfo[];
+const clearInfos = () => {
+  addedInfos.forEach(infos.remove);
+};
+const dragStartHandler = () => {
+  clearInfos();
+  const ndx = props.ndx;
+  const geos = [
+    props.points.slice(Number(ndx === props.points.length - 1), ndx),
+    props.points.slice(ndx + 2, props.points.length),
+  ];
+  if (ndx > 0 && ndx < props.points.length - 2) {
+    geos.push([props.points[ndx - 1], props.points[ndx + 2]]);
+  }
+  geos.forEach((geo) => {
+    const snapInfos = generateSnapInfos(geo, true, true, true);
+    snapInfos.forEach((item) => {
+      infos.add(item);
+      addedInfos.push(item);
+    });
+  });
+};
+const snapInfos = useGlobalSnapInfos();
+const refSnapInfos = computed(() => {
+  if (!props.id) {
+    return snapInfos.value;
+  } else {
+    return snapInfos.value.filter((p) => !("id" in p) || p.id !== props.id);
+  }
+});
+const snap = useSnap(refSnapInfos);
+
+let init: Pos[];
+watch(offset, (offset, oldOffsert) => {
+  snap.clear();
+  if (!oldOffsert) {
+    emit("dragstart");
+    init = copy(points.value);
+    dragStartHandler();
+  }
+  if (offset) {
+    const current = init.map((p) => ({
+      x: p.x + offset.x,
+      y: p.y + offset.y,
+    }));
+    const refSnapInfos = generateSnapInfos(current, true, true);
+    const transform = snap.move(refSnapInfos);
+    // emit("update:line", transform ? current.map((p) => transform.point(p)) : current);
+  } else {
+    clearInfos();
+    emit("dragend");
+  }
+});
+
+const slitPoint = ref<DC<Circle>>();
+</script>

+ 1 - 1
src/core/hook/use-alignment.ts

@@ -119,7 +119,7 @@ export const useJoinShapes = (
     const $stage = stage.value!.getNode();
     const dom = $stage.container();
     const points = drawLines(ref<(Pos | null)[]>(attribs.map(() => null)));
-    const cleanup = mergeFuns(cursor.push("crosshair"), mode.push(Mode.readonly)) 
+    const cleanup = mergeFuns(cursor.push("/icons/m_draw.png"), mode.push(Mode.readonly)) 
 
     for (let i = 0; i < attribs.length; i++) {
       const attrib = attribs[i];

+ 7 - 6
src/core/hook/use-draw.ts

@@ -343,7 +343,7 @@ export const useInteractiveDrawAreas = <T extends ShapeType>(type: T) => {
     useIA: useInteractiveAreas,
     refSelf: type === "arrow",
     enter() {
-      cursorPop = cursor.push("crosshair");
+      cursorPop = cursor.push("/icons/m_draw.png");
     },
     quit() {
       cursorPop && cursorPop();
@@ -358,7 +358,7 @@ export const useInteractiveDrawDots = <T extends ShapeType>(type: T) => {
     type,
     useIA: useInteractiveDots,
     enter() {
-      cursorPop = cursor.push(penA);
+      cursorPop = cursor.push("/icons/m_add.png");
     },
     quit() {
       cursorPop && cursorPop();
@@ -443,7 +443,7 @@ export const useInteractiveDrawPen = <T extends ShapeType>(type: T) => {
   });
 
   // 可能历史空间会撤销 重做更改到正在绘制的组件
-  const currentCursor = ref(penA);
+  const currentCursor = ref('/icons/m_add.png');
   const cursor = useCursor();
   let cursorPop: ReturnType<typeof cursor.push> | null = null;
   let stopWatch: (() => void) | null = null;
@@ -502,9 +502,10 @@ export const useInteractiveDrawPen = <T extends ShapeType>(type: T) => {
     currentCursor.value = penA;
     let pen: null | ReturnType<typeof penUpdatePoints> = null;
     if (!operMode.value.freeDraw) {
-      pen = penUpdatePoints(messages.value, cur, type !== "polygon");
-      consumed = pen.points;
-      cur = pen.cur;
+      // pen = penUpdatePoints(messages.value, cur, type !== "polygon");
+      // consumed = pen.points;
+      // cur = pen.cur;
+      
     }
 
     return {

+ 24 - 1
src/core/hook/use-global-vars.ts

@@ -19,9 +19,10 @@ import {
 import { Layer } from "konva/lib/Layer";
 import { Pos } from "@/utils/math.ts";
 import { listener } from "@/utils/event.ts";
-import { mergeFuns, onlyId } from "@/utils/shared.ts";
+import { debounce, mergeFuns, onlyId } from "@/utils/shared.ts";
 import { StoreData } from "../store/store.ts";
 import { rendererMap, rendererName } from "@/constant/index.ts";
+import { Shape, ShapeConfig } from "konva/lib/Shape";
 
 export const useRendererInstance = () => {
   let instance = getCurrentInstance()!;
@@ -210,6 +211,28 @@ export const usePointerPos = installGlobalVar(() => {
   };
 }, Symbol("pointerPos"));
 
+export const usePointerIntersections = installGlobalVar(() => {
+  const shapes = ref<Shape<ShapeConfig>[]>([])
+  const pos = usePointerPos()
+  const stage = useStage()
+  const updateShapes = debounce(() => {
+    if (!pos.value || !stage.value) {
+      return;
+    }
+    shapes.value = stage.value.getNode().getAllIntersections(pos.value) || []
+  }, 300)
+
+  const stopWatch =watch(pos, updateShapes)
+
+  return {
+    var: shapes,
+    onDestroy: () => {
+      stopWatch()
+      shapes.value = []
+    }
+  }
+})
+
 export const useDownKeys = installGlobalVar(() => {
   const keyKeys = reactive(new Set<string>());
   const mouseKeys = reactive(new Set<string>());

+ 38 - 12
src/core/hook/use-mouse-status.ts

@@ -4,6 +4,8 @@ import { Shape } from "konva/lib/Shape";
 import {
   globalWatch,
   installGlobalVar,
+  usePointerIntersections,
+  usePointerPos,
   useStage,
   useTransformIngShapes,
 } from "./use-global-vars.ts";
@@ -23,6 +25,7 @@ import { useStore } from "../store/index.ts";
 import { Group } from "konva/lib/Group";
 import { usePause } from "./use-pause.ts";
 import { lineLen, Pos } from "@/utils/math.ts";
+import { Util } from "konva/lib/Util";
 
 const stageHoverMap = new WeakMap<
   Stage,
@@ -53,7 +56,7 @@ export const getHoverShape = (stage: Stage) => {
     target.on(`pointerleave`, leaveHandler as any);
   };
 
-  const leaveHandler = () => {
+  const leaveHandler = (ev?: KonvaEventObject<any, Stage>) => {
     if (hover.value) {
       hover.value.off(`pointerleave`, leaveHandler);
       hover.value = undefined;
@@ -99,6 +102,32 @@ export const useShapeIsHover = (shape: Ref<DC<EntityShape> | undefined>) => {
   return result;
 };
 
+export const useMouseShapeIsHover = (
+  shape: Ref<DC<EntityShape> | undefined>
+) => {
+  const stage = useStage();
+  const hitShapes = usePointerIntersections();
+
+  const isHover = ref(false);
+  const stop = watch(
+    () => ({ stage: stage.value?.getNode(), shape: shape.value?.getNode() }),
+    ({ stage, shape }, _, onCleanup) => {
+      if (!stage || !shape || result.isPause) {
+        isHover.value = false;
+        return;
+      }
+
+      const stopHoverListener = watch(hitShapes, () => {
+        isHover.value = hitShapes.value.includes(shape as any);
+      });
+      onCleanup(mergeFuns([stopHoverListener, () => (isHover.value = false)]));
+    },
+    { immediate: true }
+  );
+  const result = usePause([isHover, stop] as const);
+  return result;
+};
+
 export const useShapeIsTransformerInner = () => {
   const transformer = useTransformer();
   const pointerIsTransformerInner = usePointerIsTransformerInner();
@@ -159,7 +188,6 @@ export const useMouseShapesStatus = installGlobalVar(() => {
       () => [hover.value, prevent.value],
       hoverChange
     );
-
     let downTime: number;
     let downPos: Pos | null = null;
     let downTarget: EntityShape | null;
@@ -364,6 +392,7 @@ export const useMouseStyle = <T extends ShapeType>(
   const mouseStyle = computed(() => {
     return props.getMouseStyle(props.data.value as any) as any;
   });
+
   const getStyle = () => {
     const styleMap = new Map([[mouseStyle.value.default, true]]);
     if ("hover" in mouseStyle.value) {
@@ -393,10 +422,7 @@ export const useMouseStyle = <T extends ShapeType>(
   };
   const style = ref();
   watchEffect(() => {
-    const newStyle = getStyle();
-    if (inRevise(newStyle, style.value)) {
-      style.value = newStyle;
-    }
+    style.value = getStyle();
   });
   return { currentStyle: style, status, shape };
 };
@@ -405,18 +431,18 @@ export const useAnimationMouseStyle = <T extends ShapeType>(
   props: MouseStyleProps<T>
 ) => {
   const { currentStyle, status } = useMouseStyle(props);
-  const [data, pauseAnimation, resumeAnimation] = useAniamtion(
-    currentStyle as any
-  );
+  // const [data, pauseAnimation, resumeAnimation] = useAniamtion(
+  //   currentStyle as any
+  // );
   return [
-    data,
+    currentStyle,
     () => {
-      pauseAnimation();
+      // pauseAnimation();
       status.value.pause();
     },
     () => {
       status.value.resume();
-      resumeAnimation();
+      // resumeAnimation();
     },
   ] as const;
 };

+ 5 - 5
src/core/hook/use-transformer.ts

@@ -3,6 +3,7 @@ import {  Ref, ref, toRaw, watch } from "vue";
 import { DC, EntityShape } from "../../deconstruction";
 import {
   installGlobalVar,
+  usePointerIntersections,
   useStage,
   useTransformIngShapes,
 } from "./use-global-vars.ts";
@@ -89,17 +90,17 @@ export const useTransformer = installGlobalVar(() => {
 export const usePointerIsTransformerInner = () => {
   const transformer = useTransformer();
   const stage = useStage();
+  const hitShapes = usePointerIntersections()
   return () => {
     const $stage = stage.value!.getStage();
     const pos = $stage.pointerPos;
     if (!pos) return false;
-    const hitShapes = $stage.getAllIntersections(pos);
-    if (!hitShapes.length) return false;
+    if (!hitShapes.value.length) return false;
     const selfShapes = [
       ...transformer.children,
       ...transformer.queueShapes.value.map(toRaw),
-    ];
-    for (const shape of hitShapes) {
+    ] as any;
+    for (const shape of hitShapes.value) {
       if (selfShapes.includes(shape)) return true;
     }
     return false;
@@ -196,7 +197,6 @@ export const useShapeDrag = (shape: Ref<DC<EntityShape> | undefined>) => {
         start = position;
         if (!can.dragMode) return;
         mode.add(Mode.draging);
-        console.log(shape)
         transformIngShapes.value.push(shape);
       }
     };

+ 2 - 2
src/core/renderer/renderer.vue

@@ -19,7 +19,7 @@
             <!--	不可去除,去除后移动端拖拽会有溢出	-->
             <BackGrid v-if="expose.config.showGrid" />
           </v-group>
-          <v-group :id="DataGroupId" >
+          <v-group :id="DataGroupId">
             <component
               :is="GroupComponentMap[type]"
               v-for="type in types"
@@ -137,7 +137,7 @@ const GroupComponentMap = types.reduce((map, type) => {
 const cursor = useCursor();
 const cursorStyle = computed(() => {
   if (cursor.value.includes(".")) {
-    return `url(${cursor.value}), auto`;
+    return `url(${cursor.value}) 12 12, auto`;
   } else {
     return cursor.value;
   }

+ 1 - 1
src/example/components/slide/actions.ts

@@ -36,7 +36,7 @@ export const draw: MenuItem = {
     { icon: "rectangle", ...genDrawItem("rectangle") },
     { icon: "circle", ...genDrawItem("circle") },
     { icon: "triangulartriangular", ...genDrawItem("triangle") },
-    // { icon: "", ...genDrawItem("polygon") },
+    { icon: "line", ...genDrawItem("polygon") },
   ],
 };
 

+ 1 - 1
src/example/dialog/vr/index.ts

@@ -1,6 +1,6 @@
 import { markRaw, reactive } from "vue";
 import VR from "./vr.vue";
-import { Scene } from "../../platform-resource";
+import { Scene } from "../../platform/platform-resource";
 
 type Props = {
   title: string;

+ 6 - 0
src/example/dialog/vr/vr.vue

@@ -62,6 +62,12 @@ const searchSenects = async (keyword: string) => {
   scenes.value = await getMeshSceneList(keyword);
   scenes.value.unshift(
     {
+      m: "SG-t-N6no657Kuze",
+      title: "mesh250个点位",
+      id: "-11",
+      type: SCENE_TYPE.mesh,
+    },
+    {
       m: "KK-t-ThCAj9SjuKB",
       title: "mesh250个点位",
       id: "-11",

+ 56 - 34
src/example/platform/platform-resource.ts

@@ -121,10 +121,16 @@ export const taggingGets = {
   },
   [SCENE_TYPE.mesh]: async (scene: Scene, options: string[]) => {
     const tags: Tagings = [];
-    if (options.includes("hot")) {
+    const prev = `/scene_view_data/${scene.m}`;
+    const config = await getSceneApi(scene.type, `${prev}/data/scene.json`)
+      .then((url) => fetch(url))
+      .then((res) => res.json())
+      .catch(() => ({ version: 0, billboards: 0, tags: 0 }));
+
+    if (options.includes("hot") && config.tags) {
       const medias = await getSceneApi(
         scene.type,
-        `/scene_view_data/${scene.m}/user/hot.json`
+        `${prev}/user/hot.json?_=${config.version}`
       )
         .then((url) => fetch(url))
         .then((res) => res.json())
@@ -134,7 +140,7 @@ export const taggingGets = {
         if (!validNum(media.position.x) || !validNum(media.position.y)) return;
         return getSceneApi(
           scene.type,
-          `/scene_view_data/KK-t-ThCAj9SjuKB/user/${media.icon}`
+          `${prev}/user/${media.icon}`
           // `/v4-test/www/sdk/images/tag/${media.icon}`
         )
           .then((url) => {
@@ -146,10 +152,10 @@ export const taggingGets = {
       await Promise.all(reqs);
     }
 
-    if (options.includes("signage")) {
+    if (options.includes("signage") && config.billboards) {
       const signages = await getSceneApi(
         scene.type,
-        `/scene_view_data/${scene.m}/user/billboards.json`
+        `${prev}/user/billboards.json?_=${config.version}`
       )
         .then((url) => fetch(url))
         .then((res) => res.json())
@@ -157,10 +163,7 @@ export const taggingGets = {
 
       signages.forEach((signage: any) => {
         if (!validNum(signage.pos.x) || !validNum(signage.pos.y)) return;
-        return getSceneApi(
-          scene.type,
-          `/v4-test/www/sdk/images/billboard/${signage.icon}.png`
-        )
+        return getSceneApi(scene.type, `${prev}/user/${signage.icon}.png`)
           .then((url) => {
             tags.push({ url, position: signage.pos });
           })
@@ -197,32 +200,51 @@ export const lineGets = {
     return { name: "1楼", geos: [tags.map((item) => item.position)] };
   },
   [SCENE_TYPE.mesh]: async (scene: Scene) => {
-    const { floors } = await getSceneApi(
-      scene.type,
-      `/scene_view_data/${scene.m}/data/floorplan_cad.json?_=${Date.now()}`
-    )
-      .then((url) => fetch(url))
-      .then((res) => res.json())
-      .catch(() => ({ floors: [] }));
-    const data = floors.map((floor: any) => ({
-      name: floor.name,
-      thumb: `https://4dkk.4dage.com/scene_view_data/${scene.m}/images/floor_${floor.id}.png`,
-      box: {
-        bound: {
-          ...floor.cadInfo.cadBoundingBox,
-          y_min: -floor.cadInfo.cadBoundingBox.y_max,
-          y_max: -floor.cadInfo.cadBoundingBox.y_min,
+    const prev = `/scene_view_data/${scene.m}/data/`;
+    const [{ floors }, bounds] = await Promise.all([
+      getSceneApi(scene.type, `${prev}floorplan_cad.json?_=${Date.now()}`)
+        .then((url) => fetch(url))
+        .then((res) => res.json())
+        .catch(() => ({ floors: [] })),
+      getSceneApi(scene.type, `${prev}floorplan/info.json`)
+        .then((url) => fetch(url))
+        .then((res) => res.json())
+        .then((data) => data.floors)
+        .catch(() => []),
+    ]);
+
+    const data: any = [];
+
+    const reqs = floors.map((floor: any, ndx: number) => {
+      const bound = {
+        ...(floor.cadInfo.cadBoundingBox || {}),
+        ...(bounds[ndx]?.bound || {}),
+      };
+      const item: any = {
+        name: floor.name,
+        thumb: "",
+        box: {
+          bound: {
+            ...bound,
+            y_min: -bound.y_max,
+            y_max: -bound.y_min,
+          },
+          rotate: floor.cadInfo.res,
+          scale: floor.cadInfo.currentScale,
         },
-        rotate: floor.cadInfo.res,
-        scale: floor.cadInfo.currentScale,
-      },
-      geos: extractConnectedSegments(floor.segment).map((geo) => {
-        return geo.map((id) => {
-          const p = floor["vertex-xy"].find((item: any) => item.id === id);
-          return { x: p.x, y: -p.y } as Pos;
-        })
-      }),
-    }));
+        geos: extractConnectedSegments(floor.segment).map((geo) => {
+          return geo.map((id) => {
+            const p = floor["vertex-xy"].find((item: any) => item.id === id);
+            return { x: p.x, y: -p.y } as Pos;
+          });
+        }),
+      };
+      data.push(item);
+      return getSceneApi(scene.type, `${prev}floorplan/floor_${floor.subgroup}.png`)
+        .then((url) => (item.thumb = url))
+        .catch(() => (item.thumb = ""));
+    });
+    await Promise.all(reqs);
     return data;
   },
   [SCENE_TYPE.cloud]: async (scene: Scene) => {