Prechádzať zdrojové kódy

Merge branch 'dev' of http://124.70.149.18:10880/lianghj/queenshow into dev

qinyan 1 rok pred
rodič
commit
c7ac89dd1e
31 zmenil súbory, kde vykonal 1031 pridanie a 193 odobranie
  1. 1 0
      package.json
  2. 1 0
      src/assets/imgs/add.svg
  3. 9 3
      src/modules/editor/components/CompUI/basicUI/Container/component.tsx
  4. 1 1
      src/modules/editor/components/CompUI/basicUI/Curve/component.tsx
  5. 5 1
      src/modules/editor/components/CompUI/basicUI/Page/PageForm.tsx
  6. 25 12
      src/modules/editor/components/CompUI/basicUI/Page/component.tsx
  7. 5 1
      src/modules/editor/components/CompUI/basicUI/Page/index.ts
  8. 35 0
      src/modules/editor/components/CompUI/basicUI/Page/screen.tsx
  9. 96 3
      src/modules/editor/components/CompUI/basicUI/View.tsx
  10. 1 0
      src/modules/editor/components/CompUI/basicUI/hooks.ts
  11. 135 67
      src/modules/editor/components/Viewport/Content/index.tsx
  12. 3 1
      src/modules/editor/controllers/AnimCtrl/index.ts
  13. 1 2
      src/modules/editor/controllers/CropperCtrl/index.ts
  14. 13 0
      src/modules/editor/controllers/CtxMenuCtrl/index.ts
  15. 165 0
      src/modules/editor/controllers/EditorCtrl/index.ts
  16. 76 0
      src/modules/editor/controllers/ReactCtrl/history.ts
  17. 143 0
      src/modules/editor/controllers/ReactCtrl/rxValue.ts
  18. 98 0
      src/modules/editor/controllers/ScreenCtrl/index.ts
  19. 14 0
      src/modules/editor/controllers/SelectCtrl/ObjsContainer.ts
  20. 18 22
      src/modules/editor/controllers/SelectCtrl/assistCtrl.ts
  21. 7 7
      src/modules/editor/controllers/SelectCtrl/assistMagnetCtrl.ts
  22. 1 1
      src/modules/editor/controllers/SelectCtrl/assistRulerCtrl.ts
  23. 98 48
      src/modules/editor/controllers/SelectCtrl/index.ts
  24. 12 7
      src/modules/editor/controllers/TransformCtrl/index.ts
  25. 10 3
      src/modules/editor/module/actions/edit.tsx
  26. 19 0
      src/modules/editor/module/actions/init.ts
  27. 8 1
      src/modules/editor/module/helpers/index.ts
  28. 10 1
      src/modules/editor/module/index.ts
  29. 11 6
      src/modules/editor/module/stores/index.ts
  30. 3 6
      src/modules/editor/objects/DesignTemp/creates/createCompStyle.ts
  31. 7 0
      yarn.lock

+ 1 - 0
package.json

@@ -72,6 +72,7 @@
     "queen3d": "^0.0.80",
     "queenjs": "^1.0.0-beta.77",
     "rimraf": "^3.0.2",
+    "rxjs": "^7.8.1",
     "scp2": "^0.5.0",
     "swiper": "^8.4.4",
     "three": "^0.146.0",

+ 1 - 0
src/assets/imgs/add.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" viewBox="0 0 80 80"><defs><style>.a{fill:#1f1f1f;}.b{fill:none;stroke:#fff;stroke-linecap:round;stroke-linejoin:round;stroke-width:2px;}</style></defs><g transform="translate(-1489 -385)"><rect class="a" width="80" height="80" rx="4" transform="translate(1489 385)"/><g transform="translate(1514.754 410.754)"><path class="b" d="M24,16V33.666" transform="translate(-9.754 -10.587)"/><path class="b" d="M16,24H33.666" transform="translate(-10.587 -9.754)"/></g></g></svg>

+ 9 - 3
src/modules/editor/components/CompUI/basicUI/Container/component.tsx

@@ -1,25 +1,31 @@
 import { defineComponent } from "vue";
-import { string } from "vue-types";
+import { bool, string } from "vue-types";
 import { useCompData } from ".";
 import { useEditor } from "../../../..";
 import { DesignComp } from "../../../../objects/DesignTemp/DesignComp";
 import { View } from "../View";
 import { CompUI } from "../..";
 import { SelectTransfer } from "../Transfer/select";
+import { sortedArray } from "three/src/animation/AnimationUtils";
 
 export const Component = defineComponent({
   props: {
     compId: string().isRequired,
+    showMask: bool().def(false)
   },
   setup(props) {
     const { helper, controls , store} = useEditor();
     const { children } = useCompData(props.compId);
+
+    const isStreamCard = helper.isStreamCard(props.compId);
+
+    
     return () => (
-      <View compId={props.compId}>
+      <View compId={props.compId} showMask={props.showMask}>
         {children.default?.map((compId) => {
           const compItem = helper.findComp(compId) as DesignComp;
           const Comp =
-            controls.compUICtrl.state.components.get(compItem.compKey)
+            controls.compUICtrl.state.components.get(compItem?.compKey)
               ?.Component || CompUI.Container.Component;
 
           return <Comp key={compItem.id} compId={compItem.id} />;

+ 1 - 1
src/modules/editor/components/CompUI/basicUI/Curve/component.tsx

@@ -221,7 +221,7 @@ export const Component = defineComponent({
                 
                 const isDragingIndex = ret.pIndex;
 
-                const box = controls.selectCtrl.getCurrCardBox();
+                const box = controls.selectCtrl.getCurrCardViewPortBox();
 
                 const mvingPoint = !ret.clickCurve && !ret.clickLine
                 let initControlpLen :number | undefined = undefined;

+ 5 - 1
src/modules/editor/components/CompUI/basicUI/Page/PageForm.tsx

@@ -8,6 +8,7 @@ import { PageMusic } from "./PageMusic";
 import { Select } from "ant-design-vue";
 import { MusicOptions } from "./localMusic";
 import { css } from "@linaria/core";
+import screen from "./screen";
 const styleColumns = (muisc?: string): ColumnItem[] => {
   return [
     {
@@ -39,6 +40,9 @@ const styleColumns = (muisc?: string): ColumnItem[] => {
       component: PageMusic,
       isVisible: (value, data) => data?.value?.music != "" && muisc != "",
     },
+    {
+      component: screen,
+    }
   ];
 };
 export const PageForm = defineComponent({
@@ -59,7 +63,7 @@ export const PageForm = defineComponent({
 
       return (
         <div class={formStyle}>
-          <div class="text-white">页面样式</div>
+          <div class="text-white">作品属性</div>
           <FormUI
             data={props.component}
             columns={styleColumns(curValue?.value || "")}

+ 25 - 12
src/modules/editor/components/CompUI/basicUI/Page/component.tsx

@@ -13,7 +13,7 @@ export const Component = defineComponent({
   },
   setup(props, { slots }) {
     const editor = useEditor();
-    const { helper, store } = editor;
+    const { helper, store, controls } = editor;
     const compRef = useCompRef(props.compId);
 
   
@@ -31,29 +31,42 @@ export const Component = defineComponent({
       }
 
       let contextStyle:any = null;
-      if (store.rootPage.value.pageMode == "short") {
+      if (store.rootPage.value.pageMode == "short" && !store.isEditMode) {
         contextStyle = { transform: `translate(0, ${ -store.shortPage.index * window.innerHeight + store.shortPage.offset}px`};
         if (!store.shortPage.isMoving) {
           contextStyle.transition = "transform .4s ease-out";
         }
       }
-      
+      console.log("curr card=>", store.currStreamCardId, store.currStreamCard?.children.default?.length);
+
       return (
         <div
           ref={compRef}
           style={style}
           class={[comp.value.pageMode != "short" && "!h-auto", editor.store.isEditMode ? pageEditStyle : ""]}
         >
-          <div class="relative z-999" style={contextStyle}>
-            {slots.Container?.(
-              children.default.map((compId) => {
-                const comp = helper.findComp(compId);
-                if (!comp) return;
-                return slots.CompItem?.(comp);
-              })
-            )}
-            {curValue?.value && !editor.store.isEditMode && <PageMusic />}
+          {
+             store.isDisplay && <div class="relative z-1000" style={contextStyle}>
+             {slots.Container?.(
+               children.default.map((compId) => {
+                 const comp = helper.findComp(compId);
+                 if (!comp) return;
+                 return slots.CompItem?.(comp);
+               })
+             )}
+             {curValue?.value && !editor.store.isEditMode && <PageMusic />}
+           </div>
+ 
+          }
+          {
+            store.isEditMode && store.currStreamCard && <div class="relative z-1000" style={contextStyle}>
+            {
+              slots.Container?.( [slots.CompItem?.(store.currStreamCard)])
+            }
           </div>
+
+          }
+
         </div>
       );
     };

+ 5 - 1
src/modules/editor/components/CompUI/basicUI/Page/index.ts

@@ -10,7 +10,11 @@ export const options = {
 };
 
 export const { createComp, useCompData } = createCompHooks({
-  value: {},
+  value: {
+    useFor: "mobile",
+    pageMode: "long",
+    pageSizeType: "normal"
+  },
   children: {
     default: () => [] as string[],
   },

+ 35 - 0
src/modules/editor/components/CompUI/basicUI/Page/screen.tsx

@@ -0,0 +1,35 @@
+import { useEditor } from "@/modules/editor"
+import { Select } from "ant-design-vue"
+import { defineComponent } from "vue"
+
+export default defineComponent({
+    setup(props, ctx) {
+        const editor = useEditor();
+        const ctrl = editor.controls.screenCtrl;
+        
+        return ()=>{
+            return (
+                <div class="px-16px">
+                    <div class="flex items-center">
+                        <span class="w-70px">屏幕类型</span>
+                        <Select value={ctrl.state.useFor} onChange={(v)=>{
+                            ctrl.state.setUseFor(v as any);
+                        }} class = "flex-1 overflow-hidden" options={[{ label: "手机", value: "mobile" }, { label: "PC", value: "pc" }]}  />
+                    </div>
+                    <div  class="flex items-center mt-5px">
+                        <span class="w-70px">页面模式</span>
+                        <Select onChange={(v)=>{
+                            ctrl.state.setPageMode(v as any);
+                        }} value={ctrl.state.pageMode} class = "flex-1 overflow-hidden" options={[{ label: "长页", value: "long" }, { label: "翻页", value: "short" }]}  />
+                    </div>
+                    <div  class="flex items-center mt-5px">
+                        <span class="w-70px">屏幕长度</span>
+                        <Select onChange={(v)=>{
+                            ctrl.state.setPageSizeType(v as any);
+                        }} value={ctrl.state.pageSizeType} class = "flex-1 overflow-hidden" options={[{ label: "短屏幕", value: "short" }, { label: "普通屏幕", value: "normal"},  { label: "长屏幕", value: "long"}]}  />
+                    </div>
+                </div>
+            )
+        }
+    },
+})

+ 96 - 3
src/modules/editor/components/CompUI/basicUI/View.tsx

@@ -13,6 +13,7 @@ export const View = defineComponent({
   props: {
     compId: string().isRequired,
     editlayer: bool().def(true),
+    showMask: bool().def(false),
   },
   emits: ["dblclick", "click"],
   setup(props, { slots, emit }) {
@@ -56,6 +57,49 @@ export const View = defineComponent({
           style.transition = "all 1s ease-out";
       }
 
+      function RenderPre() {
+        if ( store.currStreamCardId != props.compId || !isStreamCard || !store.isEditMode  ) return;
+          let i = store.streamCardIds.indexOf(props.compId);
+          if (i>0) {
+             const c = helper.findComp(store.streamCardIds[i-1]) as DesignComp;
+             const PreComp = controls.compUICtrl.state.components.get(c.compKey) as any
+             return (<div class="absolute w-full h-150px" style={{
+                bottom: style.height
+             }}>
+                  <div class="absolute w-full h-150px pointer-events-none overflow-hidden">
+                    <PreComp.Component compId={c.id}  key={c.id} style={{position: "absolute", bottom: "0"}} />
+                  </div>
+                   <div class={maskStyleUp}></div>
+                    <div class={[divideStyle, "bottom"]} >
+                      <span class="tip">上一页分割线</span>
+                    </div>
+
+             </div> );
+          }
+      }
+  
+      function RenderAfter() {
+        if (store.currStreamCardId != props.compId || !isStreamCard || !store.isEditMode) return 
+  
+        let i = store.streamCardIds.indexOf(props.compId);
+        if (i < store.streamCardIds.length-1 ) {
+          const c = helper.findComp(store.streamCardIds[i+1]) as DesignComp;
+          const AfterComp = controls.compUICtrl.state.components.get(c.compKey) as any;
+          return (<div class="relative"> 
+
+              <div class="h-150px pointer-events-none overflow-hidden">
+                  <AfterComp.Component compId={c.id}  key={c.id} />
+              </div>
+        
+             <div class={maskStyle}></div>
+             <div class={[divideStyle, "top"]} >
+                <span class="tip">下一页分割线</span>
+             </div>
+           </div>);
+        }
+      }
+
+      
       return (
         <div
           ref={compRef}
@@ -77,6 +121,7 @@ export const View = defineComponent({
           }}
           onDblclick={() => emit("dblclick")}
         >
+          
           <div
             onMousemove={(e) => {
               if (
@@ -91,15 +136,21 @@ export const View = defineComponent({
             {slots.default?.()}
           </div>
 
-          {store.isEditMode &&
+          {/* {store.isEditMode &&
             isStreamCard &&
             store.currStreamCardId == props.compId && (
               <Hudop compId={props.compId} />
-            )}
+            )} */}
 
           {store.isEditMode && props.editlayer && (
             <div ref={editorLayerRef} class={editAreaStyle}></div>
           )}
+          {
+             props.showMask && RenderPre()
+          }
+          {
+            props.showMask && RenderAfter()
+          }
         </div>
       );
     };
@@ -189,10 +240,11 @@ const AnchorCompStyle = css`
 const CurrCompStyle = css`
   position: relative;
   outline: 1px solid @inf-primary-color;
-  box-shadow: 0 0 0 3000px rgba(0, 0, 0, 0.5);
   z-index: 998;
 `;
 
+//box-shadow: 0 0 0 3000px rgba(0, 0, 0, 0.5);
+
 const groupCompCls = css`
   outline: 2px solid @inf-primary-color !important;
 `;
@@ -214,3 +266,44 @@ const editAreaTestStyle = css`
   height: 100px;
   background-color: red;
 `;
+const maskStyle = css`
+  background: rgba(0,0,0,0.3);  
+  position: absolute;
+  left: 0;
+  top: 0;
+  width: 100%;
+  height: 100%;
+`
+
+const maskStyleUp = css`
+  background: rgba(0,0,0,0.3);
+  position: absolute;
+  left: 0;
+  top: 0;
+  width: 100%;
+  height: 100%;
+`
+
+const divideStyle = css`
+  position: absolute;
+  left: -10%;
+  width: 120%;
+  border: 1px dashed #E54729;
+  border-dasharray: 5px 10px;
+
+  &.top {
+    top: 0;
+  }
+
+  &.bottom {
+    bottom: 0;
+  }
+  .tip {
+    font-size: 12px;
+    position: absolute;
+    left: 100%;
+    width: 80px;
+    top: -10px;
+    color: #EB684E;
+  }
+`

+ 1 - 0
src/modules/editor/components/CompUI/basicUI/hooks.ts

@@ -9,6 +9,7 @@ export function useCompRef(compId: string) {
   provide("compParentId", compId);
   store.setCompPid(compId, parentId);
 
+  
   onMounted(() => {
     const comp = helper.findComp(compId);
     if (comp) {

+ 135 - 67
src/modules/editor/components/Viewport/Content/index.tsx

@@ -9,6 +9,7 @@ import { CompUI } from "../../CompUI";
 
 import { SelectTransfer } from "../../CompUI/basicUI/Transfer/select";
 import { TipIcons } from "../../TipIcons";
+import { IconDelete } from "@/assets/icons";
 
 export default defineUI({
   setup() {
@@ -28,11 +29,11 @@ export default defineUI({
     const NotFoundComp = () => <div>无效的组件</div>;
     const flagRef = ref();
     const containRef = ref();
-    const selectCanvasRef = ref();
-    const viewportRef = ref();
     controls.cropCtrl.modifyCtrl.toolbars = TipIcons;
     const editLayerRef = ref();
 
+    const refs = controls.editorCtrl.useEditor();
+
     return () => {
       const pageRoot = helper.findRootComp();
       if (!pageRoot) return;
@@ -44,74 +45,97 @@ export default defineUI({
         setTimeout(() => {
           actions.onViewReady(
             pageRoot.$el,
-            selectCanvasRef.value,
-            viewportRef.value
+            refs.canvas.value,
+            refs.parent.value,
           );
           helper.initEditLayer(editLayerRef.value);
-        }, 0);
+        }, 100);
       }
 
       return (
-        <div class="scrollbar overflow-y-auto flex-1" ref={viewportRef}>
-          <div class="relative">
-            <div class={"w-375px my-60px mx-auto select-none " + contentCls}>
+        <div class="flex flex-1 relative">
+       
+            <div class={["scrollbar", cardList]}>
+                <div>
+                <Container  onDrop={(e: any) => {
+                            if (e.payload) {
+                              actions.addCompToDesign(e.payload, e.addedIndex);
+                            } else {
+                              actions.moveComp(e.removedIndex, e.addedIndex);
+                            }
+                  }} >
+                {
+                  store.streamCardIds.map(item=>{
+                    const c = helper.findComp(item) as DesignComp;
+                    const Comp = controls.compUICtrl.state.components.get(c.compKey)
+                      ?.Component || NotFoundComp;
+                  
+                    const r = c.layout.size[1] / c.layout.size[0];
+                    let h = (80 * r);
+                    if (h>80) h = 80;
+                    if (h <40 ) h = 40;
+
+                    const style:any = {height:h+ "px"}
+                    if (store.currStreamCardId == item) {
+                      style.border = "3px solid #EA9E40"
+                    }
+                  return (<Draggable>
+                      <div key={item} class={["card-item relative transition-opacity hover:opacity-80"]} style={style} onClick={()=>{
+                          actions.pickComp(item, false);
+                      }}>
+                          <IconDelete onClick={()=>{
+                             actions.removeStreamCard(item);
+                          }} class="deleteitem absolute right-4px top-4px text-black" />
+
+                          <Comp compId={c.id} style={{transformOrigin:"0 0", pointerEvent:"none", transform: `scale(${80.0 / helper.designSizeToPx(c.layout.size[0])})`}} />
+                      </div>
+                    </Draggable>)
+                  })
+                }
+                <img class="mt-15px cursor-pointer" onClick={()=>{
+                      const index = store.streamCardIds.length;
+                      actions.addCompToDesign("Container", index);
+                }} src={require("@/assets/imgs/add.svg")} alt="" />
+                </Container>
+              </div>
+          </div>
+        <div ref={refs.parent} class={["absolute", viewportStyle]}>
+          <div ref={refs.editor}>
+            <div ref={refs.page}  class={"select-none " + contentCls}>
               <CompUI.Page.Component compId={pageRoot.id}>
                 {{
                   Container(children: any) {
                     return (
                       <>
-                        <Container
-                          behaiver="drop-zone"
-                          class={store.isEditPage ? "!min-h-750px" : ""}
-                          // drag-handle-selector=".draganchor"
-                          ref={containRef}
-                          should-accept-drop={(
-                            sourceContainerOptions: any,
-                            payload: any
-                          ) => {
-                            if (sourceContainerOptions.groupName != "canvas") {
-                              return false;
-                            }
-
-                            console.log("payload===>", "xxx", payload);
-                            
-                            if (typeof payload == "string") {
-                              controls.dragAddCtrl.updateCompKey(payload);
-                            } else {
-                              controls.dragAddCtrl.updateCompKey(payload.type);
-                              controls.dragAddCtrl.updateCompData(payload.data);
-                            }
+                        <Container behaiver="drop-zone"
+                        should-accept-drop={(
+                          sourceContainerOptions: any,
+                          payload: any
+                        ) => {
+                          if (sourceContainerOptions.groupName != "canvas") {
                             return false;
-                          }}
-                          drop-not-allowed={(p: any) => {
-                            console.log("p", p);
-                          }}
-                          onDrop={(e: any) => {
+                          }
+
+                          console.log("payload===>", "xxx", payload);
+                          
+                          if (typeof payload == "string") {
+                            controls.dragAddCtrl.updateCompKey(payload);
+                          } else {
+                            controls.dragAddCtrl.updateCompKey(payload.type);
+                            controls.dragAddCtrl.updateCompData(payload.data);
+                          }
+                          return false;
+                        }}
+
+                        onDrop={(e: any) => {
+                            debugger;
                             if (e.payload) {
+                              console.log("xx a")
                               actions.addCompToDesign(e.payload, e.addedIndex);
-                            } else {
-                              actions.moveComp(e.removedIndex, e.addedIndex);
-                            }
-                          }}
-                          onDragStart={() => (state.draging = true)}
-                          onDragEnd={() => {
-                            state.draging = false;
-                          }}
-                          non-drag-area-selector={".drag-disable"}
-                        >
-                          {children}
+                            } 
+                          }}>
+                            {children}
                         </Container>
-
-                        {/* {store.currStreamCardId && (
-                          <StreamCardTransfer
-                            key={store.currStreamCardId + streamCardIndex}
-                          />
-                        )} */}
-
-                        {/* { 
-                          !state.draging && controls.cropCtrl.state.visible && <Transforms ctrl={ controls.cropCtrl.modifyCtrl} />
-                        } */}
-
                         {!state.draging && <SelectTransfer />}
                       </>
                     );
@@ -121,43 +145,42 @@ export default defineUI({
                       controls.compUICtrl.state.components.get(comp.compKey)
                         ?.Component || NotFoundComp;
                     return (
-                      <Draggable key={comp.id}>
-                        <Comp compId={comp.id} />
-                      </Draggable>
+                        <Comp compId={comp.id}  key={comp.id} showMask={true} />
                     );
                   },
                 }}
               </CompUI.Page.Component>
             </div>
-
             <div class={editLayerStyle} ref={editLayerRef}></div>
-            <canvas class={selectCls} ref={selectCanvasRef} />
           </div>
-          <div class={meatureStyle}>
+          <canvas class={selectCls} ref={refs.canvas} />
+          <div class={meatureStyle}>    
             <div class="ruler top" id="rulerTop"></div>
             <div class="ruler left" id="rulerLeft"></div>
             {/* <div class="ruler right" id="rulerRight"></div>
             <div class="ruler bottom" id="rulerBottom"></div> */}
           </div>
         </div>
+        </div>
       );
     };
   },
 });
 
 const contentCls = css`
+   position: absolute;
   .dndrop-container.vertical > .dndrop-draggable-wrapper {
     overflow: unset;
   }
 `;
 const selectCls = css`
+  position: absolute;
   pointer-events: none;
-  position: fixed;
   left: 0;
   top: 0;
   width: 100%;
   height: 100%;
-  z-index: 1000;
+  z-index: 10000;
 `;
 
 const meatureStyle = css`
@@ -168,7 +191,6 @@ const meatureStyle = css`
   top: 0px;
   z-index: 998;
   pointer-events: none;
-
   .ruler {
     position: absolute;
     cursor: ns-resize;
@@ -176,7 +198,7 @@ const meatureStyle = css`
   }
   .top {
     top: 0;
-    left: 0;
+    left: 0px;
     height: 20px;
     width: 100%;
     z-index: 2;
@@ -208,7 +230,7 @@ const meatureStyle = css`
   }
   .left {
     top: 0;
-    left: 0;
+    left: 0px;
     height: 100%;
     width: 20px;
     z-index: 1;
@@ -252,3 +274,49 @@ const editLayerStyle = css`
   height: 100%;
   z-index: 1000;
 `;
+
+const cardList = css`
+  
+  width: 120px;
+  height: 100%;
+  background: #262626;
+  overflow-x: hidden;
+  pointer-events: auto;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  position: absolute;
+  padding-bottom: 120px;
+
+  .card-item {
+    flex-shrink: 0;
+    margin-top: 15px;
+    width: 80px;
+    height: 80px;
+    background: #1F1F1F;
+    border-radius: 4px 4px 4px 4px;
+    cursor: pointer;
+    overflow: hidden;
+    color: white;
+    .deleteitem {
+      z-index: 1000;
+      opacity: 0;
+      font-size: 20px;
+    }
+
+    &:hover {
+      .deleteitem {
+        opacity: 1;
+        background: rgba(0,0,0,0.8);
+      }
+    }
+  }
+`;
+
+const viewportStyle =  css`
+  width: calc(100% - 120px);
+  height: 100%;
+  left: 120px;
+  top: 0px;
+  overflow: hidden;
+`

+ 3 - 1
src/modules/editor/controllers/AnimCtrl/index.ts

@@ -22,7 +22,7 @@ export class AnimCtrl extends ModuleControl<EditorModule> {
 
      }).run();
   }
-
+  
   startAnim(index:number) {
     const childrens = this.helper.findCardAllChildren(index);
 
@@ -44,6 +44,8 @@ export class AnimCtrl extends ModuleControl<EditorModule> {
         }, 100);
     })
   }
+
+  
   inited = false;
   initAnim() {
     if (this.inited) return;

+ 1 - 2
src/modules/editor/controllers/CropperCtrl/index.ts

@@ -121,8 +121,7 @@ export class ImageCropperCtrl extends ModuleControl<EditorModule> {
         const cardBox = this.controls.selectCtrl.getCurrCardBox();
         this.modifyCtrl.baseBox.x = cardBox.left;
         this.modifyCtrl.baseBox.y = cardBox.top;
-        this.modifyCtrl.baseBox.w = cardBox.width;
-        this.modifyCtrl.baseBox.h = cardBox.height;
+        this.modifyCtrl.getScale = ()=>this.controls.editorCtrl.state.scale;
 
         const isChild = this.helper.isStreamCardChild(id)
         if (isChild) {

+ 13 - 0
src/modules/editor/controllers/CtxMenuCtrl/index.ts

@@ -0,0 +1,13 @@
+import { ModuleControl } from "queenjs";
+import { EditorModule } from "../../module";
+
+
+
+export class CtxMenuCtrl extends ModuleControl<EditorModule> {
+    initEvent() {
+        window.oncontextmenu=function(e){
+            //取消默认的浏览器自带右键 很重要!!
+            e.preventDefault();
+        }
+    }
+}

+ 165 - 0
src/modules/editor/controllers/EditorCtrl/index.ts

@@ -0,0 +1,165 @@
+import { Effect, ModuleControl } from "queenjs";
+import { EditorModule } from "../../module";
+import { DesignComp } from "../../objects/DesignTemp/DesignComp";
+import { Matrix } from "../SelectCtrl/matrix";
+import {ref, onMounted, nextTick} from "vue";
+import { RxValue } from "../ReactCtrl/rxValue";
+import { DisplayObject } from "../SelectCtrl/objects/displayObject";
+import { ObjsContainer } from "../SelectCtrl/ObjsContainer";
+import { settingsStore } from "@queenjs-modules/queditor/module/stores/settings";
+
+
+const KeySpace = 32;
+
+export class EditorCtrl extends ModuleControl<EditorModule> {
+
+
+    state = RxValue.create({
+        width: 1500,
+        height: 1000,
+        pos: {
+            x: 0, y:0
+        },
+        
+        scale:  1,
+        keyCode: -1,
+
+        page: {w: 375, h: 650}
+    })
+
+    doms:any = {};
+
+  useEditor() {
+     const EditorRef = ref<HTMLElement>();
+     const ParentRef = ref<HTMLElement>();
+     const PageRef = ref<HTMLElement>();
+     const CanvasRef = ref<HTMLElement>();
+     const init = () => {
+        if (!EditorRef.value || !CanvasRef.value || !ParentRef.value) return;
+        console.log("xxxxxxxx=>" , ParentRef.value, PageRef.value);
+        EditorRef.value.style.width = this.state.width + "px";
+        EditorRef.value.style.height = this.state.height + "px";
+        EditorRef.value.style.position = "absolute";
+        // EditorRef.value.style.backgroundColor = "greenyellow";
+        EditorRef.value.style.left = "0";
+        EditorRef.value.style.top = "0";
+
+        CanvasRef.value.style.width = "100%"
+        CanvasRef.value.style.height = "100%"
+        EditorRef.value.style.position = "absolute";
+
+        this.initEditorEvent(EditorRef.value, ParentRef.value as any);
+     }
+
+     onMounted(()=>{
+        setTimeout(init, 200);
+     })
+
+     this.doms = {editor:EditorRef, parent: ParentRef, page:PageRef, canvas: CanvasRef};
+     return this.doms;
+  }
+  
+  isKeyDown( key:number) {
+    return this.state.keyCode === key;
+  }
+  isMoving() {
+    return this.isKeyDown(KeySpace);
+  }
+
+  initEditorEvent(editorLayer:HTMLElement, parent:HTMLElement) {
+    // 监听键盘的 keydown 事件
+    document.addEventListener("keydown", (event)=>{
+        this.state.keyCode = event.keyCode;
+        if (this.isKeyDown(KeySpace)) {
+            parent.style.cursor = "grab";
+        }
+    });
+
+    // 监听键盘的 keyup 事件
+    document.addEventListener("keyup", (event)=>{
+        this.state.keyCode = -1;
+        isMoving = false;
+    });
+    
+
+    parent.addEventListener("wheel", (event:any)=>{
+        // 检查滚轮方向
+        let delta = Math.max(-1, Math.min(1, (event.wheelDelta || -event.detail)))
+        console.log( delta );
+
+        let s = this.state.scale +  0.1 * delta
+        if ( s < 0.5 ) s = 0.5;
+        if (s > 2) s = 2.0;
+        this.state.setScale( s)
+    });
+
+    let isMoving = false;
+    let moveX = 0, moveY = 0;
+    parent.addEventListener("mousemove",(e:MouseEvent)=>{
+        //this.state.setMouse({x: e.offsetX, y: e.offsetY});
+        if (isMoving || e.button == 2) { //鼠标右键
+            e.preventDefault();
+            parent.style.cursor = "grab";
+            const xOffset = e.pageX - moveX;
+            const yOffset = e.pageY - moveY;
+            this.state.setPos({x: this.state.pos.x + xOffset, y: this.state.pos.y + yOffset});
+        }
+        moveX = e.pageX;
+        moveY = e.pageY;
+    });
+
+    document.addEventListener("mouseup",(e:MouseEvent)=>{
+        if (isMoving) {
+            parent.style.cursor = "pointer";
+        }
+        isMoving = false;
+    })
+
+    this.state.onScaleChanged((v)=>{
+        editorLayer.style.transformOrigin = "50% 50%";
+        editorLayer.style.transform = `scale(${v})`;
+    })
+    this.state.onPosChanged((v)=>{
+        editorLayer.style.left= v.x + "px";
+        editorLayer.style.top = v.y + "px";
+    })
+
+    parent.addEventListener("mousedown", (e:MouseEvent)=>{
+        isMoving = this.isKeyDown(KeySpace) || e.button == 2;
+        if (isMoving) {
+            parent.style.cursor = "grab";
+            e.preventDefault();
+            editorLayer.focus();
+        }
+        moveX = e.pageX;
+        moveY = e.pageY;
+    })
+
+    window.addEventListener("resize", ()=>this.updateEditorSize());
+    this.state.onPageChanged(()=>this.updateCardSize());
+
+    setTimeout(() => {
+        this.updateEditorSize();
+    }, 100);
+  }
+
+  updateCardSize() {
+    const page = this.doms.page.value as HTMLElement;
+    const state = this.state;
+    page.style.left = (state.width - state.page.w) / 2.0 + "px";
+    page.style.top = (state.height - state.page.h) / 2.0 + "px";
+
+    console.log("size");
+
+    this.updateEditorSize();
+  }
+
+  updateEditorSize() {
+    const state = this.state;
+    const parent = this.doms.parent.value as HTMLElement;
+    const left = ( parent.clientWidth - state.width) / 2.0;
+    const top =  (parent.clientHeight - state.height) / 2.0;
+
+    this.state.setPos({x: left, y: top});
+  }
+}

+ 76 - 0
src/modules/editor/controllers/ReactCtrl/history.ts

@@ -0,0 +1,76 @@
+import {reactive,  computed} from "vue"
+import { ValueSnap } from "./rxValue";
+
+export class HistoryController {
+  state = reactive({
+        currLen: 0, //操作栈的长度
+        maxLen: 100, //操作栈总长度
+        opIndex: -1, //操作栈的指针
+  });
+
+  refCanUndo = computed(() => {
+    return this.state.opIndex >= 0;
+  });
+  refCanRedo = computed(() => {
+    return this.state.opIndex < this.state.currLen - 1;
+  });
+
+  queues: Map<string, ValueSnap>[] = [];
+  cacheSnapValues = new Map<string , ValueSnap>();
+
+  // 添加缓存记录
+  record(snap: ValueSnap) {
+    const first = this.cacheSnapValues.get(snap.Id)
+    if (first) {
+        snap.OldValue = first.OldValue;
+    }
+    this.cacheSnapValues.set(snap.Id, snap);
+  }
+
+  // 保存缓存记录到历史栈中
+  submit() {
+    if (this.cacheSnapValues.size < 1) return;
+
+    const state = this.state;
+    const queue = this.queues;
+
+    // 将缓存操作记录保存到当前指针的下一栈中
+    queue[++state.opIndex] = this.cacheSnapValues;
+    this.cacheSnapValues = new Map<string, ValueSnap>();
+
+    // 设置栈的长度为指针的长度,舍弃后面的记录
+    queue.length = state.opIndex + 1;
+    // 若栈长度超过上限, 舍弃之前的记录
+    if (queue.length > state.maxLen) {
+      queue.splice(0, queue.length - state.maxLen);
+      state.opIndex = state.maxLen - 1;
+    }
+    // 更新当前长度状态
+    state.currLen = queue.length;
+  }
+
+  undo() {
+    if (!this.refCanUndo.value) return;
+
+    this.cacheSnapValues = new Map<string, ValueSnap>();
+    const snaps = this.queues[this.state.opIndex--]
+
+    snaps.forEach((vn)=>vn.undo())
+  }
+
+  redo() {
+    if (!this.refCanRedo.value ) return;
+    
+    this.cacheSnapValues = new Map<string, ValueSnap>();
+    const snaps = this.queues[++this.state.opIndex];
+    snaps.forEach(vn=>vn.redo());
+  }
+
+  //清除操作
+  clear() {
+    this.queues = [];
+    this.state.currLen = 0;
+    this.state.opIndex = -1;
+    this.cacheSnapValues = new Map<string, ValueSnap>();
+  }
+}

+ 143 - 0
src/modules/editor/controllers/ReactCtrl/rxValue.ts

@@ -0,0 +1,143 @@
+import { HistoryController } from "./history";
+import {BehaviorSubject} from "rxjs";
+import { reactive } from  "vue";
+
+export class ValueSnap {
+    Id:string;
+    Value: any;
+    OldValue: any;
+
+    Rx: BehaviorSubject<any>;
+    constructor(id:string, value:any, oldValue:any, rx: BehaviorSubject<any>) {
+        this.Id = id;
+        this.Value = value;
+        this.OldValue = oldValue;
+        this.Rx = rx
+    }
+    redo() {
+        this.Rx.next({value: this.Value, _hstry:false});
+    }
+    undo() {
+        this.Rx.next({value: this.OldValue, _hstry:false});
+    }
+
+    clone() {
+        return new ValueSnap(this.Id, this.Value,this.OldValue, this.Rx);
+    }
+}
+
+export type RxValueType<T> = {
+    value: T,
+    _hstry?: boolean
+}
+
+
+function createRxValue<T>(value: T, histry:boolean) {
+    return new BehaviorSubject< RxValueType<T> >({value:value,  _hstry: histry})
+}
+
+let _valueIndex = 0;
+export function createValueSnap(value:any, oldValue:any, rx:BehaviorSubject<any>) {
+  let i = _valueIndex + 1;
+  _valueIndex +=1;
+  return new ValueSnap(i+"", value, oldValue, rx);
+}
+
+class RxValue {
+   static create<T extends {[key:string]: any}>(_fields:T, histroy?: HistoryController ) {
+        let obj = {} as any;
+        
+        obj._historySnap = {} as any;
+        obj._historySub = {} as any;
+        obj._rxs = {} as any;
+        obj._fields = _fields;
+        obj._history = histroy;
+        obj._refs = {} as any;
+
+        const names = Object.keys(_fields);
+        
+        names.forEach(name=>{
+               const currName = name;
+               const initValue = _fields[currName]
+                const f = createRxValue(initValue, !!histroy);
+                obj._rxs[name] = f;
+
+                const snap = createValueSnap(initValue, initValue, f);
+                obj._historySnap[name] = snap;
+                const rxc =  reactive({value: initValue});
+
+                Object.defineProperty(obj, currName, {
+                    get: function(){
+                        return rxc.value;
+                    },
+                    set: function(v) {
+                        f.next({value: v});
+                    },
+                    configurable: true,
+                    enumerable: true
+                })
+
+                const CamName = currName.slice(0,1).toUpperCase() +currName.slice(1);
+                
+                obj["set"+CamName] = function(value:T, nohistory = false){
+                    f.next({value, _hstry: !nohistory});
+                }
+        
+                obj["on"+CamName + "Changed"] = function(subscribe: (value:T, oldValue:T)=>void){
+                    return f.subscribe((v:any)=>{
+                            subscribe(v.value, snap.OldValue)
+                        }
+                    )
+                }
+                
+                obj._historySub[name] = f.subscribe((v)=>{
+                    snap.OldValue = v.value;
+                    rxc.value = v.value;
+
+                    if (obj._history) {
+                        if (!v._hstry) return;
+                        const s = snap.clone();
+                        s.Value = v.value;
+                        obj._history.record(s);
+                    }
+                })
+        });
+
+
+        obj["setHistory"] = function(h: HistoryController){
+            obj._history = h;
+        }
+        obj["toJson"] = function() {
+            const out:any = {};
+            const names = Object.keys(_fields);
+            names.forEach(name=>{
+                out[name] = obj._rxs[name].getValue().value;
+            })
+            return out;
+        }
+        obj["fromJson"] = function(json:any) {
+            const out:any = {};
+            const names = Object.keys(_fields);
+            names.forEach(name=>{
+                obj._rxs[name].next({value: json[name], _hstry: false})
+            })
+            return out;
+        }
+        
+        return obj as typeof _fields & {
+            [K in keyof typeof _fields as `set${Capitalize<string & K>}`]: (value: typeof _fields[K], nohistory?:boolean) => void;
+        } & {
+            [K in keyof typeof _fields as `on${Capitalize<string & K>}Changed`]: (subscribe: (value: typeof _fields[K], oldValue:typeof _fields[K])=>void) => void;
+        } & 
+        // {
+        //     [K in keyof typeof _fields as `ref${Capitalize<string & K>}`]: () => typeof _fields[K];
+        // } &
+        {
+            setHistory: (history: HistoryController)=>void
+            toJson:()=>typeof _fields
+            fromJson:(json:typeof _fields)=>void
+        }
+    }
+}
+
+export {RxValue};

+ 98 - 0
src/modules/editor/controllers/ScreenCtrl/index.ts

@@ -0,0 +1,98 @@
+import { Effect, ModuleControl } from "queenjs";
+import { EditorModule } from "../../module";
+import { reactive } from "vue";
+import { DesignComp } from "../../objects/DesignTemp/DesignComp";
+import { RxValue } from "../ReactCtrl/rxValue";
+
+
+// const WidthHeightRatios = [1.377, 1.777, 2.177];
+
+const MobleDesignWidth = 750;
+const MobleSafeHeights = [860, 1080, 1300]
+const MobleHeights = [1080, 1300, 1520]
+
+const PCWidths = [] as number[];
+const PCDesignHeight = 1520
+const PCRates = [0.42, 0.8];
+
+
+export const MobleScreenNames = ["短屏", "普通", "长屏幕"];
+export class ScreenCtrl extends ModuleControl<EditorModule> {
+   state = RxValue.create({
+      useFor: "mobile" as "mobile" | "pc", // pc 还是 手机
+      pageMode: "long" as "long" | "short", //长页面还是短页面(一屏高度)
+      pageSizeType: "normal" as "normal" | "long" | "short", //适配类型 长屏 正常 短屏幕
+
+      docWidth: window.innerWidth,   //实际屏幕宽度
+      docHeight: window.innerHeight,  //实际屏幕高度
+      safeFactor: 0.8,
+   })
+   get isShortPage () {
+      return this.state.pageMode == "short";
+   }
+   
+   initEvent() {
+      if ( !this.store.isEditMode ) return;
+
+      this.state.onUseForChanged(()=>this.updateAdapterState());
+      this.state.onPageModeChanged(()=>this.updateAdapterState());
+      this.state.onPageSizeTypeChanged(()=>this.updateAdapterState());
+
+      const size = 3;
+      const safeFactor =  Math.pow((PCRates[0] / PCRates[1]) , 1.0 / size);
+      let min = 0.42;
+      const pcDesignWidthRanges = [];
+      for (let i=0; i<size; i++) {
+         const w =  safeFactor * PCDesignHeight / min 
+         let pre = min;
+         min = PCDesignHeight / w;
+         PCWidths.push( w )
+         pcDesignWidthRanges.push([pre, min])
+      }
+      const t = PCWidths[0]
+      PCWidths[0] = PCWidths[2]
+      PCWidths[2] = t; 
+      this.state.safeFactor = safeFactor;
+   }
+
+   getAdapterIndex() {
+      if(this.state.pageMode == "long") return 1;
+      return ["short", "normal", "long"].indexOf(this.state.pageSizeType)
+   }
+
+   updateAdapterState() {
+      if (!this.store.rootPage) return;
+
+      this.store.streamCardIds.forEach(c=>{
+         const card = this.helper.findComp(c) as DesignComp;
+         card.setW(this.getCurrScreenWidth());
+         this.helper.extendStreamCard(card.id);
+      })
+      const w = this.helper.designSizeToPx(this.getCurrScreenWidth());
+      const h =  this.helper.designSizeToPx(this.getCurrScreenHeight());
+
+      this.controls.editorCtrl.state.setPage({w, h});
+
+     
+      this.store.rootPage.layout.size[0] = this.getCurrScreenWidth();
+      this.store.rootPage.layout.size[1] = this.getCurrScreenHeight();
+   }
+
+   getCurrScreenHeight() {
+      const pageValue = this.state
+      if ( pageValue.useFor == "pc") {
+         return PCDesignHeight;
+      }
+      const currScreenIndex = this.getAdapterIndex();
+      return MobleHeights[currScreenIndex];
+   }
+
+   getCurrScreenWidth() {
+      const currScreenIndex = this.getAdapterIndex();
+      const pageValue = this.state
+      if ( pageValue.useFor == "pc" ) {
+         return PCWidths[currScreenIndex];
+      }
+      return MobleDesignWidth
+   }
+}

+ 14 - 0
src/modules/editor/controllers/SelectCtrl/ObjsContainer.ts

@@ -167,6 +167,20 @@ export class ObjsContainer {
         return { x: point.x, y: point.y};
     }
 
+    setPivot2(x:number, y:number) {
+      
+        let targetPivot = {x, y}
+        let point = { x, y } as any;
+        this.parent.worldTransform.apply(point, point);
+
+        this.parent.pivot = targetPivot as any;
+        this.parent.position.x = point.x;
+        this.parent.position.y = point.y;
+        this.parent.updateTransform();
+        return { x: point.x, y: point.y};
+    }
+
+
     getPivotXY(index:number) {
         let rect = this.rect;
         let pivots = [{ x: 0, y: 0 }, { x: rect.width, y: 0 }, { x: rect.width, y: rect.height }, { x: 0, y: rect.height }, { x: rect.width / 2, y: rect.height / 2 }];

+ 18 - 22
src/modules/editor/controllers/SelectCtrl/assistCtrl.ts

@@ -36,11 +36,9 @@ export class AssistCtrl {
 
         const size = this.ctrl._selCanvaseSize;
         const ctx = this.ctrl._selCtx;
-        const cardBox = this.ctrl.getCurrCardBox();
-        const veiewBox = this.ctrl.getViewPortBox();
-
-        const ObjC = this.ctrl.objContainer 
-        const bound = ObjC.getBound()
+        const cardBox = this.ctrl.getCurrCardViewPortBox();
+  
+        const bound = this.ctrl.getSelectBound(); 
         ctx.lineWidth = 2;
         ctx.beginPath(); // Start a new path
         ctx.strokeStyle = "orange"; 
@@ -54,11 +52,11 @@ export class AssistCtrl {
         let y = (cardBox.y + bound.y + bound.height / 2.0) *2
         const tl = ( x - cardBox.x*2).toFixed(0);
         const m = ctx.measureText(tl)
-        ctx.moveTo(veiewBox.left *2, y); 
-        ctx.lineTo(veiewBox.left *2 + 30, y);
+        ctx.moveTo(0, y); 
+        ctx.lineTo(30, y);
         ctx.stroke();
 	    ctx.closePath();
-        ctx.fillText(tl, veiewBox.left *2, y - 18);
+        ctx.fillText(tl, 0, y - 18);
 
         //右边
         x = (cardBox.x + bound.x + bound.width);
@@ -67,36 +65,34 @@ export class AssistCtrl {
         const m2 = ctx.measureText(tr)
 
         ctx.beginPath(); // Start a new path
-        ctx.moveTo(veiewBox.right*2.0, y); 
-        ctx.lineTo( veiewBox.right*2.0 - 30, y); 
+        ctx.moveTo(size.w, y); 
+        ctx.lineTo(size.w - 30, y); 
         ctx.stroke();
         ctx.closePath();
-        ctx.fillText(tr, veiewBox.right*2.0 - m2.width, y-18);
+        ctx.fillText(tr, size.w - m2.width, y-18);
 
         //上边
-        x = cardBox.x + cardBox.width / 2.0;
-        y = cardBox.y;
-
+        x = cardBox.x + bound.x + bound.width / 2.0;
         ctx.beginPath(); // Start a new path
-        ctx.moveTo(x*2, veiewBox.top*2); // Move the pen to (30, 50)
-        ctx.lineTo( x*2, veiewBox.top*2 + 40 ); // Draw a line to (150, 100)
+        ctx.moveTo(x*2, 0); // Move the pen to (30, 50)
+        ctx.lineTo(x*2, 40 ); // Draw a line to (150, 100)
         ctx.stroke(); // Render the path
         let dy = (bound.y*2).toFixed(0);
-        ctx.fillText(dy, x*2 + 10, veiewBox.top*2 +36);
+        ctx.fillText(dy, x*2 + 10, 36);
 
 
         //下边
-        x = cardBox.x + cardBox.width / 2.0;
+ 
         y = cardBox.y + cardBox.height;
-
         ctx.beginPath(); // Start a new path
-        ctx.moveTo(x*2, veiewBox.bottom*2.0); // Move the pen to (30, 50)
-        ctx.lineTo( x*2, veiewBox.bottom*2.0 - 40); // Draw a line to (150, 100)
+        ctx.moveTo(x*2, size.h); // Move the pen to (30, 50)
+        ctx.lineTo( x*2, size.h - 40); // Draw a line to (150, 100)
         ctx.stroke(); // Render the path
         dy = ((cardBox.height - bound.y - bound.height)*2).toFixed(0);
-        ctx.fillText(dy, x*2 + 10, veiewBox.bottom*2.0);
+        ctx.fillText(dy, x*2 + 10, size.h);
         
         //如果有旋转角度
+        const ObjC = this.ctrl.objContainer;
         if ( Math.abs(ObjC.parent.rotation) > 0.001 ) {
             ctx.strokeRect((bound.x + cardBox.x)*2, (bound.y + cardBox.y)*2, bound.width *2, bound.height *2);
             //绘制角度

+ 7 - 7
src/modules/editor/controllers/SelectCtrl/assistMagnetCtrl.ts

@@ -66,10 +66,11 @@ export class AssistMagnetCtrl {
         
         if ( !this.enable ) return;
 
-        const eps = 4;
-        const Objc = this.ctrl.objContainer as ObjsContainer
-        const bund = Objc.getBound();
-        const box = this.ctrl.getCurrCardBox();
+        const eps = 2;
+
+        //在屏幕空间中计算
+        const bund = this.ctrl.getSelectBound();
+        const box = this.ctrl.getCurrCardViewPortBox();
 
         //包围盒的上 中 下 三条横线
         const srcY1 = (bund.y + box.top)*2.0
@@ -186,13 +187,12 @@ export class AssistMagnetCtrl {
             ctx.closePath();
         }
 
-        const box = this.ctrl.getViewPortBox();
         n = this.currRefYs.length;
         while(n--) {
             let y = this.currRefYs[n]
             ctx.beginPath();
-            ctx.moveTo(box.left*2, y)
-            ctx.lineTo(box.right*2, y);
+            ctx.moveTo(0, y)
+            ctx.lineTo(this.ctrl._selCanvaseSize.h, y);
             ctx.stroke();
             ctx.closePath();
         }

+ 1 - 1
src/modules/editor/controllers/SelectCtrl/assistRulerCtrl.ts

@@ -155,7 +155,7 @@ export class AssistRulerCtrl {
       ctx.moveTo(x1, y);
       ctx.lineTo(x2, y);
 
-      const curBox = this.ctrl.getCurrCardBox();
+      const curBox = this.ctrl.getCurrCardViewPortBox();
       if (typeIndex == 2) {
         ctx.fillText(
           ((e.clientY - curBox.top) * 2).toFixed(0),

+ 98 - 48
src/modules/editor/controllers/SelectCtrl/index.ts

@@ -77,18 +77,44 @@ export class SelectCtrl extends ModuleControl<EditorModule> {
     return (this.pageEl as (HTMLElement)).getBoundingClientRect();
   }
   
-  getCurrCardBox() {
-    return this.store.currStreamCard.$el.getBoundingClientRect();
+  _cardBox = {x:0,y:0,width: 0, height: 0, bottom: 0, top: 0, left: 0};
+
+  getCurrCardViewPortBox() {//屏幕空间坐标clientX 转中间viewport空间
+    const box = this.store.currStreamCard.$el.getBoundingClientRect();
+    const viewportbox = this.getViewPortBox();
+    const _cardBox  = this._cardBox;
+    _cardBox.x = box.x  - viewportbox.x;
+    _cardBox.y = box.y  - viewportbox.y;
+    _cardBox.width = box.width; 
+    _cardBox.height = box.height;
+    _cardBox.left = box.left - viewportbox.left;
+    _cardBox.top = box.top - viewportbox.top;
+
+    return _cardBox;
   } 
+
+  _tempPos = {x: 0, y:0}
+  viewportPos2DesignPos(clientX: number, clientY:number) {
+      const box = this.store.currStreamCard.$el.getBoundingClientRect();
+      let scale = this.controls.editorCtrl.state.scale;
+      this._tempPos.x = (clientX - box.left) / scale;
+      this._tempPos.y = (clientY - box.top)  / scale;
+      return this._tempPos;
+  }
+
   getViewPortBox() {
     //@ts-ignore
-    return this.viewport.getBoundingClientRect();
+    const box = this.viewport.getBoundingClientRect();
+    return box;
   } 
+
   
   getCurrCard() {
     return this.store.currStreamCard;
   }
-
+  getCurrCardBox() {
+    return this.store.currStreamCard.$el.getBoundingClientRect();
+  }
   getProjectId() {
     return this.store.designData._id;
   }
@@ -119,8 +145,8 @@ export class SelectCtrl extends ModuleControl<EditorModule> {
 
     this._selCtx = selCanvas.getContext("2d") as CanvasRenderingContext2D;
 
-    this._selCanvaseSize.w = selCanvas.width * 2;
-    this._selCanvaseSize.h = selCanvas.height * 2;
+    this._selCanvaseSize.w = selCanvas.width;
+    this._selCanvaseSize.h = selCanvas.height;
 
     this.assistCtrl = new AssistCtrl(this);
     this.assistRuler = new AssistRulerCtrl(this);
@@ -171,9 +197,7 @@ export class SelectCtrl extends ModuleControl<EditorModule> {
   _downClickedCompId = "";
   onDocMouseDown(e: MouseEvent) {
     this._mouseDownTimestamp = Date.now();
-    if (!this.pageEl || !this.selCanvas) return;
-
-    
+    if (e.button != 0 || !this.pageEl || !this.selCanvas || this.controls.editorCtrl.isMoving() ) return;
 
     document.addEventListener("mousemove", this.onDocMouseMove, {
       capture: true,
@@ -194,12 +218,13 @@ export class SelectCtrl extends ModuleControl<EditorModule> {
     this._state = draging ? MODE_RULER_DRAG : MODE_NONE;
 
     const sel = this.selCanvas.getBoundingClientRect();
-    const selX = e.clientX - sel.left;
-    const sely = e.clientY - sel.top;
-    this._selDownX = selX;
-    this._selDownY = sely;
     this._selBox = sel;
 
+    const pos = this.getViewportPos(e);
+
+    this._selDownX = pos.x;
+    this._selDownY = pos.y;
+
     this._downClientX = e.clientX;
     this._downClientY = e.clientY;
 
@@ -213,30 +238,28 @@ export class SelectCtrl extends ModuleControl<EditorModule> {
         //选框点击判断
         let isClickSelRect = false;
         if (this.selected.length > 0) {
-          const card = this.store.currStreamCard.$el;
-          box = card.getBoundingClientRect();
-          const cardX = pageX;
-          const cardY = e.clientY - box.top;
-          isClickSelRect = this.objContainer?.testClick(cardX, cardY) as boolean;
+          const pos = this.viewportPos2DesignPos(e.clientX, e.clientY);
+          isClickSelRect = this.objContainer?.testClick(pos.x, pos.y) as boolean;
           if (isClickSelRect) {
             this._state = MODE_MOVING;
           }
         }
         if (!isClickSelRect) {
           //点击在选框之外
-  
-          if (!this._downClickedCompId) {
-            //没有点击到组件
-            const view = this.viewport?.getBoundingClientRect() as any;
-            const isOut =
-              e.clientX < view.left ||
-              e.clientX > view.right ||
-              e.clientY < view.top ||
-              e.clientY > view.bottom;
-            if (!isOut) {
-              this._state = MODE_SEL_RECT;
-            }
-          }
+          this._state = MODE_SEL_RECT;
+          
+          // if (!this._downClickedCompId) {
+          //   //没有点击到组件
+          //   const view = this.viewport?.getBoundingClientRect() as any;
+          //   const isOut =
+          //     e.clientX < view.left ||
+          //     e.clientX > view.right ||
+          //     e.clientY < view.top ||
+          //     e.clientY > view.bottom;
+          //   if (!isOut) {
+          //     this._state = MODE_SEL_RECT;
+          //   }
+          // }
           //else {//点击到选框之外的组件, 把时间放到mouseup 时相应.
           //   this._state = MODE_MOVING;
           //   const obj = this.compMap[comps[0].id];
@@ -399,6 +422,7 @@ export class SelectCtrl extends ModuleControl<EditorModule> {
     this.helper.extendStreamCard(this.store.currStreamCardId);
   }
 
+
   movingMousemove(e: MouseEvent) {
     const objContainer = this.objContainer as ObjsContainer;
     const magnet = this.assistMagnet as AssistMagnetCtrl;
@@ -408,11 +432,12 @@ export class SelectCtrl extends ModuleControl<EditorModule> {
       this._initMovePos = { x: obj.parent.x, y: obj.parent.y };
     }
     magnet.test(e);
+    const s = this.controls.editorCtrl.state.scale;
 
     objContainer.setPivot(0);
     objContainer.translate(
-      magnet.clientX - this._movePreClientX,
-      magnet.clientY - this._movePreClientY
+      (magnet.clientX - this._movePreClientX) / s,
+      (magnet.clientY - this._movePreClientY ) / s
     );
 
     this.upgateGizmoStyle();
@@ -491,11 +516,13 @@ export class SelectCtrl extends ModuleControl<EditorModule> {
       //选择空间转 streamCard空间
       const card = this.store.currStreamCard;
       const box = card.$el.getBoundingClientRect();
+      const s = this.controls.editorCtrl.state.scale;
+
       this.rectSelect(
-        this._lastSelRect[0] - box.left,
-        this._lastSelRect[1] - box.top,
-        this._lastSelRect[2],
-        this._lastSelRect[3],
+        (this._lastSelRect[0] - box.left)/s,
+        (this._lastSelRect[1] - box.top) / s,
+        this._lastSelRect[2] / s,
+        this._lastSelRect[3] / s,
         e
       );
     }
@@ -688,6 +715,12 @@ export class SelectCtrl extends ModuleControl<EditorModule> {
 
   _lastSelRect = [0, 0, 0, 0];
 
+  getViewportPos(e:MouseEvent) {
+    this._tempPos.x = (e.clientX - this._selBox.left); /// this.controls.editorCtrl.state.scale;
+    this._tempPos.y = (e.clientY - this._selBox.top ); /// this.controls.editorCtrl.state.scale;
+    return this._tempPos;
+  }
+
   drawSelRect(e: MouseEvent) {
     this.assistRuler?.draw();
 
@@ -695,8 +728,14 @@ export class SelectCtrl extends ModuleControl<EditorModule> {
 
     const dx = this._selDownX;
     const dy = this._selDownY;
-    const currX = e.clientX - this._selBox.left;
-    const currY = e.clientY - this._selBox.top;
+    
+    const pos  = this.getViewportPos(e);
+
+    const currX = pos.x;
+    const currY = pos.y;
+
+    console.log("xxxxxxxx=>", currX, currY);
+
     const x = Math.min(currX, dx),
       y = Math.min(dy, currY);
 
@@ -745,6 +784,16 @@ export class SelectCtrl extends ModuleControl<EditorModule> {
     //const m = Matrix.createFromComp(comp.layout.transform)
   }
   objContainer?: ObjsContainer;
+  getSelectBound() {
+    const Objc = this.objContainer as ObjsContainer;
+    const w = Objc.getBound();
+    const s = this.controls.editorCtrl.state.scale;
+    w.x = w.x * s;
+    w.y = w.y * s;
+    w.width = w.width *s;
+    w.height = w.height *s;
+    return w;
+  }
 
   selecteObjs(objs: any[], ContainerBox?: ObjsContainer) {
     if (this.selected.length == 0 && objs.length == 0) return;
@@ -800,11 +849,10 @@ export class SelectCtrl extends ModuleControl<EditorModule> {
   lastRad = 0;
 
   rotateMousemove(e: MouseEvent) {
-    const card = this.store.currStreamCard;
-
-    const rect = card.$el.getBoundingClientRect();
-    let StartX = e.clientX - rect.left;
-    let StartY = e.clientY - rect.top;
+    
+    const pos = this.viewportPos2DesignPos(e.clientX, e.clientY)
+    let StartX = pos.x;
+    let StartY = pos.y;
 
     const objContainer = this.objContainer as ObjsContainer;
 
@@ -924,13 +972,15 @@ export class SelectCtrl extends ModuleControl<EditorModule> {
     ];
     let dirOrth = ["scaleright", "scaleleft", "scalebottom", "scaletop"];
 
-    const rect = this.store.currStreamCard.$el.getBoundingClientRect();
-
+   
     const maget = this.assistMagnet as AssistMagnetCtrl;
     maget.test(event);
 
-    let StartX = maget.clientX - rect.left;
-    let StartY = maget.clientY - rect.top;
+    const pos = this.viewportPos2DesignPos(maget.clientX, maget.clientY)
+
+    let StartX = pos.x;
+    let StartY = pos.y;
+
     const objContainer = this.objContainer as ObjsContainer;
 
     //获取当前屏幕坐标和选框中心点坐标,计算旋转值

+ 12 - 7
src/modules/editor/controllers/TransformCtrl/index.ts

@@ -28,7 +28,8 @@ export class TransformCtrl extends Events {
 
   minBox ?:{x:number, y:number, w:number, h:number}
   maxBox ?:{x:number, y:number, w:number, h:number}
-  baseBox = {x:0, y:0, w: 0, h: 0}
+  baseBox = {x:0, y:0}
+  getScale = ()=>1;
 
   objContainer = new ObjsContainer([]);
 
@@ -42,7 +43,8 @@ export class TransformCtrl extends Events {
     this.toolbars = barComps;
   }
 
-  initUI(ui: HTMLElement) {
+  
+  initUI(ui: HTMLElement, ) {
      ui.addEventListener("mousedown", (e:MouseEvent)=>{
         e.preventDefault();
         e.stopPropagation();
@@ -58,18 +60,21 @@ export class TransformCtrl extends Events {
     objContainer.setPivot(0);
     const dtx = e.clientX - moveOptions._movePreClientX;
     const dty = e.clientY - moveOptions._movePreClientY;
+
+    const s = this.getScale();
+
     objContainer.translate(
-      dtx,
-      dty
+      dtx / s,
+      dty / s
     );
     this.updateState();
     this.emit("moving", dtx, dty);
   }
 
   rotate(e:MouseEvent) {
-
-    let StartX = e.clientX - this.baseBox.x;
-    let StartY = e.clientY - this.baseBox.y;
+    
+    let StartX = (e.clientX - this.baseBox.x) / this.getScale();
+    let StartY = e.clientY - this.baseBox.y / this.getScale();
 
     const objContainer = this.objContainer as ObjsContainer;
 

+ 10 - 3
src/modules/editor/module/actions/edit.tsx

@@ -442,7 +442,7 @@ export const editActions = EditorModule.action({
   },
 
   async removeStreamCard(compId: string) {
-    await queenApi.showConfirm({ title: "删除", content: "确认删除当前内容?" });
+    await queenApi.showConfirm({ title: "删除", content: "确认删除当前页面?" });
 
     // if (this.store.streamCardIds.length < 2) {
     //   queenApi.messageError("")
@@ -458,9 +458,9 @@ export const editActions = EditorModule.action({
     }
     this.controls.selectCtrl.selecteObjs([]);
 
-    this.store.deleteComp(compId);
-
     this.store.setCurrComp(nextCard);
+
+    this.store.deleteComp(compId);
   },
   // 移动组件顺序
   moveComp(selIndex: number, targetIndex: number) {
@@ -539,6 +539,13 @@ export const editActions = EditorModule.action({
     try {
       // 清除无用组件
       this.helper.clearUnusedComps(this.store.designData.compMap);
+      const c = this.controls.screenCtrl;
+
+      const root = this.helper.findRootComp() as DesignComp;
+      root.value.useFor = c.state.useFor;
+      root.value.pageMode = c.state.pageMode;
+      root.value.pageSizeType = c.state.pageSizeType;
+
       // 封面截屏
       if (!this.store.designData.thumbnail) {
         await this.actions.updateThumbnailByScreenshot();

+ 19 - 0
src/modules/editor/module/actions/init.ts

@@ -29,7 +29,26 @@ export const initActions = EditorModule.action({
   async initDesign(id: string, isSys = false) {
     const ret = await this.https.getDesignDetail(id, { isSys });
     this.store.setDesignData(ret.result);
+
+    const root = this.helper.findRootComp() as DesignComp;
+    this.controls.screenCtrl.state.useFor = root.value.useFor || "mobile";
+    this.controls.screenCtrl.state.pageMode = root.value.pageMode || "long";
+    this.controls.screenCtrl.state.pageSizeType = root.value.pageSizeType || "normal";
+  
+    //设置组件父子关系
+    const ite = (root:any)=> {
+      const cards = root.children?.default || [];
+      cards.forEach((c:string)=>{
+          this.store.setCompPid(c, root.id);
+          const r = this.helper.findComp(c);
+          if (r) {
+            ite(r);
+          }
+      })
+    }
+    ite(this.store.rootPage);
   },
+
   async initWkDesign(id: string) {
     this.store.setWk(true);
     const ret = await this.https.getWkDesignDetail(id);

+ 8 - 1
src/modules/editor/module/helpers/index.ts

@@ -86,7 +86,9 @@ export const helpers = EditorModule.helper({
     const m = new Matrix();
     let n = paths.length;
     let box = paths[1].$el.getBoundingClientRect();
-    m.translate(box.left - vx, box.top - vy);
+    const s = this.controls.editorCtrl.state.scale;
+    m.translate((box.left - vx) / s, (box.top - vy)/s);
+    
     for (let i = 2; i < n - 1; i++) {
       //card开始遍历
       const m1 = new Matrix();
@@ -173,6 +175,11 @@ export const helpers = EditorModule.helper({
 
     const compMap = this.store.designData.compMap;
     const card = compMap[streamCardId];
+    if (this.controls.screenCtrl.isShortPage) {
+       card.setH(this.controls.screenCtrl.getCurrScreenHeight());
+       return;
+    }
+    
     const childs = card.children.default || [];
     let maxH = 0,
       n = childs.length;

+ 10 - 1
src/modules/editor/module/index.ts

@@ -24,6 +24,9 @@ import { ImageCropperCtrl } from "../controllers/CropperCtrl";
 import { MediaCtrl } from "../controllers/MediaCtrl/indext";
 import { AnimCtrl } from "../controllers/AnimCtrl";
 import { TextEditorCtrl } from "../controllers/TextEditorCtrl";
+import { ScreenCtrl } from "../controllers/ScreenCtrl";
+import { EditorCtrl } from "../controllers/EditorCtrl";
+import { CtxMenuCtrl } from "../controllers/CtxMenuCtrl";
 
 export class EditorModule extends ModuleRoot {
   config = this.setConfig({
@@ -65,13 +68,19 @@ export class EditorModule extends ModuleRoot {
     cropCtrl: new ImageCropperCtrl(this),
     mediaCtrl: new MediaCtrl(this),
     textEditorCtrl: new TextEditorCtrl(this),
-    animCtrl: new AnimCtrl(this)
+    animCtrl: new AnimCtrl(this),
+    screenCtrl: new ScreenCtrl(this),
+    editorCtrl: new EditorCtrl(this),
+    menuCtrl: new CtxMenuCtrl(this),
   };
+
   compObjsMap = new Map<string, CompObject>();
 
   onReady() {
     this.actions.init();
     this.controls.animCtrl.initEvent();
+    this.controls.screenCtrl.initEvent();
+    this.controls.menuCtrl.initEvent();
   }
 
   jumpIndexHtml(route = "#/") {

+ 11 - 6
src/modules/editor/module/stores/index.ts

@@ -171,7 +171,11 @@ export const store = EditorModule.store({
       if (compId == "root") {
         return;
       }
-      this.store.currStreamCardId = comps[1]?.id || "";
+      let cardId = comps[1]?.id || "";
+      if (this.helper.isStreamCard(compId)) {
+        cardId = compId;
+      }
+      this.store.currStreamCardId = cardId;
     },
 
     deleteComp(compId: string) {
@@ -192,11 +196,12 @@ export const store = EditorModule.store({
       }
 
       if (deleteOK) {
-        const comp = this.helper.findComp(compId) as DesignComp;
-        const ids = comp.getChildIds();
-        [compId, ...ids].forEach((id) => {
-          delete compMap[id];
-        });
+        //不删除孩子节点
+        // const comp = this.helper.findComp(compId) as DesignComp;
+        // const ids = comp.getChildIds();
+        // [compId, ...ids].forEach((id) => {
+        //   delete compMap[id];
+        // });
         delete this.store.compPids[compId];
       }
     },

+ 3 - 6
src/modules/editor/objects/DesignTemp/creates/createCompStyle.ts

@@ -96,12 +96,9 @@ export function createCompStyle(
 
   if (layout.transformMatrix) {
     const m = Matrix.createFromMatrixStr(layout.transformMatrix);
-    m.ty = parseFloat(
-      designToNaturalSize(pxToDesignSize(m.ty), {
-        adaptiveH:
-          module.helper.findParentComp(comp.id)?.layout.size[2]?.unit === "%",
-      })
-    );
+    // m.ty = parseFloat(
+    //   designToNaturalSize(pxToDesignSize(m.ty), { adaptiveH: true })
+    // );
     style.transform = m.getMatrixStr(); //layout.transformMatrix;
     style.transformOrigin = "0 0";
   } else {

+ 7 - 0
yarn.lock

@@ -7646,6 +7646,13 @@ run-parallel@^1.1.9:
   dependencies:
     queue-microtask "^1.2.2"
 
+rxjs@^7.8.1:
+  version "7.8.1"
+  resolved "http://124.70.149.18:4873/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543"
+  integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==
+  dependencies:
+    tslib "^2.1.0"
+
 safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
   version "5.1.2"
   resolved "http://124.70.149.18:4873/safe-buffer/-/safe-buffer-5.1.2.tgz"