diff --git a/src/styles/common/mixins/mixins.scss b/src/styles/common/mixins/mixins.scss
index ec6f2ccd..38228a91 100644
--- a/src/styles/common/mixins/mixins.scss
+++ b/src/styles/common/mixins/mixins.scss
@@ -1,78 +1,84 @@
-@import './config.scss';
-@import './function.scss';
-@import '../theme.scss';
-
-@mixin go($block) {
-  $B: $namespace + '-' + $block;
-  .#{$B} {
-    @content;
-  }
-}
-
-@mixin goId($block) {
-  $B: $namespace + '-' + $block;
-  ##{$B} {
-    @content;
-  }
-}
-
-@mixin deep() {
-  :deep() {
-    @content;
-  }
-}
-
-@mixin when($state) {
-  @at-root {
-    &.#{$state-prefix + $state} {
-      @content;
-    }
-  }
-}
-
-@mixin themeify {
-  @each $theme-name, $theme-map in $themes {
-    $theme-map: $theme-map !global;
-    [data-theme='#{$theme-name}'] & {
-      @content;
-    }
-  }
-}
-
-@mixin fetch-theme($param) {
-  @include themeify {
-    #{$param}: themed($param);
-  }
-}
-
-@mixin fetch-theme-custom ($key, $value) {
-  @include themeify {
-    #{$key}: themed($value);
-  }
-}
-
-//获取背景颜色
-@mixin fetch-bg-color($target) {
-  @include themeify {
-    background-color: themed($target);
-  }
-}
-
-//获取背景渐变颜色
-@mixin background-image($target) {
-  @include themeify {
-    background-image: themed($target);
-  }
-}
-
-//设置边框颜色
-@mixin fetch-border-color($target) {
-  @include themeify {
-    border-color: themed($target);
-  }
-}
-@mixin hover-border-color($target) {
-  @include themeify {
-    border: 1px solid themed($target);
-  }
-}
+@import './config.scss';
+@import './function.scss';
+@import '../theme.scss';
+
+@mixin go($block) {
+  $B: $namespace + '-' + $block;
+  .#{$B} {
+    @content;
+  }
+}
+
+@mixin dark {
+  [data-theme='dark'] {
+    @content;
+  }
+}
+
+@mixin goId($block) {
+  $B: $namespace + '-' + $block;
+  ##{$B} {
+    @content;
+  }
+}
+
+@mixin deep() {
+  :deep() {
+    @content;
+  }
+}
+
+@mixin when($state) {
+  @at-root {
+    &.#{$state-prefix + $state} {
+      @content;
+    }
+  }
+}
+
+@mixin themeify {
+  @each $theme-name, $theme-map in $themes {
+    $theme-map: $theme-map !global;
+    [data-theme='#{$theme-name}'] & {
+      @content;
+    }
+  }
+}
+
+@mixin fetch-theme($param) {
+  @include themeify {
+    #{$param}: themed($param);
+  }
+}
+
+@mixin fetch-theme-custom ($key, $value) {
+  @include themeify {
+    #{$key}: themed($value);
+  }
+}
+
+//获取背景颜色
+@mixin fetch-bg-color($target) {
+  @include themeify {
+    background-color: themed($target);
+  }
+}
+
+//获取背景渐变颜色
+@mixin background-image($target) {
+  @include themeify {
+    background-image: themed($target);
+  }
+}
+
+//设置边框颜色
+@mixin fetch-border-color($target) {
+  @include themeify {
+    border-color: themed($target);
+  }
+}
+@mixin hover-border-color($target) {
+  @include themeify {
+    border: 1px solid themed($target);
+  }
+}
diff --git a/src/styles/pages/index.scss b/src/styles/pages/index.scss
index b8f7272d..cde2d584 100644
--- a/src/styles/pages/index.scss
+++ b/src/styles/pages/index.scss
@@ -1,9 +1,15 @@
-// 页面全局样式
-// 去除高德地图 logo
-.amap-logo {
-  display: none !important;
-  opacity: 0 !important;
-}
-.amap-copyright {
-  opacity: 0 !important;
-}
+// 页面全局样式
+// 去除高德地图 logo
+.amap-logo {
+  display: none !important;
+  opacity: 0 !important;
+}
+.amap-copyright {
+  opacity: 0 !important;
+}
+
+[data-theme='dark'] {
+  body {
+    background-color: #18181c;
+  }
+}
\ No newline at end of file
diff --git a/src/views/preview/hooks/useScale.hook.ts b/src/views/preview/hooks/useScale.hook.ts
index e4c57f97..53b02d46 100644
--- a/src/views/preview/hooks/useScale.hook.ts
+++ b/src/views/preview/hooks/useScale.hook.ts
@@ -23,16 +23,27 @@ export const useScale = (localStorageInfo: ChartEditStorageType) => {
           e.preventDefault()
           e.stopPropagation()
           removeEvent()
-          const fitDom = document.querySelector(".go-preview.fit") as HTMLElement
-          if (fitDom) fitDom.style.overflow = 'auto'
-          const transform = previewRef.value.style.transform
-          // 使用正则解析 scale(1, 1) 中的两个数值
+          const transform = previewRef.value?.style.transform
           const regRes = transform.match(/scale\((\d+\.?\d*)*/) as RegExpMatchArray
           const width = regRes[1]
+          const previewBoxDom = document.querySelector('.go-preview') as HTMLElement
+          const entityDom = document.querySelector('.go-preview-entity') as HTMLElement
+          if (previewBoxDom) {
+            previewBoxDom.style.overflow = 'unset'
+            previewBoxDom.style.position = 'absolute'
+            previewBoxDom.style.top = '10px'
+            previewBoxDom.style.left = '20px'
+          }
+          if (entityDom) {
+            entityDom.style.overflow = 'unset'
+          }
+
           if (e.wheelDelta > 0) {
-            previewRef.value.style.transform = `scale(${parseFloat(Number(width).toFixed(2)) + 0.1})`
+            const resNum = parseFloat(Number(width).toFixed(2))
+            previewRef.value.style.transform = `scale(${resNum > 5 ? 5 : resNum + 0.1})`
           } else {
-            previewRef.value.style.transform = `scale(${parseFloat(Number(width).toFixed(2)) - 0.1})`
+            const resNum = parseFloat(Number(width).toFixed(2))
+            previewRef.value.style.transform = `scale(${resNum < 0.2 ? 0.2 : resNum - 0.1})`
           }
         }
       },
diff --git a/src/views/preview/suspenseIndex.vue b/src/views/preview/suspenseIndex.vue
index 1a1932b9..bf2c528e 100644
--- a/src/views/preview/suspenseIndex.vue
+++ b/src/views/preview/suspenseIndex.vue
@@ -1,5 +1,5 @@
 <template>
-  <div :class="`go-preview ${chartEditStore.editCanvasConfig.previewScaleType}`">
+  <div :class="`go-preview ${chartEditStore.editCanvasConfig.previewScaleType}`" @mousedown="dragCanvas">
     <template v-if="showEntity">
       <!-- 实体区域 -->
       <div ref="entityRef" class="go-preview-entity">
@@ -30,7 +30,7 @@
 import { computed } from 'vue'
 import { PreviewRenderList } from './components/PreviewRenderList'
 import { getFilterStyle, setTitle } from '@/utils'
-import { getEditCanvasConfigStyle, getSessionStorageInfo, keyRecordHandle } from './utils'
+import { getEditCanvasConfigStyle, getSessionStorageInfo, keyRecordHandle, dragCanvas } from './utils'
 import { useComInstall } from './hooks/useComInstall.hook'
 import { useScale } from './hooks/useScale.hook'
 import { useStore } from './hooks/useStore.hook'
diff --git a/src/views/preview/utils/drag.ts b/src/views/preview/utils/drag.ts
new file mode 100644
index 00000000..b78bbb53
--- /dev/null
+++ b/src/views/preview/utils/drag.ts
@@ -0,0 +1,55 @@
+import { listen } from 'dom-helpers'
+import throttle from 'lodash/throttle'
+
+let prevMoveXValue = [0, 0]
+let prevMoveYValue = [0, 0]
+
+// 拖拽处理
+export const dragCanvas = (e: MouseEvent) => {
+  const previewBoxDom = document.querySelector('.go-preview') as HTMLElement
+  if (!previewBoxDom || previewBoxDom.style.position !== 'absolute') return
+  if (!window.$KeyboardActive?.space) return
+
+  e.preventDefault()
+  e.stopPropagation()
+  // @ts-ignore
+  document.activeElement?.blur()
+  const startX = e.screenX
+  const startY = e.screenY
+
+  const listenMousemove = listen(
+    window,
+    'mousemove',
+    throttle((moveEvent: MouseEvent) => {
+      const nx = moveEvent.screenX - startX
+      const ny = moveEvent.screenY - startY
+
+      const [prevMoveX1, prevMoveX2] = prevMoveXValue
+      const [prevMoveY1, prevMoveY2] = prevMoveYValue
+
+      prevMoveXValue = [prevMoveX2, nx]
+      prevMoveYValue = [prevMoveY2, ny]
+
+      // 去除小数部分
+      if (previewBoxDom) {
+        const oldLeft = previewBoxDom.style.left ? Number(previewBoxDom.style.left.split('px')[0]) : 0
+        const oldTop = previewBoxDom.style.top ? Number(previewBoxDom.style.top.split('px')[0]) : 0
+        previewBoxDom.style.left =
+          oldLeft +
+          (prevMoveX2 > prevMoveX1 ? Math.abs(prevMoveX2 - prevMoveX1) : -Math.abs(prevMoveX2 - prevMoveX1)) +
+          'px'
+        previewBoxDom.style.top =
+          oldTop +
+          (prevMoveY2 > prevMoveY1 ? Math.abs(prevMoveY2 - prevMoveY1) : -Math.abs(prevMoveY2 - prevMoveY1)) +
+          'px'
+      }
+    }, 20)
+  )
+
+  const listenMouseup = listen(window, 'mouseup', () => {
+    prevMoveXValue = [0, 0]
+    prevMoveYValue = [0, 0]
+    listenMousemove()
+    listenMouseup()
+  })
+}
diff --git a/src/views/preview/utils/index.ts b/src/views/preview/utils/index.ts
index 1d0be713..c5aa120f 100644
--- a/src/views/preview/utils/index.ts
+++ b/src/views/preview/utils/index.ts
@@ -1,3 +1,4 @@
 export * from './style'
 export * from './storage'
-export * from './keyboard'
\ No newline at end of file
+export * from './keyboard'
+export * from './drag'
\ No newline at end of file
diff --git a/src/views/preview/utils/keyboard.ts b/src/views/preview/utils/keyboard.ts
index 0b895ab4..bacaa4e7 100644
--- a/src/views/preview/utils/keyboard.ts
+++ b/src/views/preview/utils/keyboard.ts
@@ -12,8 +12,16 @@ export const keyRecordHandle = () => {
 
     if ([17, 32].includes(keyCode) && window.$KeyboardActive) {
       switch (keyCode) {
-        case 17: window.$KeyboardActive.ctrl = true; break
-        case 32: window.$KeyboardActive.space = true; break
+        case 17:
+          window.$KeyboardActive.ctrl = true
+          break
+        case 32:
+          window.$KeyboardActive.space = true
+          const previewBoxDom = document.querySelector('.go-preview') as HTMLElement
+          if (previewBoxDom && previewBoxDom.style.position === 'absolute') {
+            previewBoxDom.style.cursor = 'move'
+          }
+          break
       }
     }
   }
@@ -24,9 +32,18 @@ export const keyRecordHandle = () => {
 
     if ([17, 32].includes(keyCode) && window.$KeyboardActive) {
       switch (keyCode) {
-        case 17: window.$KeyboardActive.ctrl = false; break
-        case 32: window.$KeyboardActive.space = false; break
+        case 17:
+          window.$KeyboardActive.ctrl = false
+          break
+        case 32:
+          window.$KeyboardActive.space = false
+          break
       }
     }
+
+    const previewBoxDom = document.querySelector('.go-preview') as HTMLElement
+    if (previewBoxDom) {
+      previewBoxDom.style.cursor = 'default'
+    }
   }
-}
\ No newline at end of file
+}