├── .browserslistrc ├── .npmignore ├── public ├── favicon.ico └── index.html ├── postcss.config.js ├── preview ├── favicon.ico ├── static │ ├── img │ │ ├── ve-bar.fc0a17e5.png │ │ ├── ve-map.ccf2219e.png │ │ ├── ve-pie.987b8426.png │ │ ├── ve-line.75126573.png │ │ ├── ve-radar.2f5b69a2.png │ │ └── ve-histogram.0683a6c8.png │ ├── fonts │ │ ├── iconfont.2b3196f7.ttf │ │ ├── iconfont.abe346b2.eot │ │ ├── iconfont.ac59ffae.woff │ │ ├── element-icons.535877f5.woff │ │ └── element-icons.732389de.ttf │ └── js │ │ ├── chunk-2d0c4a47.0e8656d7.js │ │ ├── chunk-95354e52.42529e2d.js │ │ └── app.6a3a718f.js └── index.html ├── src ├── assets │ └── images │ │ ├── dot.png │ │ ├── ve-bar.png │ │ ├── ve-map.png │ │ ├── ve-pie.png │ │ ├── ve-line.png │ │ ├── ve-radar.png │ │ └── ve-histogram.png ├── utils │ ├── deepClone.js │ ├── render.js │ ├── defaultColors.js │ ├── db.js │ ├── arr-utils.js │ ├── formatData.js │ ├── geoCoordMap.js │ └── database.js ├── App.vue ├── components │ ├── board │ │ ├── options │ │ │ ├── gui-colors.vue │ │ │ ├── gui-inline.vue │ │ │ ├── gui-field.vue │ │ │ ├── gui-group.vue │ │ │ └── gui-wrap.vue │ │ ├── header │ │ │ └── index.vue │ │ ├── canvas │ │ │ ├── components │ │ │ │ └── edit-slider.vue │ │ │ └── index.vue │ │ ├── coverage │ │ │ └── index.vue │ │ ├── index.vue │ │ └── context-menu │ │ │ └── index.vue │ ├── drop │ │ └── drop-panel.vue │ ├── preview │ │ └── preview-box.vue │ ├── drag │ │ ├── DragList.vue │ │ └── DragItem.vue │ └── charts │ │ └── charts-factory.vue ├── styles │ ├── index.styl │ ├── modules │ │ ├── preview.styl │ │ ├── home.styl │ │ └── admin.styl │ ├── common │ │ ├── base.styl │ │ └── var.styl │ └── board │ │ ├── context-menu.styl │ │ ├── canvas.styl │ │ ├── edit-slider.styl │ │ ├── coverage.styl │ │ ├── header-box.styl │ │ ├── options.styl │ │ └── transform-block.styl ├── store │ ├── index.js │ ├── getters.js │ └── modules │ │ ├── app.js │ │ └── canvasMaps.js ├── router │ ├── routes.js │ └── index.js ├── api │ ├── app │ │ └── app-request.js │ ├── canvasMaps │ │ └── canvas-maps-request.js │ ├── api_request.js │ └── datastore.js ├── main.js ├── config │ ├── board.js │ ├── components │ │ ├── line.json │ │ └── test.json │ └── navigate.js └── views │ ├── home.vue │ ├── screen.vue │ └── admin.vue ├── docs ├── .vuepress │ ├── public │ │ ├── hero.jpg │ │ └── favicon.png │ ├── styles │ │ └── palette.styl │ └── config.js ├── README.md └── guide │ └── index.md ├── .editorconfig ├── babel.config.js ├── .gitignore ├── .eslintrc.js ├── README.md ├── vue.config.js ├── LICENSE └── package.json /.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .* 2 | *.md 3 | *.yml 4 | build/ 5 | node_modules/ 6 | test/ 7 | gulpfile.js 8 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangbin3162/bin-data/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {} 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /preview/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangbin3162/bin-data/HEAD/preview/favicon.ico -------------------------------------------------------------------------------- /src/assets/images/dot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangbin3162/bin-data/HEAD/src/assets/images/dot.png -------------------------------------------------------------------------------- /src/assets/images/ve-bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangbin3162/bin-data/HEAD/src/assets/images/ve-bar.png -------------------------------------------------------------------------------- /src/assets/images/ve-map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangbin3162/bin-data/HEAD/src/assets/images/ve-map.png -------------------------------------------------------------------------------- /src/assets/images/ve-pie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangbin3162/bin-data/HEAD/src/assets/images/ve-pie.png -------------------------------------------------------------------------------- /src/utils/deepClone.js: -------------------------------------------------------------------------------- 1 | export function deepClone (obj) { 2 | return JSON.parse(JSON.stringify(obj)) 3 | } 4 | -------------------------------------------------------------------------------- /docs/.vuepress/public/hero.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangbin3162/bin-data/HEAD/docs/.vuepress/public/hero.jpg -------------------------------------------------------------------------------- /src/assets/images/ve-line.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangbin3162/bin-data/HEAD/src/assets/images/ve-line.png -------------------------------------------------------------------------------- /src/assets/images/ve-radar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangbin3162/bin-data/HEAD/src/assets/images/ve-radar.png -------------------------------------------------------------------------------- /docs/.vuepress/public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangbin3162/bin-data/HEAD/docs/.vuepress/public/favicon.png -------------------------------------------------------------------------------- /src/assets/images/ve-histogram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangbin3162/bin-data/HEAD/src/assets/images/ve-histogram.png -------------------------------------------------------------------------------- /preview/static/img/ve-bar.fc0a17e5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangbin3162/bin-data/HEAD/preview/static/img/ve-bar.fc0a17e5.png -------------------------------------------------------------------------------- /preview/static/img/ve-map.ccf2219e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangbin3162/bin-data/HEAD/preview/static/img/ve-map.ccf2219e.png -------------------------------------------------------------------------------- /preview/static/img/ve-pie.987b8426.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangbin3162/bin-data/HEAD/preview/static/img/ve-pie.987b8426.png -------------------------------------------------------------------------------- /preview/static/img/ve-line.75126573.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangbin3162/bin-data/HEAD/preview/static/img/ve-line.75126573.png -------------------------------------------------------------------------------- /preview/static/img/ve-radar.2f5b69a2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangbin3162/bin-data/HEAD/preview/static/img/ve-radar.2f5b69a2.png -------------------------------------------------------------------------------- /preview/static/fonts/iconfont.2b3196f7.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangbin3162/bin-data/HEAD/preview/static/fonts/iconfont.2b3196f7.ttf -------------------------------------------------------------------------------- /preview/static/fonts/iconfont.abe346b2.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangbin3162/bin-data/HEAD/preview/static/fonts/iconfont.abe346b2.eot -------------------------------------------------------------------------------- /preview/static/fonts/iconfont.ac59ffae.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangbin3162/bin-data/HEAD/preview/static/fonts/iconfont.ac59ffae.woff -------------------------------------------------------------------------------- /preview/static/img/ve-histogram.0683a6c8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangbin3162/bin-data/HEAD/preview/static/img/ve-histogram.0683a6c8.png -------------------------------------------------------------------------------- /preview/static/fonts/element-icons.535877f5.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangbin3162/bin-data/HEAD/preview/static/fonts/element-icons.535877f5.woff -------------------------------------------------------------------------------- /preview/static/fonts/element-icons.732389de.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangbin3162/bin-data/HEAD/preview/static/fonts/element-icons.732389de.ttf -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{js,jsx,ts,tsx,vue}] 2 | indent_style = space 3 | indent_size = 2 4 | trim_trailing_whitespace = true 5 | insert_final_newline = true 6 | -------------------------------------------------------------------------------- /docs/.vuepress/styles/palette.styl: -------------------------------------------------------------------------------- 1 | // showing default values 2 | $accentColor = #409EFF 3 | $textColor = #2c3e50 4 | $borderColor = #eaecef 5 | $codeBgColor = #282c34 6 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 12 | -------------------------------------------------------------------------------- /src/components/board/options/gui-colors.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | -------------------------------------------------------------------------------- /src/styles/index.styl: -------------------------------------------------------------------------------- 1 | // 样式引入,所有前缀遵循dv- 及data view缩写,样式单独引入后期可方便打包 2 | @import "./common/base.styl" 3 | @import "./modules/home.styl" 4 | @import "./modules/admin.styl" 5 | @import "./modules/preview.styl" 6 | -------------------------------------------------------------------------------- /src/utils/render.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'RenderCell', 3 | functional: true, 4 | props: { 5 | render: Function 6 | }, 7 | render: (h, ctx) => { 8 | return ctx.props.render(h) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/app' 4 | ], 5 | plugins: [ 6 | [ 7 | 'component', 8 | { 9 | 'libraryName': 'element-ui', 10 | 'styleLibraryName': 'theme-chalk' 11 | } 12 | ] 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /src/utils/defaultColors.js: -------------------------------------------------------------------------------- 1 | export const DEFAULT_COLORS = [ 2 | '#60b8f6', '#55da8d', '#ffcc41', 3 | '#ba5eed', '#ff6e8c', '#1f9bff', 4 | '#e1017e', '#e7641c', '#c1df05', 5 | '#00acc5', '#de0029', '#02af3b', 6 | '#c23531', '#2f4554', '#ca8622', 7 | '#7ec720', '#3c117c', '#0168b3' 8 | ] 9 | -------------------------------------------------------------------------------- /src/styles/modules/preview.styl: -------------------------------------------------------------------------------- 1 | .dv-screen { 2 | height: 100%; 3 | width: 100%; 4 | .canvas-panel { 5 | position: relative; 6 | .preview-box { 7 | position: absolute; 8 | } 9 | } 10 | } 11 | 12 | .dv-screen .bin-scrollbar__wrap { 13 | overflow-x: hidden; 14 | } 15 | -------------------------------------------------------------------------------- /src/components/board/options/gui-inline.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 15 | -------------------------------------------------------------------------------- /src/styles/common/base.styl: -------------------------------------------------------------------------------- 1 | @import "var.styl" 2 | #app { 3 | height: 100%; 4 | color: $color-text-primary; 5 | font-size: 14px; 6 | background-color: $color-main; 7 | } 8 | * { 9 | margin: 0; 10 | padding: 0; 11 | border: 0; 12 | font-size: 100%; 13 | vertical-align: baseline; 14 | } 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw* 22 | -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import app from './modules/app' 4 | import canvasMaps from './modules/canvasMaps' 5 | import getters from './getters' 6 | 7 | Vue.use(Vuex) 8 | 9 | export default new Vuex.Store({ 10 | modules: { 11 | app, canvasMaps 12 | }, 13 | getters 14 | }) 15 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | home: true 3 | heroImage: /hero.jpg 4 | actionText: 快速上手 → 5 | actionLink: /guide/ 6 | features: 7 | - title: 业务提炼 8 | details: 对业务进行封装,提炼基础功能 9 | - title: 组件 10 | details: 简洁的代码、目录、格式,封装部分可复用组件 11 | - title: 技术栈 12 | details: 使用 vue/vuex/vue-router/bin-ui 等前端技术 13 | footer: MIT Licensed | Copyright © 2019-present wang bin 14 | --- 15 | -------------------------------------------------------------------------------- /src/components/board/options/gui-field.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 17 | -------------------------------------------------------------------------------- /src/utils/db.js: -------------------------------------------------------------------------------- 1 | import low from 'lowdb' 2 | import LocalStorage from 'lowdb/adapters/LocalStorage' 3 | import database from './database' 4 | 5 | const adapter = new LocalStorage('bin-data') 6 | const db = low(adapter) 7 | 8 | db 9 | .defaults(database) 10 | .write() 11 | 12 | // db.set('canvasMaps', database.canvasMaps).write() 13 | 14 | export default db 15 | -------------------------------------------------------------------------------- /src/components/board/options/gui-group.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 17 | -------------------------------------------------------------------------------- /src/store/getters.js: -------------------------------------------------------------------------------- 1 | const getters = { 2 | pageSettings: state => state.app.pageSettings, 3 | // 画布缩放 4 | canvasRange: state => state.app.canvasRange, 5 | // 参数面板展开 6 | optionsExpand: state => state.app.optionsExpand, 7 | // 画布映射数组 8 | canvasMap: state => state.canvasMaps.canvasMap, 9 | // 当前选中的 10 | currentSelected: state => state.canvasMaps.singleSelected, 11 | // 右键菜单信息 12 | contextMenuInfo: state => state.canvasMaps.contextMenuInfo 13 | } 14 | 15 | export default getters 16 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true 5 | }, 6 | 'extends': [ 7 | 'plugin:vue/essential', 8 | '@vue/standard' 9 | ], 10 | rules: { 11 | 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', 12 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', 13 | 'indent': 'off', 14 | 'space-before-function-paren': 'off', 15 | 'no-unused-vars': 'off' 16 | }, 17 | parserOptions: { 18 | parser: 'babel-eslint' 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/router/routes.js: -------------------------------------------------------------------------------- 1 | import Home from '../views/home' 2 | 3 | let routes = [ 4 | { 5 | path: '/', 6 | redirect: '/home', 7 | component: Home, 8 | children: [{ 9 | path: 'home', 10 | name: 'home', 11 | component: Home 12 | }] 13 | }, 14 | { 15 | path: '/admin/:id', 16 | name: 'admin', 17 | component: () => import('../views/admin') 18 | }, 19 | { 20 | path: '/screen/:id', 21 | name: 'screen', 22 | component: () => import('../views/screen') 23 | } 24 | ] 25 | 26 | export default routes 27 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueRouter from 'vue-router' 3 | import store from '../store/index' 4 | // 路由数据 5 | import routes from './routes' 6 | 7 | import BinUI from 'bin-ui' 8 | 9 | Vue.use(BinUI) 10 | 11 | Vue.use(VueRouter) 12 | 13 | // 导出路由 在 main.js 里使用 14 | const router = new VueRouter({ 15 | base: process.env.BASE_URL, 16 | routes 17 | }) 18 | 19 | router.beforeEach((to, from, next) => { 20 | BinUI.LoadingBar.start() 21 | store.dispatch('SingleSelected', null) 22 | next() 23 | }) 24 | router.afterEach(() => { 25 | BinUI.LoadingBar.done() 26 | }) 27 | 28 | export default router 29 | -------------------------------------------------------------------------------- /src/styles/common/var.styl: -------------------------------------------------------------------------------- 1 | // 定义基本色系 2 | $color-main = #171b22 3 | $color-primary = #00baff 4 | $color-blue = #1a8ae4 5 | $color-text-primary = #ffffff 6 | $color-text-info = #bcc9d4 7 | $color-linear-gradient = #00baff 8 | 9 | $color-admin-main = #222528 10 | $color-admin-ctrl = #1b1f25 11 | $color-admin-ctrl-header = #2e343c 12 | $color-admin-options-dark = #0e1013 13 | $color-admin-options-hover = #212631 14 | $color-admin-options-bg = #1b1f25 15 | $color-admin-canvas = #2a2e33 16 | 17 | $color-admin-context-menu = #27343e 18 | $color-admin-context-menu-color = #bcc9d4 19 | 20 | //指示线 21 | $color-navigator-line = #05ddff 22 | -------------------------------------------------------------------------------- /src/api/app/app-request.js: -------------------------------------------------------------------------------- 1 | // import request from '../api_request' 2 | import * as api from '../datastore' 3 | 4 | // 获取页面参数信息 5 | export function getPageSettings () { 6 | return api.getPageSettings() 7 | // return request({ 8 | // url: '/getPageSettings', 9 | // method: 'get' 10 | // }) 11 | } 12 | 13 | // 设置页面参数信息 14 | export function setPageSettings (setting) { 15 | return api.setPageSettings(setting) 16 | } 17 | 18 | // 重置页面参数配置 19 | export function resetPageSettings () { 20 | return api.resetPageSettings() 21 | } 22 | 23 | // 初始化所有参数配置 24 | export function initLocalData () { 25 | return api.initLocalData() 26 | } 27 | -------------------------------------------------------------------------------- /docs/guide/index.md: -------------------------------------------------------------------------------- 1 | # 入门 2 | 3 | 本项目是基于 Vue2.6,配合使用 [bin-ui](https://github.com/wangbin3162/bin-ui/) 作为组件库来进行搭建, 4 | 参考阿里DataV来实现的一套数据可视化配置系统,主要实现对百度地图的多拽生成和动态配置。 5 | 6 | 现已实现一版简易版,包括折线图,中国地图,柱状图,饼状图,条形图,雷达图等6个图标的样式配置和数据配置,后续继续进行完善补充,现发布第一版 7 | 文档及预览,后续持续更新... 8 | 9 | ## 功能概述 10 | 11 | - lowdb实现本地数据配置,后续实现持久化更新 12 | - 初始化数据库后可进行拖拽移动 13 | - 图表可以动态进行样式设置和数据设置 14 | 15 | 16 | 注:仅列举部分组件和功能 17 | 18 | 19 | ## 安装 20 | 21 | ```bash 22 | # 克隆项目 23 | git clone https://github.com/wangbin3162/bin-data.git 24 | 25 | # 安装依赖 26 | npm install 27 | 28 | # 本地开发 启动项目 29 | npm run serve 30 | # OR vue ui 图形化界面启动 31 | vue ui 32 | ``` 33 | 34 | 文档持续更新中... 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # bin-data 2 | 3 | [预览](https://wangbin3162.github.io/bin-data/) 4 | 5 | # 入门 6 | 7 | 本项目是基于 Vue2.6,配合使用 [bin-ui](https://github.com/wangbin3162/bin-ui/) 作为组件库来进行搭建, 8 | 参考阿里DataV来实现的一套数据可视化配置系统,主要实现对百度地图的多拽生成和动态配置。 9 | 10 | 现已实现一版简易版,包括折线图,中国地图,柱状图,饼状图,条形图,雷达图等6个图标的样式配置和数据配置,后续继续进行完善补充,现发布第一版 11 | 文档及预览,后续持续更新... 12 | 13 | ## 功能概述 14 | 15 | - lowdb实现本地数据配置,后续实现持久化更新 16 | - 初始化数据库后可进行拖拽移动 17 | - 图表可以动态进行样式设置和数据设置 18 | 19 | 20 | 注:仅列举部分组件和功能 21 | 22 | 23 | ## 安装 24 | 25 | ```bash 26 | # 克隆项目 27 | git clone https://github.com/wangbin3162/bin-data.git 28 | 29 | # 安装依赖 30 | npm install 31 | 32 | # 本地开发 启动项目 33 | npm run serve 34 | # OR vue ui 图形化界面启动 35 | vue ui 36 | ``` 37 | 38 | 文档持续更新中... 39 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import router from './router' 4 | import store from './store' 5 | import { Button, ColorPicker, Select, Option } from 'element-ui' 6 | import BinUI from 'bin-ui' 7 | import VCharts from 'v-charts' 8 | import 'bin-ui/lib/styles/index.css' 9 | import './styles/index.styl' 10 | 11 | // element-ui 局部引用 12 | Vue.use(Button) 13 | Vue.use(ColorPicker) 14 | Vue.use(Select) 15 | Vue.use(Option) 16 | 17 | Vue.use(BinUI) 18 | Vue.use(VCharts) 19 | 20 | Vue.prototype.$EventBus = new Vue() 21 | Vue.prototype.$base = process.env.NODE_ENV === 'production' ? '/bin-data-site' : '' 22 | 23 | new Vue({ 24 | router, 25 | store, 26 | render: h => h(App) 27 | }).$mount('#app') 28 | -------------------------------------------------------------------------------- /src/config/board.js: -------------------------------------------------------------------------------- 1 | // 画板默认布局配置 2 | export default { 3 | // 编辑器功能:头部组件 4 | header: { 5 | // 标题配置 6 | title: { 7 | text: '当前工作空间' 8 | }, 9 | // 该功能数据源 10 | data: [], 11 | // 初始化数据 12 | initData: [] 13 | }, 14 | // 左侧功能栏 15 | coverage: { 16 | // 是否启用该功能,true: 启用 false: 不启用 17 | enable: true, 18 | // 标题配置 19 | title: { 20 | enable: true, 21 | text: '图层' 22 | }, 23 | // 样式 24 | style: { 25 | width: '180px', 26 | flex: '0 0 180px' 27 | } 28 | }, 29 | // 表单元素配置组件 30 | options: { 31 | // 标题配置 32 | title: { 33 | enable: true, 34 | text: '页面设置' 35 | }, 36 | style: { 37 | width: '300px' 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/styles/board/context-menu.styl: -------------------------------------------------------------------------------- 1 | @import "../common/var.styl" 2 | .dv-context-menu { 3 | position: fixed; 4 | z-index: 9999; 5 | background: $color-admin-context-menu; 6 | color: $color-admin-context-menu-color; 7 | user-select: none; 8 | .context-menu-item { 9 | padding: 0 6px; 10 | line-height: 28px; 11 | height: 28px; 12 | border-left: 2px solid transparent; 13 | cursor: pointer; 14 | overflow: hidden; 15 | padding-right: 3em; 16 | display: flex; 17 | .iconfont { 18 | margin-right: 3px; 19 | line-height: 28px; 20 | width: 16px; 21 | } 22 | &:hover { 23 | background-color: #1d262e; 24 | color: #00baff; 25 | border-left: 2px solid #00baff; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | // 配置路径别名 2 | var path = require('path') 3 | 4 | function resolve (dir) { 5 | return path.join(__dirname, dir) 6 | } 7 | 8 | module.exports = { 9 | // 配置基础链接地址,根据发布环境添加 10 | publicPath: process.env.NODE_ENV === 'production' 11 | ? '' 12 | : '/', 13 | outputDir: 'preview', 14 | // dev跨域问题 15 | // devServer: { 16 | // proxy: { 17 | // '/admin': { target: 'http://localhost:8088/cms' } 18 | // } 19 | // }, 20 | productionSourceMap: false, 21 | lintOnSave: process.env.NODE_ENV !== 'production', 22 | assetsDir: 'static', 23 | filenameHashing: true, // 发布打包文件是否有哈希后缀 24 | chainWebpack: config => { 25 | config.resolve.alias 26 | .set('@', resolve('src')) // key,value自行定义,比如.set('@@', resolve('src/components')) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/utils/arr-utils.js: -------------------------------------------------------------------------------- 1 | export function toFirst (fieldData, index) { 2 | let arr = [...fieldData] 3 | if (index !== 0) { 4 | arr.unshift(arr.splice(index, 1)[0]) 5 | } 6 | return arr 7 | } 8 | 9 | export function toLast (fieldData, index) { 10 | let arr = [...fieldData] 11 | if (index !== arr.length - 1) { 12 | arr.push(arr.shift()) 13 | } 14 | return arr 15 | } 16 | 17 | export function upGo (fieldData, index) { 18 | let arr = [...fieldData] 19 | if (index !== 0) { 20 | arr[index] = arr.splice(index - 1, 1, arr[index])[0] 21 | } 22 | return arr 23 | } 24 | 25 | export function downGo (fieldData, index) { 26 | let arr = [...fieldData] 27 | if (index !== arr.length - 1) { 28 | arr[index] = arr.splice(index + 1, 1, arr[index])[0] 29 | } 30 | return arr 31 | } 32 | -------------------------------------------------------------------------------- /src/store/modules/app.js: -------------------------------------------------------------------------------- 1 | const app = { 2 | state: { 3 | pageSettings: { width: 1920, height: 1080, backgroundColor: '#0d2a42', gridStep: 1 }, 4 | // 状态数据 5 | canvasRange: 0, // 画布缩放 6 | optionsExpand: true // 参数面板打开关闭 7 | }, 8 | mutations: { 9 | SET_CANVAS_RANGE: (state, val) => { 10 | state.canvasRange = val 11 | }, 12 | SET_OPTIONS_EXPAND: (state) => { 13 | state.optionsExpand = !state.optionsExpand 14 | }, 15 | SET_PAGE_SETTING: (state, setting) => { 16 | state.pageSettings = { ...setting } 17 | } 18 | }, 19 | actions: { 20 | SetCanvasRange: ({ commit }, val) => { 21 | commit('SET_CANVAS_RANGE', val) 22 | }, 23 | ToggleOptionsExpand: ({ commit }) => { 24 | commit('SET_OPTIONS_EXPAND') 25 | }, 26 | SetPageSettings: ({ commit }, setting) => { 27 | commit('SET_PAGE_SETTING', setting) 28 | } 29 | } 30 | } 31 | 32 | export default app 33 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | bin-data 9 | 26 | 27 | 28 |
29 | 30 | 31 | -------------------------------------------------------------------------------- /src/styles/board/canvas.styl: -------------------------------------------------------------------------------- 1 | .canvas-main { 2 | position: relative; 3 | width: 100%; 4 | height: 100%; 5 | overflow: hidden; 6 | user-select: none; 7 | background: #26282d url('../assets/images/dot.png') repeat; 8 | .canvas-panel-wrap { 9 | width: 100%; 10 | height: calc(100% - 30px); 11 | overflow: hidden; 12 | position: relative; 13 | .screen-shot { 14 | position: relative; 15 | .canvas-panel { 16 | position: absolute; 17 | transform-origin: 0 0; 18 | top: 60px; 19 | left: 60px; 20 | transition: .2s all ease-in-out; 21 | background-size: cover, contain; 22 | background-position: center, right bottom; 23 | background-repeat: no-repeat, no-repeat; 24 | box-shadow: rgba(0, 0, 0, .5) 0 0 30px 0; 25 | .drop-panel { 26 | width: 100%; 27 | height: 100%; 28 | } 29 | } 30 | } 31 | } 32 | } 33 | 34 | // 需要覆盖bin-ui的样式 35 | .canvas-panel-wrap .bin-scrollbar__wrap { 36 | overflow-x: hidden; 37 | } 38 | -------------------------------------------------------------------------------- /docs/.vuepress/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | title: '[bin-data]说明文档', 3 | description: '基于bin-ui echarts的数据可视化平台', 4 | // 注入到当前页面的 HTML 中的标签 5 | head: [ 6 | ['link', { rel: 'icon', href: '/favicon.png' }], // 增加一个自定义的 favicon(网页标签的图标) 7 | ], 8 | base: '/docs/bin-data/', 9 | markdown: { 10 | lineNumbers: true // 代码块显示行号 11 | }, 12 | themeConfig: { 13 | sidebarDepth: 2, // e'b将同时提取markdown中h2 和 h3 标题,显示在侧边栏上。 14 | lastUpdated: 'Last Updated', // 文档更新时间:每个文件git最后提交的时间 15 | nav: [ 16 | { text: '指南', link: '/guide/' }, 17 | { text: 'bin-ui', link: 'https://wangbin3162.github.io/docs/bin-ui/' }, 18 | { text: '预览', link: 'https://wangbin3162.github.io/preview/bin-data/' }, 19 | { text: 'GitHub', link: 'https://github.com/wangbin3162/bin-data' } 20 | ], 21 | sidebar: { 22 | // 第一组侧边栏 23 | '/guide/': [ 24 | { 25 | collapsable: false, 26 | children: [ 27 | ['/guide/', '入门'] 28 | ] 29 | } 30 | ] 31 | } 32 | } 33 | } 34 | 35 | -------------------------------------------------------------------------------- /src/components/drop/drop-panel.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 39 | -------------------------------------------------------------------------------- /src/config/components/line.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "x": "1/1", 4 | "y": 375, 5 | "s": "系列1" 6 | }, 7 | { 8 | "x": "1/1", 9 | "y": 123, 10 | "s": "系列2" 11 | }, 12 | { 13 | "x": "1/2", 14 | "y": 200, 15 | "s": "系列1" 16 | }, 17 | { 18 | "x": "1/2", 19 | "y": 122, 20 | "s": "系列2" 21 | }, 22 | { 23 | "x": "1/3", 24 | "y": 25, 25 | "s": "系列1" 26 | }, 27 | { 28 | "x": "1/3", 29 | "y": 231, 30 | "s": "系列2" 31 | }, 32 | { 33 | "x": "1/4", 34 | "y": 190, 35 | "s": "系列1" 36 | }, 37 | { 38 | "x": "1/4", 39 | "y": 11, 40 | "s": "系列2" 41 | }, 42 | { 43 | "x": "1/5", 44 | "y": 90, 45 | "s": "系列1" 46 | }, 47 | { 48 | "x": "1/5", 49 | "y": 134, 50 | "s": "系列2" 51 | }, 52 | { 53 | "x": "1/6", 54 | "y": 233, 55 | "s": "系列1" 56 | }, 57 | { 58 | "x": "1/6", 59 | "y": 155, 60 | "s": "系列2" 61 | }, 62 | { 63 | "x": "1/7", 64 | "y": 120, 65 | "s": "系列1" 66 | }, 67 | { 68 | "x": "1/7", 69 | "y": 333, 70 | "s": "系列2" 71 | } 72 | ] 73 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2019 bin-data/wang bin 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the “Software”), to deal in the 6 | Software without restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 8 | the Software, and to permit persons to whom the Software is furnished to do so, 9 | subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 17 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 18 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH 19 | THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /src/components/preview/preview-box.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 49 | -------------------------------------------------------------------------------- /src/styles/board/edit-slider.styl: -------------------------------------------------------------------------------- 1 | @import "../common/var.styl" 2 | // 下方缩放条 3 | .board-edit-slider { 4 | background: $color-admin-main; 5 | height: 30px; 6 | width: 100%; 7 | display: flex; 8 | align-items: center; 9 | justify-content: flex-end; 10 | position: absolute; 11 | right: 0; 12 | bottom: 0; 13 | z-index: 99; 14 | .label { 15 | font-size: 12px; 16 | line-height: 18px; 17 | padding: 0 5px; 18 | color: $color-text-info; 19 | } 20 | .data-slider { 21 | display: flex; 22 | right: 4px; 23 | align-items: center; 24 | .input-range { 25 | cursor: pointer; 26 | height: 2px; 27 | -webkit-appearance: none; 28 | box-sizing: border-box; 29 | outline: 0; 30 | margin: 0; 31 | display: inline-block; 32 | &::-webkit-slider-thumb { 33 | -webkit-appearance: none; /*清除系统默认样式*/ 34 | height: 12px; /*拖动块高度*/ 35 | width: 12px; /*拖动块宽度*/ 36 | background: #fff; /*拖动块背景*/ 37 | border: solid 1px #202020; /*设置边框*/ 38 | } 39 | } 40 | .iconfont { 41 | color: $color-text-info; 42 | font-size: 18px; 43 | margin: 0 8px; 44 | &.zoom-out { 45 | cursor: zoom-out; 46 | } 47 | &.zoom-in { 48 | cursor: zoom-in; 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/utils/formatData.js: -------------------------------------------------------------------------------- 1 | // 处理图表数据源,换算为v-charts数据结构 2 | import { geoCoordMap } from './geoCoordMap' 3 | 4 | export function formatData (source) { 5 | const apiData = { 6 | columns: [], 7 | rows: [] 8 | } 9 | const map = new Map() 10 | 11 | source.forEach(item => { 12 | let obj = {} 13 | if (item.x) { 14 | apiData.columns[0] = 'x' 15 | obj['x'] = item.x 16 | } 17 | // 如果系列值存在且column中不包含这个系列则增加一个系列 18 | if (item.s) { 19 | if (!apiData.columns.includes(item.s)) { 20 | apiData.columns.push(item.s) 21 | } 22 | obj[item.s] = item.y 23 | } else { 24 | apiData.columns[1] = 's' 25 | obj['s'] = item.y 26 | } 27 | if (map.has(item.x)) { 28 | let temp = Object.assign(map.get(item.x), obj) 29 | map.set(item.x, temp) 30 | } else { 31 | map.set(item.x, obj) 32 | } 33 | }) 34 | apiData.rows = [...map.values()] 35 | return apiData 36 | } 37 | 38 | export function convertData (data) { 39 | let res = [] 40 | for (let i = 0; i < data.length; i++) { 41 | let geoCoord = geoCoordMap[data[i].name] 42 | if (geoCoord) { 43 | res.push({ 44 | name: data[i].name, 45 | value: geoCoord.concat(data[i].value), 46 | selected: false 47 | }) 48 | } 49 | } 50 | return res 51 | } 52 | -------------------------------------------------------------------------------- /preview/index.html: -------------------------------------------------------------------------------- 1 | bin-data
-------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bin-data", 3 | "version": "0.1.0", 4 | "description": "大数据基础框架", 5 | "keywords": [ 6 | "bin-ui", 7 | "bin", 8 | "ui", 9 | "vue", 10 | "vue", 11 | "components" 12 | ], 13 | "author": "wang bin", 14 | "files": [ 15 | "lib", 16 | "src" 17 | ], 18 | "private": false, 19 | "license": "MIT", 20 | "scripts": { 21 | "serve": "vue-cli-service serve", 22 | "build": "vue-cli-service build", 23 | "lint": "vue-cli-service lint", 24 | "dev:doc": "vuepress dev docs", 25 | "build:doc": "vuepress build docs" 26 | }, 27 | "dependencies": { 28 | "axios": "^0.19.0", 29 | "bin-ui": "^2.0.2", 30 | "core-js": "^2.6.5", 31 | "echarts": "^4.2.1", 32 | "element-ui": "^2.9.1", 33 | "lodash": "^4.17.11", 34 | "lowdb": "^1.0.0", 35 | "qs": "^6.7.0", 36 | "v-charts": "^1.19.0", 37 | "vue": "^2.6.10", 38 | "vue-router": "^3.0.3", 39 | "vuex": "^3.0.1" 40 | }, 41 | "devDependencies": { 42 | "@vue/cli-plugin-babel": "^3.8.0", 43 | "@vue/cli-plugin-eslint": "^3.8.0", 44 | "@vue/cli-service": "^3.8.0", 45 | "@vue/eslint-config-standard": "^4.0.0", 46 | "babel-eslint": "^10.0.1", 47 | "babel-plugin-component": "^1.1.1", 48 | "eslint": "^5.16.0", 49 | "eslint-plugin-vue": "^5.0.0", 50 | "stylus": "^0.54.5", 51 | "stylus-loader": "^3.0.2", 52 | "vue-template-compiler": "^2.5.21", 53 | "vuepress": "^1.0.2" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/views/home.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 48 | -------------------------------------------------------------------------------- /src/api/canvasMaps/canvas-maps-request.js: -------------------------------------------------------------------------------- 1 | // import request from '../api_request' 2 | import * as api from '../datastore' 3 | import { deepClone } from '../../utils/deepClone' 4 | 5 | // 获取所有的maps 6 | export function getCanvasMaps () { 7 | return api.getCanvasMaps() 8 | // return request({ 9 | // url: '/getPageSettings', 10 | // method: 'get' 11 | // }) 12 | } 13 | 14 | // 修改当前的map 15 | export function setBaseProperty (currentMaps) { 16 | return api.setBaseProperty(currentMaps) 17 | } 18 | 19 | // 增加一个canvasmap 20 | export function addCanvasMap (map) { 21 | return api.addCanvasMap(map) 22 | } 23 | 24 | // 置顶一个canvasmap 25 | export function topCanvasMap (map) { 26 | return api.topCanvasMap(map) 27 | } 28 | 29 | // 置底一个canvasmap 30 | export function bottomCanvasMap (map) { 31 | return api.bottomCanvasMap(map) 32 | } 33 | 34 | // 置底一个canvasmap 35 | export function upCanvasMap (map) { 36 | return api.upCanvasMap(map) 37 | } 38 | 39 | // 置底一个canvasmap 40 | export function downCanvasMap (map) { 41 | return api.downCanvasMap(map) 42 | } 43 | 44 | // copy一个canvasmap 45 | export function copyCanvasMap (map) { 46 | let newMap = deepClone(map)// 深拷贝一个对象并修改默认信息, 47 | newMap.id = 'node-' + ((new Date()).getTime()) // 修改生成的id 48 | // 修改复制出来的位置信息 49 | newMap.packageJson.view.x += 20 50 | newMap.packageJson.view.y += 20 51 | return api.addCanvasMap(newMap) 52 | } 53 | 54 | // 删除一个canvasmap 55 | export function removeCanvasMap (map) { 56 | return api.removeCanvasMap(map) 57 | } 58 | -------------------------------------------------------------------------------- /src/styles/modules/home.styl: -------------------------------------------------------------------------------- 1 | @import "../common/var.styl" 2 | .dv-home { 3 | header { 4 | height: 60px; 5 | line-height: 60px; 6 | box-sizing: border-box; 7 | padding: 0 30px; 8 | border-bottom: 1px solid $color-blue; 9 | background: linear-gradient(180deg, transparent, #171b22); 10 | .head-title { 11 | font-size: 24px; 12 | font-weight: 600; 13 | color: $color-blue; 14 | background-image: -webkit-gradient(linear, left 0, right 0, from($color-primary), to($color-blue)); 15 | -webkit-background-clip: text; 16 | } 17 | } 18 | .dv-container { 19 | width: 100%; 20 | height: calc(100vh - 60px); 21 | overflow: hidden; 22 | .dv-ctrl { 23 | padding: 40px; 24 | text-align: center; 25 | display: flex; 26 | justify-content: center; 27 | align-items: center; 28 | .btn { 29 | display: flex; 30 | justify-content: center; 31 | align-items: center; 32 | height: 184px; 33 | width: 258px; 34 | margin: 16px; 35 | border: 1px solid #00baff; 36 | font-size: 18px; 37 | color: #8eeeff; 38 | text-decoration: none; 39 | transition: all .3s; 40 | background-image: linear-gradient(-90deg, rgba(0, 222, 255, .39) 0, rgba(0, 174, 255, .19) 100%); 41 | box-shadow: 0 0 10px 0 rgba(55, 224, 255, .3); 42 | cursor: pointer; 43 | &:hover { 44 | font-size: 20px; 45 | } 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/components/board/header/index.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 49 | -------------------------------------------------------------------------------- /src/components/board/canvas/components/edit-slider.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 53 | -------------------------------------------------------------------------------- /src/components/board/options/gui-wrap.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 60 | -------------------------------------------------------------------------------- /src/styles/modules/admin.styl: -------------------------------------------------------------------------------- 1 | @import "../common/var.styl" 2 | @import "../board/header-box.styl" 3 | @import "../board/coverage.styl" 4 | @import "../board/edit-slider.styl" 5 | @import "../board/canvas.styl" 6 | @import "../board/transform-block.styl" 7 | @import "../board/options.styl" 8 | @import "../board/context-menu.styl" 9 | // 主体布局 10 | .dv-admin { 11 | width: 100%; 12 | height: 100%; 13 | overflow: hidden; 14 | .board-layout { 15 | position: relative; 16 | width: 100%; 17 | height: 100%; 18 | display: inline-block; 19 | background: #ffffff; 20 | overflow: hidden; 21 | cursor: default; 22 | user-select: none; 23 | font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif; 24 | -webkit-font-smoothing: antialiased; 25 | -moz-osx-font-smoothing: grayscale; 26 | box-sizing: border-box; 27 | .center-box { 28 | position: relative; 29 | height: 100%; 30 | padding-top: 40px; 31 | .board-center { 32 | position: absolute; 33 | top: 40px; 34 | left: 0; 35 | right: 300px; 36 | bottom: 0; 37 | transition: right .3s; 38 | } 39 | } 40 | } 41 | } 42 | 43 | .delete-dialog { 44 | .bin-modal-content { 45 | background: #27343e; 46 | } 47 | .bin-modal-footer { 48 | border-top: 1px solid #3a4659; 49 | } 50 | .delete-dialog-inner { 51 | text-align: center; 52 | padding-top: 30px; 53 | .iconfont { 54 | color: #ff4f43; 55 | } 56 | p { 57 | padding: 10px; 58 | font-size: 14px; 59 | color: #fff; 60 | } 61 | } 62 | } 63 | 64 | // 覆盖样式 65 | .bin-modal-mask { 66 | background-color: rgba(0, 0, 0, .35); 67 | } 68 | 69 | -------------------------------------------------------------------------------- /src/styles/board/coverage.styl: -------------------------------------------------------------------------------- 1 | @import "../common/var.styl" 2 | // 左侧图层列表 3 | .board-coverage { 4 | background: $color-admin-ctrl; 5 | .header-title { 6 | height: 30px; 7 | line-height: 30px; 8 | padding-left: 10px; 9 | background: $color-admin-ctrl-header; 10 | font-size: 12px; 11 | color: $color-text-info; 12 | } 13 | .control { 14 | display: flex; 15 | justify-content: center; 16 | align-items: center; 17 | height: 30px; 18 | border-bottom: 2px solid #282f3a; 19 | opacity: .3; 20 | .iconfont { 21 | padding: 2px; 22 | font-size: 14px; 23 | background-color: #282f3a; 24 | color: #8cc7ff; 25 | margin: 0 8px; 26 | } 27 | &.selected { 28 | opacity: 1; 29 | .iconfont { 30 | cursor: pointer; 31 | &:hover { 32 | color: #fff; 33 | background-color: #2d8cf0; 34 | } 35 | } 36 | } 37 | } 38 | .control-body { 39 | width: 100%; 40 | height: 100%; 41 | overflow: hidden; 42 | .body-wrap { 43 | width: 100%; 44 | height: 100%; 45 | padding: 5px; 46 | .list-item { 47 | position: relative; 48 | padding: 0 6px; 49 | line-height: 26px; 50 | cursor: pointer; 51 | transition: all 0.2s ease-in-out; 52 | color: $color-text-info; 53 | span { 54 | display: inline-block; 55 | vertical-align: middle; 56 | text-indent: 7px; 57 | font-size: 12px; 58 | } 59 | &.hovered { 60 | background-color: rgba(143, 255, 255, .1); 61 | } 62 | &.selected { 63 | background-color: $color-blue; 64 | } 65 | } 66 | } 67 | } 68 | } 69 | 70 | // 需要覆盖bin-ui的样式 71 | .body-wrap .bin-scrollbar__wrap { 72 | overflow-x: hidden; 73 | } 74 | -------------------------------------------------------------------------------- /src/views/screen.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 55 | -------------------------------------------------------------------------------- /src/components/board/coverage/index.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 62 | -------------------------------------------------------------------------------- /src/components/board/index.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 64 | -------------------------------------------------------------------------------- /preview/static/js/chunk-2d0c4a47.0e8656d7.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d0c4a47"],{"3c67":function(t,a,e){"use strict";e.r(a);var n=function(){var t=this,a=t.$createElement,e=t._self._c||a;return e("div",{staticClass:"dv-screen"},[e("b-scrollbar",{staticStyle:{height:"100%"}},[e("div",{staticClass:"canvas-panel",style:t.canvasPanelStyle},[t._l(t.canvasMap,function(t){return[e("preview-box",{key:t.id,attrs:{item:t}},[e("charts-factory",{attrs:{"type-name":t.packageJson.name,config:t.packageJson.config,"api-data":t.packageJson.api_data,apis:t.packageJson.apis}})],1)]})],2)])],1)},s=[],c=e("cebc"),i=e("2f62"),r=e("c15d"),o=e("549b"),p=e("0324"),h=function(){var t=this,a=t.$createElement,e=t._self._c||a;return e("div",{staticClass:"preview-box",style:t.contentStyles},[e("div",{staticClass:"preview-wrap",style:t.dvWrapperStyles},[t._t("default")],2)])},l=[],d={props:{item:{type:Object,required:!0}},created:function(){this.transformData=Object(c["a"])({},this.item.packageJson.view)},watch:{item:{handler:function(t){t&&(this.transformData=Object(c["a"])({},t.packageJson.view))},deep:!0}},computed:{contentStyles:function(){return{width:this.transformData.width+"px",height:this.transformData.height+"px",transform:"translate3d(".concat(this.transformData.x,"px,").concat(this.transformData.y,"px,0)")}},dvWrapperStyles:function(){return{transform:"translateZ(0)",width:this.transformData.width+"px",height:this.transformData.height+"px",padding:"10px 0"}}}},u=d,f=e("2877"),g=Object(f["a"])(u,h,l,!1,null,null,null),v=g.exports,m={name:"screen",components:{ChartsFactory:p["a"],PreviewBox:v},data:function(){return{}},computed:Object(c["a"])({},Object(i["c"])(["canvasMap","pageSettings"]),{canvasPanelStyle:function(){return{width:"".concat(this.pageSettings.width,"px"),height:"".concat(this.pageSettings.height,"px"),backgroundColor:this.pageSettings.backgroundColor}}}),created:function(){var t=this;Object(r["a"])().then(function(a){t.$store.dispatch("SetPageSettings",a.data),console.log(a.data)}),Object(o["e"])().then(function(a){t.$store.dispatch("InitCanvasMaps",a.data)})}},w=m,b=Object(f["a"])(w,n,s,!1,null,null,null);a["default"]=b.exports}}]); -------------------------------------------------------------------------------- /src/components/drag/DragList.vue: -------------------------------------------------------------------------------- 1 | 34 | 35 | 67 | -------------------------------------------------------------------------------- /src/config/components/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "ml-area-basic_rny2b", 3 | "packageJson": { 4 | "api_data": { 5 | "source": [ 6 | { 7 | "x": "2010/01/01 00:00:00", 8 | "y": 666 9 | }, 10 | { 11 | "x": "2010/02/01 00:00:00", 12 | "y": 200 13 | }, 14 | { 15 | "x": "2010/03/01 00:00:00", 16 | "y": 555 17 | }, 18 | { 19 | "x": "2010/04/01 00:00:00", 20 | "y": 190 21 | }, 22 | { 23 | "x": "2010/05/01 00:00:00", 24 | "y": 90 25 | }, 26 | { 27 | "x": "2010/06/01 00:00:00", 28 | "y": 237 29 | } 30 | ] 31 | }, 32 | "apis": { 33 | "source": { 34 | "description": "区域图接口", 35 | "fields": { 36 | "s": { 37 | "description": "系列(可选)", 38 | "optional": true 39 | }, 40 | "x": { 41 | "description": "类目" 42 | }, 43 | "y": { 44 | "description": "值" 45 | } 46 | }, 47 | "handler": "render" 48 | } 49 | }, 50 | "cn_name": "区域图", 51 | "config": { 52 | "chart": { 53 | "emptyData": true, 54 | "fontFamily": "Microsoft Yahei", 55 | "loadAmount": 2000, 56 | "margin": { 57 | "top": 0, 58 | "right": 0, 59 | "bottom": 0, 60 | "left": 0 61 | } 62 | }, 63 | "title": { 64 | "content": "主标题", 65 | "textStyle": { 66 | "color": "rgba(255,255,255,0.6)", 67 | "fontSize": 20, 68 | "fontWeight": "normal" 69 | } 70 | }, 71 | "animation": { 72 | "animationDuration": 1000, 73 | "animationDurationUpdate": 300, 74 | "animationEasing": "cubicInOut", 75 | "animationUpdateFromPrevious": true, 76 | "show": true 77 | } 78 | }, 79 | "icon": "", 80 | "level": 0, 81 | "name": "ml-area-basic", 82 | "protocol": 2, 83 | "type": [ 84 | "regular_area" 85 | ], 86 | "validate": {}, 87 | "view": { 88 | "height": 200, 89 | "width": 300, 90 | "zIndex": 1010 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/components/board/context-menu/index.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 72 | -------------------------------------------------------------------------------- /src/api/api_request.js: -------------------------------------------------------------------------------- 1 | /** 2 | *创建axios服务实例 3 | */ 4 | import httpRequest from 'axios' 5 | import Qs from 'qs' 6 | import { messages } from 'bin-ui' 7 | 8 | let baseUrl = process.env.NODE_ENV !== 'production' ? '/' : '/admin' 9 | const service = httpRequest.create({ 10 | baseURL: baseUrl, 11 | headers: { 12 | 'X-Requested-With': 'XMLHttpRequest' 13 | }, 14 | timeout: 60000 // 请求超时时间 15 | }) 16 | /** 17 | * respone拦截器 18 | */ 19 | service.interceptors.response.use( 20 | response => { 21 | return response 22 | }, 23 | error => { 24 | if (error.response) { 25 | messages({ content: error.response.data, type: 'danger', duration: 5 }) 26 | } else { 27 | messages({ content: error.message, type: 'danger', duration: 5 }) 28 | } 29 | return Promise.reject(error) 30 | } 31 | ) 32 | 33 | export default service 34 | 35 | /** 36 | * get请求 37 | * @param url 38 | * @param data 39 | */ 40 | export function requestGetNoData (url) { 41 | return service({ 42 | url: url, 43 | method: 'get' 44 | }) 45 | } 46 | 47 | export function requestGet (url, data) { 48 | return service({ 49 | url: url, 50 | method: 'get', 51 | params: data 52 | }) 53 | } 54 | 55 | /** 56 | * post请求 57 | * @param url 58 | * @param data 59 | */ 60 | export function requestPost (url, data) { 61 | return service({ 62 | url: url, 63 | method: 'post', 64 | transformRequest: [function (data) { 65 | data = Qs.stringify(data) 66 | return data 67 | }], 68 | headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, 69 | data: data 70 | }) 71 | } 72 | 73 | /** 74 | * post请求 75 | * @param url 76 | * @param data 77 | */ 78 | export function requestPost2 (url, data) { 79 | return service({ 80 | url: url, 81 | method: 'post', 82 | data: data 83 | }) 84 | } 85 | 86 | /** 87 | * post请求 88 | * @param url 89 | * @param formData 90 | */ 91 | export function requestPostFormData (url, data) { 92 | return service({ 93 | url: url, 94 | method: 'post', 95 | headers: { 'Content-Type': 'multipart/form-data' }, 96 | data: data 97 | }) 98 | } 99 | 100 | /** 101 | * 向formData中添加新的项,如果值为null则跳过 102 | * @param formData FormData 103 | * @param name 参数名 104 | * @param value 参数值 105 | */ 106 | export function appendFormData (formData, name, value) { 107 | if (value != null) { 108 | formData.append(name, value) 109 | } 110 | } 111 | 112 | export function getBaseUrl () { 113 | return baseUrl 114 | } 115 | 116 | export function requestGet2 (url, data, downloadProcess) { 117 | return service({ 118 | timeout: 10000 * 60, // 请求超时时间 119 | url: url, 120 | method: 'get', 121 | params: data, 122 | headers: { 'Content-Type': 'application/octet-stream;charset=utf-8' }, 123 | responseType: 'arraybuffer', 124 | onDownloadProgress: downloadProcess 125 | }) 126 | } 127 | -------------------------------------------------------------------------------- /src/components/board/canvas/index.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 99 | -------------------------------------------------------------------------------- /src/components/charts/charts-factory.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 138 | -------------------------------------------------------------------------------- /src/store/modules/canvasMaps.js: -------------------------------------------------------------------------------- 1 | import { 2 | addCanvasMap, 3 | bottomCanvasMap, 4 | copyCanvasMap, downCanvasMap, 5 | removeCanvasMap, 6 | topCanvasMap, upCanvasMap 7 | } from '../../api/canvasMaps/canvas-maps-request' 8 | 9 | const canvasMaps = { 10 | state: { 11 | canvasMap: [], // 画布中的组件,默认插入一个用于调试可动态添加,暂时写死,后期用lowdb缓存 12 | singleSelected: null, // 单选选中的可拖拽组件 13 | contextMenuInfo: { x: 0, y: 0, isShow: false } 14 | }, 15 | mutations: { 16 | SET_CANVAS_MAPS (state, maps) { 17 | state.canvasMap = [...maps] 18 | }, 19 | ADD_CANVAS_MAP (state, nodeInfo) { 20 | state.canvasMap.push(nodeInfo) 21 | }, 22 | // 单选组件 23 | SINGLE_SELECT (state, item) { 24 | if (state.singleSelected === item) return 25 | state.singleSelected = item 26 | if (state.singleSelected) { 27 | console.warn('===single select===' + item.id) 28 | } 29 | }, 30 | // 设置右键菜单信息 31 | SET_CONTEXT_MENU_INFO (state, info) { 32 | state.contextMenuInfo = info 33 | }, 34 | // 设置当前选中的基本属性 35 | SET_CURRENT_BASE_PROPERTY (state, transformData) { 36 | state.singleSelected.packageJson.view = { ...transformData } 37 | let current = state.canvasMap.find(item => { 38 | return item.id === state.singleSelected.id 39 | }) 40 | if (current) { 41 | current.packageJson.view = { ...transformData } 42 | } 43 | }, 44 | // 设置当前选中的自有属性 45 | SET_CURRENT_SELF (state, { data, property }) { 46 | state.singleSelected.packageJson[property] = { ...data } 47 | let current = state.canvasMap.find(item => { 48 | return item.id === state.singleSelected.id 49 | }) 50 | if (current) { 51 | current.packageJson[property] = { ...data } 52 | } 53 | } 54 | }, 55 | actions: { 56 | InitCanvasMaps ({ commit }, maps) { 57 | commit('SET_CANVAS_MAPS', maps) 58 | }, 59 | AddCanvasMap ({ commit }, nodeInfo) { 60 | addCanvasMap(nodeInfo).then(() => { 61 | commit('ADD_CANVAS_MAP', nodeInfo) 62 | }) 63 | }, 64 | SingleSelected ({ commit }, selectItem) { 65 | commit('SINGLE_SELECT', selectItem) 66 | }, 67 | ToggleContextMenu ({ commit }, info) { 68 | let menuInfo = info ? Object.assign({}, info, { isShow: true }) : { x: 0, y: 0, isShow: false } 69 | commit('SET_CONTEXT_MENU_INFO', menuInfo) 70 | }, 71 | HideContextMenu ({ commit }) { 72 | commit('SET_CONTEXT_MENU_INFO', { x: 0, y: 0, isShow: false }) 73 | }, 74 | ContextMenuCommand ({ commit, state }, order) { 75 | commit('SET_CONTEXT_MENU_INFO', { x: 0, y: 0, isShow: false }) 76 | switch (order) { 77 | case 'top': 78 | // 如果是置顶 79 | topCanvasMap(state.singleSelected).then(res => { 80 | commit('SET_CANVAS_MAPS', res.data) 81 | }) 82 | break 83 | case 'bottom': 84 | // 如果是置顶 85 | bottomCanvasMap(state.singleSelected).then(res => { 86 | commit('SET_CANVAS_MAPS', res.data) 87 | }) 88 | break 89 | case 'up': 90 | upCanvasMap(state.singleSelected).then(res => { 91 | commit('SET_CANVAS_MAPS', res.data) 92 | }) 93 | break 94 | case 'down': 95 | downCanvasMap(state.singleSelected).then(res => { 96 | commit('SET_CANVAS_MAPS', res.data) 97 | }) 98 | break 99 | case 'copy': 100 | // 如果是复制操作,则传入当前选中的值 101 | copyCanvasMap(state.singleSelected).then(res => { 102 | let last = res.data[res.data.length - 1] 103 | commit('SET_CANVAS_MAPS', res.data) 104 | commit('SINGLE_SELECT', last) 105 | }) 106 | break 107 | case 'remove': 108 | // 如果是删除操作,则需要删除并更新当前的canvasMaps,并默认设置当前选中为空 109 | removeCanvasMap(state.singleSelected).then(res => { 110 | commit('SET_CANVAS_MAPS', res.data) 111 | commit('SINGLE_SELECT', null) 112 | }) 113 | break 114 | } 115 | }, 116 | SetBaseProperty ({ commit, state }, transformData) { 117 | if (state.singleSelected) { 118 | commit('SET_CURRENT_BASE_PROPERTY', transformData) 119 | } 120 | }, 121 | SetSelfProperty ({ commit, state }, config) { 122 | if (state.singleSelected) { 123 | commit('SET_CURRENT_SELF', { data: config, property: 'config' }) 124 | } 125 | }, 126 | SetApis ({ commit, state }, apis) { 127 | if (state.singleSelected) { 128 | commit('SET_CURRENT_SELF', { data: apis, property: 'apis' }) 129 | } 130 | }, 131 | SetSelfDataSource ({ commit, state }, source) { 132 | if (state.singleSelected) { 133 | commit('SET_CURRENT_SELF', { data: source, property: 'api_data' }) 134 | } 135 | } 136 | } 137 | } 138 | export default canvasMaps 139 | -------------------------------------------------------------------------------- /src/api/datastore.js: -------------------------------------------------------------------------------- 1 | import db from '../utils/db' 2 | import database from '../utils/database' 3 | import { toFirst, toLast, upGo, downGo } from '../utils/arr-utils' 4 | 5 | // 初始化所有本地数据 6 | export function initLocalData () { 7 | return new Promise((resolve, reject) => { 8 | try { 9 | db.set('app', database.app).write() 10 | db.set('canvasMaps', database.canvasMaps).write() 11 | resolve({ message: '初始化数据库成功' }) 12 | } catch (err) { 13 | return reject(err) 14 | } 15 | }) 16 | } 17 | 18 | // pageSetting配置数据 19 | export function getPageSettings () { 20 | return new Promise((resolve, reject) => { 21 | try { 22 | resolve({ data: db.get('app').cloneDeep().value() }) 23 | } catch (err) { 24 | return reject(err) 25 | } 26 | }) 27 | } 28 | 29 | export function setPageSettings (setting) { 30 | return new Promise((resolve, reject) => { 31 | try { 32 | db.set('app', setting).write() 33 | resolve({ data: db.get('app').cloneDeep().value() }) 34 | } catch (err) { 35 | return reject(err) 36 | } 37 | }) 38 | } 39 | 40 | export function resetPageSettings () { 41 | return setPageSettings(database.app) 42 | } 43 | 44 | // 画布db数据 45 | export function getCanvasMaps () { 46 | return new Promise((resolve, reject) => { 47 | try { 48 | resolve({ data: db.get('canvasMaps').cloneDeep().value() }) 49 | } catch (err) { 50 | return reject(err) 51 | } 52 | }) 53 | } 54 | 55 | export function setBaseProperty (currentMaps) { 56 | return new Promise((resolve, reject) => { 57 | try { 58 | db.get('canvasMaps') 59 | .find({ id: currentMaps.id }) 60 | .assign(currentMaps) 61 | .write() 62 | resolve({ data: db.get('canvasMaps').cloneDeep().value() }) 63 | } catch (err) { 64 | return reject(err) 65 | } 66 | }) 67 | } 68 | 69 | export function addCanvasMap (map) { 70 | return new Promise((resolve, reject) => { 71 | try { 72 | db.get('canvasMaps') 73 | .push(map) 74 | .write() 75 | resolve({ data: db.get('canvasMaps').cloneDeep().value() }) 76 | } catch (err) { 77 | return reject(err) 78 | } 79 | }) 80 | } 81 | 82 | export function removeCanvasMap (map) { 83 | return new Promise((resolve, reject) => { 84 | try { 85 | db.get('canvasMaps') 86 | .remove({ id: map.id }) 87 | .write() 88 | resolve({ data: db.get('canvasMaps').cloneDeep().value() }) 89 | } catch (err) { 90 | return reject(err) 91 | } 92 | }) 93 | } 94 | 95 | // 置顶一个数据 96 | export function topCanvasMap (map) { 97 | return new Promise((resolve, reject) => { 98 | try { 99 | let arr = db.get('canvasMaps').cloneDeep().value() 100 | let index = arr.findIndex(item => { 101 | return item.id === map.id 102 | }) 103 | if (index !== arr.length - 1) { 104 | let newArr = toLast(arr, index) 105 | db.set('canvasMaps', newArr).write() 106 | } 107 | resolve({ data: db.get('canvasMaps').cloneDeep().value() }) 108 | } catch (err) { 109 | return reject(err) 110 | } 111 | }) 112 | } 113 | 114 | // 置底一个数据 即将数组元素排至开头位置 115 | export function bottomCanvasMap (map) { 116 | return new Promise((resolve, reject) => { 117 | try { 118 | let arr = db.get('canvasMaps').cloneDeep().value() 119 | let index = arr.findIndex(item => { 120 | return item.id === map.id 121 | }) 122 | if (index !== 0) { 123 | let newArr = toFirst(arr, index) 124 | db.set('canvasMaps', newArr).write() 125 | } 126 | resolve({ data: db.get('canvasMaps').cloneDeep().value() }) 127 | } catch (err) { 128 | return reject(err) 129 | } 130 | }) 131 | } 132 | 133 | // up 134 | export function upCanvasMap (map) { 135 | return new Promise((resolve, reject) => { 136 | try { 137 | let arr = db.get('canvasMaps').cloneDeep().value() 138 | let index = arr.findIndex(item => { 139 | return item.id === map.id 140 | }) 141 | if (index !== arr.length - 1) { 142 | let newArr = downGo(arr, index) 143 | db.set('canvasMaps', newArr).write() 144 | } 145 | resolve({ data: db.get('canvasMaps').cloneDeep().value() }) 146 | } catch (err) { 147 | return reject(err) 148 | } 149 | }) 150 | } 151 | 152 | // down 153 | export function downCanvasMap (map) { 154 | return new Promise((resolve, reject) => { 155 | try { 156 | let arr = db.get('canvasMaps').cloneDeep().value() 157 | let index = arr.findIndex(item => { 158 | return item.id === map.id 159 | }) 160 | if (index !== 0) { 161 | let newArr = upGo(arr, index) 162 | db.set('canvasMaps', newArr).write() 163 | } 164 | resolve({ data: db.get('canvasMaps').cloneDeep().value() }) 165 | } catch (err) { 166 | return reject(err) 167 | } 168 | }) 169 | } 170 | -------------------------------------------------------------------------------- /src/styles/board/header-box.styl: -------------------------------------------------------------------------------- 1 | @import "../common/var.styl" 2 | // 画板顶部 3 | .board-header { 4 | position: absolute; 5 | top: 0; 6 | right: 0; 7 | left: 0; 8 | width: 100%; 9 | height: 40px; 10 | line-height: 40px; 11 | z-index: 205; 12 | background: $color-admin-main; 13 | transition: all .5s ease-in .1s; 14 | .header-title { 15 | width: 200px; 16 | height: 40px; 17 | display: inline-block; 18 | .iconfont { 19 | display: inline-block; 20 | vertical-align: top; 21 | height: 100%; 22 | line-height: 40px; 23 | cursor: pointer; 24 | color: $color-blue; 25 | padding: 0 5px; 26 | } 27 | span { 28 | display: inline-block; 29 | vertical-align: top; 30 | font-size: 14px; 31 | line-height: 40px; 32 | color: $color-blue; 33 | padding-left: 20px; 34 | } 35 | } 36 | .control { 37 | padding-left: 30px; 38 | height: 40px; 39 | line-height: 40px; 40 | .drag-list-menu { 41 | height: 100%; 42 | .list-group { 43 | position: relative; 44 | width: 56px; 45 | height: 100%; 46 | text-align: center; 47 | .list-group-header { 48 | position: relative; 49 | box-sizing: border-box; 50 | font-size: 14px; 51 | color: $color-text-info; 52 | cursor: pointer; 53 | &:before { 54 | content: '' 55 | position: absolute; 56 | top: 0; 57 | left: 0; 58 | right: 0; 59 | border-top: 2px solid transparent; 60 | } 61 | } 62 | &.hovered { 63 | .list-group-header { 64 | color: $color-primary; 65 | &:before { 66 | border-top: 2px solid $color-primary; 67 | } 68 | } 69 | } 70 | .list-group-body { 71 | position: absolute; 72 | top: 40px; 73 | left: 0; 74 | width: 555px; 75 | height: 333px; 76 | background-color: #1c1f25; 77 | .left { 78 | width: 60px; 79 | background-color: #2b2e36; 80 | } 81 | .right { 82 | flex: 1; 83 | text-align: left; 84 | padding: 20px 0 0 20px; 85 | .list-item { 86 | position: relative; 87 | display: inline-block; 88 | width: 138px; 89 | height: 100px; 90 | cursor: pointer; 91 | transition: all 0.2s ease-in-out; 92 | color: $color-text-info; 93 | background-color: #282a30; 94 | box-sizing: border-box; 95 | border: 1px solid transparent; 96 | margin-right: 20px; 97 | margin-bottom: 20px; 98 | .img { 99 | position: absolute; 100 | width: 100%; 101 | height: 100%; 102 | background-repeat: no-repeat; 103 | background-size: 100% 100%; 104 | background-position: 0 0; 105 | &.ve-line { 106 | background-image: url("../assets/images/ve-line.png") 107 | } 108 | &.ve-histogram { 109 | background-image: url("../assets/images/ve-histogram.png") 110 | } 111 | &.ve-bar { 112 | background-image: url("../assets/images/ve-bar.png") 113 | } 114 | &.ve-pie { 115 | background-image: url("../assets/images/ve-pie.png") 116 | } 117 | &.ve-radar { 118 | background-image: url("../assets/images/ve-radar.png") 119 | } 120 | &.ve-map { 121 | background-image: url("../assets/images/ve-map.png") 122 | } 123 | } 124 | .front { 125 | position: absolute; 126 | width: 100%; 127 | height: 30px; 128 | bottom: 0; 129 | margin-bottom: -30px; 130 | line-height: 30px; 131 | span { 132 | display: inline-block; 133 | vertical-align: middle; 134 | text-indent: 7px; 135 | font-size: 12px; 136 | } 137 | } 138 | &:hover { 139 | border: 1px solid $color-primary; 140 | } 141 | } 142 | } 143 | } 144 | } 145 | } 146 | } 147 | .right-box { 148 | width: 300px; 149 | height: 40px; 150 | line-height: 40px; 151 | display: inline-block; 152 | text-align: center; 153 | .iconfont { 154 | cursor: pointer; 155 | width: 65px; 156 | font-size: 18px; 157 | transition: .3s; 158 | &:hover { 159 | color: $color-primary; 160 | } 161 | } 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /src/views/admin.vue: -------------------------------------------------------------------------------- 1 | 53 | 54 | 143 | -------------------------------------------------------------------------------- /src/utils/geoCoordMap.js: -------------------------------------------------------------------------------- 1 | export const geoCoordMap = { 2 | '海门': [121.15, 31.89], 3 | '鄂尔多斯': [109.781327, 39.608266], 4 | '招远': [120.38, 37.35], 5 | '舟山': [122.207216, 29.985295], 6 | '齐齐哈尔': [123.97, 47.33], 7 | '盐城': [120.13, 33.38], 8 | '赤峰': [118.87, 42.28], 9 | '青岛': [120.33, 36.07], 10 | '乳山': [121.52, 36.89], 11 | '金昌': [102.188043, 38.520089], 12 | '泉州': [118.58, 24.93], 13 | '莱西': [120.53, 36.86], 14 | '日照': [119.46, 35.42], 15 | '胶南': [119.97, 35.88], 16 | '南通': [121.05, 32.08], 17 | '拉萨': [91.11, 29.97], 18 | '云浮': [112.02, 22.93], 19 | '梅州': [116.1, 24.55], 20 | '文登': [122.05, 37.2], 21 | '上海': [121.48, 31.22], 22 | '攀枝花': [101.718637, 26.582347], 23 | '威海': [122.1, 37.5], 24 | '承德': [117.93, 40.97], 25 | '厦门': [118.1, 24.46], 26 | '汕尾': [115.375279, 22.786211], 27 | '潮州': [116.63, 23.68], 28 | '丹东': [124.37, 40.13], 29 | '太仓': [121.1, 31.45], 30 | '曲靖': [103.79, 25.51], 31 | '烟台': [121.39, 37.52], 32 | '福州': [119.3, 26.08], 33 | '瓦房店': [121.979603, 39.627114], 34 | '即墨': [120.45, 36.38], 35 | '抚顺': [123.97, 41.97], 36 | '玉溪': [102.52, 24.35], 37 | '张家口': [114.87, 40.82], 38 | '阳泉': [113.57, 37.85], 39 | '莱州': [119.942327, 37.177017], 40 | '湖州': [120.1, 30.86], 41 | '汕头': [116.69, 23.39], 42 | '昆山': [120.95, 31.39], 43 | '宁波': [121.56, 29.86], 44 | '湛江': [110.359377, 21.270708], 45 | '揭阳': [116.35, 23.55], 46 | '荣成': [122.41, 37.16], 47 | '连云港': [119.16, 34.59], 48 | '葫芦岛': [120.836932, 40.711052], 49 | '常熟': [120.74, 31.64], 50 | '东莞': [113.75, 23.04], 51 | '河源': [114.68, 23.73], 52 | '淮安': [119.15, 33.5], 53 | '泰州': [119.9, 32.49], 54 | '南宁': [108.33, 22.84], 55 | '营口': [122.18, 40.65], 56 | '惠州': [114.4, 23.09], 57 | '江阴': [120.26, 31.91], 58 | '蓬莱': [120.75, 37.8], 59 | '韶关': [113.62, 24.84], 60 | '嘉峪关': [98.289152, 39.77313], 61 | '广州': [113.23, 23.16], 62 | '延安': [109.47, 36.6], 63 | '太原': [112.53, 37.87], 64 | '清远': [113.01, 23.7], 65 | '中山': [113.38, 22.52], 66 | '昆明': [102.73, 25.04], 67 | '寿光': [118.73, 36.86], 68 | '盘锦': [122.070714, 41.119997], 69 | '长治': [113.08, 36.18], 70 | '深圳': [114.07, 22.62], 71 | '珠海': [113.52, 22.3], 72 | '宿迁': [118.3, 33.96], 73 | '咸阳': [108.72, 34.36], 74 | '铜川': [109.11, 35.09], 75 | '平度': [119.97, 36.77], 76 | '佛山': [113.11, 23.05], 77 | '海口': [110.35, 20.02], 78 | '江门': [113.06, 22.61], 79 | '章丘': [117.53, 36.72], 80 | '肇庆': [112.44, 23.05], 81 | '大连': [121.62, 38.92], 82 | '临汾': [111.5, 36.08], 83 | '吴江': [120.63, 31.16], 84 | '石嘴山': [106.39, 39.04], 85 | '沈阳': [123.38, 41.8], 86 | '苏州': [120.62, 31.32], 87 | '茂名': [110.88, 21.68], 88 | '嘉兴': [120.76, 30.77], 89 | '长春': [125.35, 43.88], 90 | '胶州': [120.03336, 36.264622], 91 | '银川': [106.27, 38.47], 92 | '张家港': [120.555821, 31.875428], 93 | '三门峡': [111.19, 34.76], 94 | '锦州': [121.15, 41.13], 95 | '南昌': [115.89, 28.68], 96 | '柳州': [109.4, 24.33], 97 | '三亚': [109.511909, 18.252847], 98 | '自贡': [104.778442, 29.33903], 99 | '吉林': [126.57, 43.87], 100 | '阳江': [111.95, 21.85], 101 | '泸州': [105.39, 28.91], 102 | '西宁': [101.74, 36.56], 103 | '宜宾': [104.56, 29.77], 104 | '呼和浩特': [111.65, 40.82], 105 | '成都': [104.06, 30.67], 106 | '大同': [113.3, 40.12], 107 | '镇江': [119.44, 32.2], 108 | '桂林': [110.28, 25.29], 109 | '张家界': [110.479191, 29.117096], 110 | '宜兴': [119.82, 31.36], 111 | '北海': [109.12, 21.49], 112 | '西安': [108.95, 34.27], 113 | '金坛': [119.56, 31.74], 114 | '东营': [118.49, 37.46], 115 | '牡丹江': [129.58, 44.6], 116 | '遵义': [106.9, 27.7], 117 | '绍兴': [120.58, 30.01], 118 | '扬州': [119.42, 32.39], 119 | '常州': [119.95, 31.79], 120 | '潍坊': [119.1, 36.62], 121 | '重庆': [106.54, 29.59], 122 | '台州': [121.420757, 28.656386], 123 | '南京': [118.78, 32.04], 124 | '滨州': [118.03, 37.36], 125 | '贵阳': [106.71, 26.57], 126 | '无锡': [120.29, 31.59], 127 | '本溪': [123.73, 41.3], 128 | '克拉玛依': [84.77, 45.59], 129 | '渭南': [109.5, 34.52], 130 | '马鞍山': [118.48, 31.56], 131 | '宝鸡': [107.15, 34.38], 132 | '焦作': [113.21, 35.24], 133 | '句容': [119.16, 31.95], 134 | '北京': [116.46, 39.92], 135 | '徐州': [117.2, 34.26], 136 | '衡水': [115.72, 37.72], 137 | '包头': [110, 40.58], 138 | '绵阳': [104.73, 31.48], 139 | '乌鲁木齐': [87.68, 43.77], 140 | '枣庄': [117.57, 34.86], 141 | '杭州': [120.19, 30.26], 142 | '淄博': [118.05, 36.78], 143 | '鞍山': [122.85, 41.12], 144 | '溧阳': [119.48, 31.43], 145 | '库尔勒': [86.06, 41.68], 146 | '安阳': [114.35, 36.1], 147 | '开封': [114.35, 34.79], 148 | '济南': [117, 36.65], 149 | '德阳': [104.37, 31.13], 150 | '温州': [120.65, 28.01], 151 | '九江': [115.97, 29.71], 152 | '邯郸': [114.47, 36.6], 153 | '临安': [119.72, 30.23], 154 | '兰州': [103.73, 36.03], 155 | '沧州': [116.83, 38.33], 156 | '临沂': [118.35, 35.05], 157 | '南充': [106.110698, 30.837793], 158 | '天津': [117.2, 39.13], 159 | '富阳': [119.95, 30.07], 160 | '泰安': [117.13, 36.18], 161 | '诸暨': [120.23, 29.71], 162 | '郑州': [113.65, 34.76], 163 | '哈尔滨': [126.63, 45.75], 164 | '聊城': [115.97, 36.45], 165 | '芜湖': [118.38, 31.33], 166 | '唐山': [118.02, 39.63], 167 | '平顶山': [113.29, 33.75], 168 | '邢台': [114.48, 37.05], 169 | '德州': [116.29, 37.45], 170 | '济宁': [116.59, 35.38], 171 | '荆州': [112.239741, 30.335165], 172 | '宜昌': [111.3, 30.7], 173 | '义乌': [120.06, 29.32], 174 | '丽水': [119.92, 28.45], 175 | '洛阳': [112.44, 34.7], 176 | '秦皇岛': [119.57, 39.95], 177 | '株洲': [113.16, 27.83], 178 | '石家庄': [114.48, 38.03], 179 | '莱芜': [117.67, 36.19], 180 | '常德': [111.69, 29.05], 181 | '保定': [115.48, 38.85], 182 | '湘潭': [112.91, 27.87], 183 | '金华': [119.64, 29.12], 184 | '岳阳': [113.09, 29.37], 185 | '长沙': [113, 28.21], 186 | '衢州': [118.88, 28.97], 187 | '廊坊': [116.7, 39.53], 188 | '菏泽': [115.480656, 35.23375], 189 | '合肥': [117.27, 31.86], 190 | '武汉': [114.31, 30.52], 191 | '大庆': [125.03, 46.58] 192 | } 193 | -------------------------------------------------------------------------------- /src/styles/board/options.styl: -------------------------------------------------------------------------------- 1 | @import "../common/var.styl" 2 | // 右侧参数配置页面 3 | .board-options { 4 | position: absolute; 5 | top: 40px; 6 | right: 0; 7 | bottom: 0; 8 | box-sizing: border-box; 9 | z-index: 200; 10 | background: #ffffff; 11 | box-shadow: -2px 0 2px 0 rgba(0, 0, 0, 0.1); 12 | transition: all .3s; 13 | transform: translate3d(100%, 0, 0) 14 | .header-title { 15 | height: 30px; 16 | line-height: 30px; 17 | text-align: center; 18 | background: $color-admin-ctrl-header; 19 | } 20 | .tabs { 21 | width: 100%; 22 | display: flex; 23 | height: 30px; 24 | line-height: 27px; 25 | .tab-item { 26 | flex: 1; 27 | height: 100%; 28 | display: inline-block; 29 | text-align: center; 30 | background: #27343e; 31 | transition: .2s; 32 | outline: 0; 33 | color: #bcc9d4; 34 | font-size: 12px; 35 | cursor: pointer; 36 | border-top: 2px solid transparent; 37 | &.active { 38 | background: $color-admin-options-bg; 39 | color: $color-primary; 40 | border-top: 2px solid $color-primary; 41 | } 42 | .iconfont { 43 | font-size: 16px; 44 | } 45 | } 46 | } 47 | .options-body { 48 | background: $color-admin-options-bg; 49 | height: calc(100% - 30px); 50 | } 51 | .expand-hover { 52 | position: absolute; 53 | top: 50%; 54 | left: 0; 55 | width: 16px; 56 | height: 160px; 57 | margin-top: -80px; 58 | margin-left: -16px; 59 | cursor: pointer; 60 | .inner { 61 | position: relative; 62 | width: 100%; 63 | height: 100%; 64 | background: $color-admin-options-hover; 65 | opacity: 0; 66 | transition: all .2s; 67 | i { 68 | position: absolute; 69 | width: 18px; 70 | height: 18px; 71 | font-size: 18px; 72 | top: 50%; 73 | margin-top: -9px; 74 | &:hover { 75 | color: #2d8cf0; 76 | } 77 | } 78 | &:before, &:after { 79 | content: '' 80 | position: absolute 81 | left: 0; 82 | } 83 | &:before { 84 | top: 0; 85 | margin-top: -16px; 86 | border-top: 16px solid transparent; 87 | border-right: 16px solid $color-admin-options-hover; 88 | } 89 | &:after { 90 | bottom: 0; 91 | margin-bottom: -16px; 92 | border-left: 16px solid transparent; 93 | border-top: 16px solid $color-admin-options-hover; 94 | } 95 | } 96 | &:hover .inner { 97 | opacity: 1; 98 | } 99 | } 100 | &.is-expand { 101 | transform: translate3d(0, 0, 0) 102 | } 103 | } 104 | // 页面设置 105 | .page-config, .block-config { 106 | padding-top: 10px; 107 | .gui-field { 108 | display: flex; 109 | justify-content: space-between; 110 | padding: 6px 13px; 111 | min-height: 24px; 112 | color: $color-text-info; 113 | font-size: 12px; 114 | .gui-field-name { 115 | padding-right: 5px; 116 | line-height: 28px; 117 | } 118 | .gui-field-container { 119 | min-height: 24px; 120 | display: flex; 121 | width: 175px; 122 | font-size: 12px; 123 | align-items: center; 124 | .gui-inline { 125 | display: inline-block; 126 | width: 85px; 127 | .label { 128 | color: #647279; 129 | white-space: nowrap; 130 | overflow: hidden; 131 | text-overflow: ellipsis; 132 | font-size: 12px; 133 | line-height: 18px; 134 | text-align: left; 135 | } 136 | &:first-child { 137 | margin-right: 5px; 138 | } 139 | } 140 | } 141 | } 142 | .gui-wrap { 143 | position: relative; 144 | padding-left: 13px; 145 | &.disable { 146 | color: #647279; 147 | } 148 | .wrap-name { 149 | line-height: 40px; 150 | span { 151 | display: inline-block; 152 | vertical-align: middle; 153 | } 154 | .wrap-arrow { 155 | transition: .3s 156 | &.show { 157 | transform: rotate(90deg) 158 | } 159 | &.simple { 160 | cursor: pointer; 161 | } 162 | } 163 | .wrap-label { 164 | padding: 0 5px 0 2px; 165 | } 166 | .wrap-toggle { 167 | cursor: pointer; 168 | } 169 | .iconfont { 170 | line-height: normal; 171 | } 172 | } 173 | .gui-field { 174 | padding-left: 18px; 175 | } 176 | &:after { 177 | content: '' 178 | position: absolute; 179 | top: 40px; 180 | left: 18px; 181 | bottom: 0; 182 | border-left: 1px solid #282f3a; 183 | } 184 | } 185 | .gui-group { 186 | .gui-group-name { 187 | border-bottom: 1px solid #282f3a; 188 | line-height: 26px; 189 | cursor: pointer; 190 | padding: 4px 5px 6px 18px; 191 | text-align: left; 192 | font-size: 12px; 193 | } 194 | .gui-group-content { 195 | background: #15171c; 196 | padding: 5px 0; 197 | .gui-field { 198 | padding-left: 20px; 199 | } 200 | } 201 | } 202 | .gui-color { 203 | display: inline-block; 204 | margin: 0 4px 4px 0 205 | } 206 | .group-title { 207 | padding: 0 10px; 208 | } 209 | } 210 | 211 | // 需要覆盖bin-ui的样式 212 | .options-body .bin-scrollbar__wrap { 213 | overflow-x: hidden; 214 | } 215 | .options-body .bin-collapse-simple { 216 | background-color: $color-admin-options-bg; 217 | } 218 | 219 | // 折叠菜单 220 | .options-body .bin-collapse > .bin-collapse-item > .bin-collapse-header { 221 | color: #fff; 222 | padding-left: 5px; 223 | font-size: 12px; 224 | i { 225 | margin-right: 0; 226 | } 227 | } 228 | .options-body .bin-collapse-content { 229 | background-color: $color-admin-options-dark; 230 | color: $color-text-info; 231 | padding: 0; 232 | .bin-collapse-content-box { 233 | padding-top: 6px; 234 | padding-bottom: 6px; 235 | font-size: 12px; 236 | } 237 | } 238 | 239 | .options-body .bin-collapse > .bin-collapse-item.bin-collapse-item-active > .bin-collapse-header { 240 | border-bottom: 1px solid #282f3a; 241 | } 242 | .options-body .bin-collapse { 243 | border-top: 1px solid #282f3a; 244 | border-bottom: 1px solid #282f3a; 245 | } 246 | .options-body .bin-collapse > .bin-collapse-item { 247 | border-top: 1px solid #282f3a; 248 | } 249 | .options-body .bin-collapse > .bin-collapse-item:first-child { 250 | border-top: none; 251 | } 252 | // 数字输入框样式覆盖 253 | .options-body .bin-input-number { 254 | width: 85px; 255 | } 256 | .options-body .bin-input-number-input { 257 | background-color: $color-admin-options-dark; 258 | color: $color-text-info; 259 | } 260 | .options-body .bin-input-number-handler-wrap { 261 | background-color: $color-admin-options-dark; 262 | } 263 | // 输入框样式 264 | .options-body .bin-input { 265 | background-color: $color-admin-options-dark; 266 | color: $color-text-info; 267 | } 268 | 269 | 270 | // 覆盖element-ui 271 | .options-body { 272 | .el-color-picker { 273 | vertical-align: middle; 274 | height: 26px; 275 | .el-color-picker__trigger { 276 | height: 26px; 277 | width: 26px; 278 | padding: 2px; 279 | } 280 | .el-color-picker__color { 281 | overflow: hidden; 282 | border: none; 283 | } 284 | } 285 | 286 | .el-input__inner { 287 | color: $color-text-info; 288 | background-color: $color-admin-options-dark; 289 | } 290 | .el-select { 291 | .el-input__suffix { 292 | right: 0 293 | } 294 | .el-input__inner { 295 | padding: 0 15px; 296 | } 297 | } 298 | } 299 | 300 | 301 | -------------------------------------------------------------------------------- /src/styles/board/transform-block.styl: -------------------------------------------------------------------------------- 1 | @import "../common/var.styl" 2 | * { 3 | outline: 0; 4 | } 5 | .dv-transform { 6 | position: absolute; 7 | top: 0; 8 | left: 0; 9 | will-change: transform; 10 | .dv-com { 11 | outline: 0; 12 | transform-origin: 50% 50%; 13 | width: 100%; 14 | height: 100%; 15 | box-sizing: border-box 16 | &.hovered { 17 | background: rgba(0, 231, 255, .11); 18 | } 19 | .dv-wrapper { 20 | pointer-events: none !important; 21 | } 22 | } 23 | .transform-handler { 24 | width: 100%; 25 | height: 100%; 26 | box-sizing: border-box; 27 | cursor: move; 28 | } 29 | &.selected { 30 | z-index: 1; 31 | .dv-com { 32 | background: rgba(0, 231, 255, .11); 33 | } 34 | .dv-scale::after { 35 | z-index: -1; 36 | content: ""; 37 | position: absolute; 38 | top: 0; 39 | bottom: 0; 40 | left: 0; 41 | right: 0; 42 | border: 1px dashed #05ddff; 43 | } 44 | } 45 | } 46 | // 导航线条 47 | .navigator-line { 48 | width: 100%; 49 | height: 100%; 50 | position: absolute; 51 | top: 0; 52 | left: 0; 53 | pointer-events: none; 54 | box-sizing: content-box; 55 | .navigator-line-left { 56 | position: absolute; 57 | border-top: 1px dashed $color-navigator-line; 58 | height: 0; 59 | top: 0; 60 | font-size: 12px; 61 | transform: translateX(-100%); 62 | box-sizing: border-box; 63 | } 64 | .navigator-line-top { 65 | position: absolute; 66 | border-left: 1px dashed $color-navigator-line; 67 | width: 0; 68 | left: 0; 69 | font-size: 12px; 70 | transform: translateY(-100%); 71 | box-sizing: border-box; 72 | } 73 | .navigator-line-account { 74 | position: absolute; 75 | transform: translate(-100%, -100%); 76 | color: $color-navigator-line; 77 | text-shadow: 1px 1px 1px #222; 78 | white-space: nowrap; 79 | } 80 | } 81 | // scale-面板 82 | .dv-scale { 83 | transform-origin: 0 0; 84 | width: 100%; 85 | height: 100%; 86 | position: absolute; 87 | } 88 | 89 | .dv-wrapper { 90 | box-sizing: border-box; 91 | } 92 | 93 | //resize-bar 94 | .dv-transform.selected .transform-handler .bottom-handler, 95 | .dv-transform.selected .transform-handler .left-handler, 96 | .dv-transform.selected .transform-handler .right-handler, 97 | .dv-transform.selected .transform-handler .top-handler { 98 | display: flex !important; 99 | } 100 | .transform-handler { 101 | .top-handler { 102 | display: flex; 103 | justify-content: center; 104 | align-items: center; 105 | position: absolute; 106 | top: -5px; 107 | width: 100%; 108 | height: 11px; 109 | .control-point { 110 | display: flex; 111 | justify-content: center; 112 | align-items: center; 113 | height: 20px; 114 | width: 20px; 115 | z-index: 2; 116 | &::after { 117 | content: ''; 118 | height: 6px; 119 | width: 6px; 120 | border-radius: 100%; 121 | background: #fff; 122 | } 123 | } 124 | &::after { 125 | content: ""; 126 | height: 1px; 127 | background: #05ddff; 128 | width: 100%; 129 | position: absolute; 130 | z-index: 1; 131 | } 132 | } 133 | .bottom-handler { 134 | display: flex; 135 | justify-content: center; 136 | align-items: center; 137 | position: absolute; 138 | bottom: -5px; 139 | width: 100%; 140 | height: 11px; 141 | .control-point { 142 | display: flex; 143 | justify-content: center; 144 | align-items: center; 145 | height: 20px; 146 | width: 20px; 147 | z-index: 2; 148 | &::after { 149 | content: ''; 150 | height: 6px; 151 | width: 6px; 152 | border-radius: 100%; 153 | background: #fff; 154 | } 155 | } 156 | &::after { 157 | content: ""; 158 | height: 1px; 159 | background: #05ddff; 160 | width: 100%; 161 | position: absolute; 162 | z-index: 1; 163 | } 164 | } 165 | .left-handler { 166 | display: flex; 167 | justify-content: center; 168 | align-items: center; 169 | position: absolute; 170 | top: 0; 171 | left: -5px; 172 | width: 11px; 173 | height: 100%; 174 | .control-point { 175 | display: flex; 176 | justify-content: center; 177 | align-items: center; 178 | height: 20px; 179 | width: 20px; 180 | z-index: 2; 181 | &::after { 182 | content: ''; 183 | height: 6px; 184 | width: 6px; 185 | border-radius: 100%; 186 | background: #fff; 187 | } 188 | } 189 | &::after { 190 | content: ""; 191 | width: 1px; 192 | background: #05ddff; 193 | height: 100%; 194 | position: absolute; 195 | z-index: 1; 196 | } 197 | } 198 | .right-handler { 199 | display: flex; 200 | justify-content: center; 201 | align-items: center; 202 | position: absolute; 203 | top: 0; 204 | right: -5px; 205 | width: 11px; 206 | height: 100%; 207 | .control-point { 208 | display: flex; 209 | justify-content: center; 210 | align-items: center; 211 | height: 20px; 212 | width: 20px; 213 | z-index: 2; 214 | &::after { 215 | content: ''; 216 | height: 6px; 217 | width: 6px; 218 | border-radius: 100%; 219 | background: #fff; 220 | } 221 | } 222 | &::after { 223 | content: ""; 224 | width: 1px; 225 | background: #05ddff; 226 | height: 100%; 227 | position: absolute; 228 | z-index: 1; 229 | } 230 | } 231 | .top-left-handler { 232 | display: flex; 233 | justify-content: center; 234 | align-items: center; 235 | position: absolute; 236 | left: -5px; 237 | top: -5px; 238 | height: 11px; 239 | width: 11px; 240 | .control-point { 241 | display: flex; 242 | justify-content: center; 243 | align-items: center; 244 | height: 20px; 245 | width: 20px; 246 | z-index: 2; 247 | &::after { 248 | content: ''; 249 | height: 6px; 250 | width: 6px; 251 | border-radius: 100%; 252 | background: #fff; 253 | } 254 | } 255 | } 256 | .top-right-handler { 257 | display: flex; 258 | justify-content: center; 259 | align-items: center; 260 | position: absolute; 261 | right: -5px; 262 | top: -5px; 263 | height: 11px; 264 | width: 11px; 265 | .control-point { 266 | display: flex; 267 | justify-content: center; 268 | align-items: center; 269 | height: 20px; 270 | width: 20px; 271 | z-index: 2; 272 | &::after { 273 | content: ''; 274 | height: 6px; 275 | width: 6px; 276 | border-radius: 100%; 277 | background: #fff; 278 | } 279 | } 280 | } 281 | .bottom-left-handler { 282 | display: flex; 283 | justify-content: center; 284 | align-items: center; 285 | position: absolute; 286 | bottom: -5px; 287 | left: -5px; 288 | height: 11px; 289 | width: 11px; 290 | .control-point { 291 | display: flex; 292 | justify-content: center; 293 | align-items: center; 294 | height: 20px; 295 | width: 20px; 296 | z-index: 2; 297 | &::after { 298 | content: ''; 299 | height: 6px; 300 | width: 6px; 301 | border-radius: 100%; 302 | background: #fff; 303 | } 304 | } 305 | } 306 | .bottom-right-handler { 307 | display: flex; 308 | justify-content: center; 309 | align-items: center; 310 | position: absolute; 311 | bottom: -5px; 312 | right: -5px; 313 | height: 11px; 314 | width: 11px; 315 | .control-point { 316 | display: flex; 317 | justify-content: center; 318 | align-items: center; 319 | height: 20px; 320 | width: 20px; 321 | z-index: 2; 322 | &::after { 323 | content: ''; 324 | height: 6px; 325 | width: 6px; 326 | border-radius: 100%; 327 | background: #fff; 328 | } 329 | } 330 | } 331 | } 332 | 333 | .transform-handler.hide > .transform-bg, 334 | .transform-handler.hide > i[class$="-handler"], 335 | .transform-handler.hide > i[class$="-handler"] .control-point { 336 | display: none; 337 | } 338 | 339 | // 悬停显示 340 | .dv-com.hovered { 341 | .transform-handler > i[class$="-handler"] { 342 | display: flex !important; 343 | } 344 | .transform-handler > i[class$="-handler"] .control-point { 345 | display: none; 346 | } 347 | .top-handler { 348 | &::after { 349 | content: ""; 350 | height: 1px; 351 | background: #05ddff; 352 | width: 100%; 353 | position: absolute; 354 | z-index: 1; 355 | } 356 | } 357 | .bottom-handler { 358 | &::after { 359 | content: ""; 360 | height: 1px; 361 | background: #05ddff; 362 | width: 100%; 363 | position: absolute; 364 | z-index: 1; 365 | } 366 | } 367 | .left-handler { 368 | &::after { 369 | content: ""; 370 | width: 1px; 371 | background: #05ddff; 372 | height: 100%; 373 | position: absolute; 374 | z-index: 1; 375 | } 376 | } 377 | .right-handler { 378 | &::after { 379 | content: ""; 380 | width: 1px; 381 | background: #05ddff; 382 | height: 100%; 383 | position: absolute; 384 | z-index: 1; 385 | } 386 | } 387 | } 388 | 389 | // 选中显示 390 | .dv-transform.selected { 391 | .dv-com { 392 | .transform-handler > i[class$="-handler"] .control-point { 393 | display: flex !important; 394 | } 395 | } 396 | } 397 | -------------------------------------------------------------------------------- /src/components/drag/DragItem.vue: -------------------------------------------------------------------------------- 1 | 54 | 55 | 333 | -------------------------------------------------------------------------------- /preview/static/js/chunk-95354e52.42529e2d.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-95354e52"],{"02f4":function(t,e,n){var i=n("4588"),r=n("be13");t.exports=function(t){return function(e,n){var c,o,s=String(r(e)),a=i(n),u=s.length;return a<0||a>=u?t?"":void 0:(c=s.charCodeAt(a),c<55296||c>56319||a+1===u||(o=s.charCodeAt(a+1))<56320||o>57343?t?s.charAt(a):c:t?s.slice(a,a+2):o-56320+(c-55296<<10)+65536)}}},"0324":function(t,e,n){"use strict";var i=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{ref:"wrap",staticClass:"dv-charts",staticStyle:{width:"100%",height:"100%"}},[t.config.title?n("div",{ref:"titles",staticClass:"titles",style:t.titleStyle},[n("span",[t._v(t._s(t.config.title.content))])]):t._e(),n(t.typeName,{ref:"chart",tag:"component",attrs:{data:t.chartData,width:t.width,height:t.height,"legend-visible":t.legendVisible,"after-config":t.afterConfig,extend:t.chartExtend,options:t.chartOptions,settings:t.chartSettings}})],1)},r=[],c=n("75fc"),o=n("cebc"),s=n("fbe2"),a=(n("7f7f"),n("6762"),n("2fdb"),n("ac6a"),n("5df3"),n("f400"),{"海门":[121.15,31.89],"鄂尔多斯":[109.781327,39.608266],"招远":[120.38,37.35],"舟山":[122.207216,29.985295],"齐齐哈尔":[123.97,47.33],"盐城":[120.13,33.38],"赤峰":[118.87,42.28],"青岛":[120.33,36.07],"乳山":[121.52,36.89],"金昌":[102.188043,38.520089],"泉州":[118.58,24.93],"莱西":[120.53,36.86],"日照":[119.46,35.42],"胶南":[119.97,35.88],"南通":[121.05,32.08],"拉萨":[91.11,29.97],"云浮":[112.02,22.93],"梅州":[116.1,24.55],"文登":[122.05,37.2],"上海":[121.48,31.22],"攀枝花":[101.718637,26.582347],"威海":[122.1,37.5],"承德":[117.93,40.97],"厦门":[118.1,24.46],"汕尾":[115.375279,22.786211],"潮州":[116.63,23.68],"丹东":[124.37,40.13],"太仓":[121.1,31.45],"曲靖":[103.79,25.51],"烟台":[121.39,37.52],"福州":[119.3,26.08],"瓦房店":[121.979603,39.627114],"即墨":[120.45,36.38],"抚顺":[123.97,41.97],"玉溪":[102.52,24.35],"张家口":[114.87,40.82],"阳泉":[113.57,37.85],"莱州":[119.942327,37.177017],"湖州":[120.1,30.86],"汕头":[116.69,23.39],"昆山":[120.95,31.39],"宁波":[121.56,29.86],"湛江":[110.359377,21.270708],"揭阳":[116.35,23.55],"荣成":[122.41,37.16],"连云港":[119.16,34.59],"葫芦岛":[120.836932,40.711052],"常熟":[120.74,31.64],"东莞":[113.75,23.04],"河源":[114.68,23.73],"淮安":[119.15,33.5],"泰州":[119.9,32.49],"南宁":[108.33,22.84],"营口":[122.18,40.65],"惠州":[114.4,23.09],"江阴":[120.26,31.91],"蓬莱":[120.75,37.8],"韶关":[113.62,24.84],"嘉峪关":[98.289152,39.77313],"广州":[113.23,23.16],"延安":[109.47,36.6],"太原":[112.53,37.87],"清远":[113.01,23.7],"中山":[113.38,22.52],"昆明":[102.73,25.04],"寿光":[118.73,36.86],"盘锦":[122.070714,41.119997],"长治":[113.08,36.18],"深圳":[114.07,22.62],"珠海":[113.52,22.3],"宿迁":[118.3,33.96],"咸阳":[108.72,34.36],"铜川":[109.11,35.09],"平度":[119.97,36.77],"佛山":[113.11,23.05],"海口":[110.35,20.02],"江门":[113.06,22.61],"章丘":[117.53,36.72],"肇庆":[112.44,23.05],"大连":[121.62,38.92],"临汾":[111.5,36.08],"吴江":[120.63,31.16],"石嘴山":[106.39,39.04],"沈阳":[123.38,41.8],"苏州":[120.62,31.32],"茂名":[110.88,21.68],"嘉兴":[120.76,30.77],"长春":[125.35,43.88],"胶州":[120.03336,36.264622],"银川":[106.27,38.47],"张家港":[120.555821,31.875428],"三门峡":[111.19,34.76],"锦州":[121.15,41.13],"南昌":[115.89,28.68],"柳州":[109.4,24.33],"三亚":[109.511909,18.252847],"自贡":[104.778442,29.33903],"吉林":[126.57,43.87],"阳江":[111.95,21.85],"泸州":[105.39,28.91],"西宁":[101.74,36.56],"宜宾":[104.56,29.77],"呼和浩特":[111.65,40.82],"成都":[104.06,30.67],"大同":[113.3,40.12],"镇江":[119.44,32.2],"桂林":[110.28,25.29],"张家界":[110.479191,29.117096],"宜兴":[119.82,31.36],"北海":[109.12,21.49],"西安":[108.95,34.27],"金坛":[119.56,31.74],"东营":[118.49,37.46],"牡丹江":[129.58,44.6],"遵义":[106.9,27.7],"绍兴":[120.58,30.01],"扬州":[119.42,32.39],"常州":[119.95,31.79],"潍坊":[119.1,36.62],"重庆":[106.54,29.59],"台州":[121.420757,28.656386],"南京":[118.78,32.04],"滨州":[118.03,37.36],"贵阳":[106.71,26.57],"无锡":[120.29,31.59],"本溪":[123.73,41.3],"克拉玛依":[84.77,45.59],"渭南":[109.5,34.52],"马鞍山":[118.48,31.56],"宝鸡":[107.15,34.38],"焦作":[113.21,35.24],"句容":[119.16,31.95],"北京":[116.46,39.92],"徐州":[117.2,34.26],"衡水":[115.72,37.72],"包头":[110,40.58],"绵阳":[104.73,31.48],"乌鲁木齐":[87.68,43.77],"枣庄":[117.57,34.86],"杭州":[120.19,30.26],"淄博":[118.05,36.78],"鞍山":[122.85,41.12],"溧阳":[119.48,31.43],"库尔勒":[86.06,41.68],"安阳":[114.35,36.1],"开封":[114.35,34.79],"济南":[117,36.65],"德阳":[104.37,31.13],"温州":[120.65,28.01],"九江":[115.97,29.71],"邯郸":[114.47,36.6],"临安":[119.72,30.23],"兰州":[103.73,36.03],"沧州":[116.83,38.33],"临沂":[118.35,35.05],"南充":[106.110698,30.837793],"天津":[117.2,39.13],"富阳":[119.95,30.07],"泰安":[117.13,36.18],"诸暨":[120.23,29.71],"郑州":[113.65,34.76],"哈尔滨":[126.63,45.75],"聊城":[115.97,36.45],"芜湖":[118.38,31.33],"唐山":[118.02,39.63],"平顶山":[113.29,33.75],"邢台":[114.48,37.05],"德州":[116.29,37.45],"济宁":[116.59,35.38],"荆州":[112.239741,30.335165],"宜昌":[111.3,30.7],"义乌":[120.06,29.32],"丽水":[119.92,28.45],"洛阳":[112.44,34.7],"秦皇岛":[119.57,39.95],"株洲":[113.16,27.83],"石家庄":[114.48,38.03],"莱芜":[117.67,36.19],"常德":[111.69,29.05],"保定":[115.48,38.85],"湘潭":[112.91,27.87],"金华":[119.64,29.12],"岳阳":[113.09,29.37],"长沙":[113,28.21],"衢州":[118.88,28.97],"廊坊":[116.7,39.53],"菏泽":[115.480656,35.23375],"合肥":[117.27,31.86],"武汉":[114.31,30.52],"大庆":[125.03,46.58]});function u(t){var e={columns:[],rows:[]},n=new Map;return t.forEach(function(t){var i={};if(t.x&&(e.columns[0]="x",i["x"]=t.x),t.s?(e.columns.includes(t.s)||e.columns.push(t.s),i[t.s]=t.y):(e.columns[1]="s",i["s"]=t.y),n.has(t.x)){var r=Object.assign(n.get(t.x),i);n.set(t.x,r)}else n.set(t.x,i)}),e.rows=Object(c["a"])(n.values()),e}function f(t){for(var e=[],n=0;n1?arguments[1]:void 0)}})},5147:function(t,e,n){var i=n("2b4c")("match");t.exports=function(t){var e=/./;try{"/./"[t](e)}catch(n){try{return e[i]=!1,!"/./"[t](e)}catch(r){}}return!0}},"5dbc":function(t,e,n){var i=n("d3f4"),r=n("8b97").set;t.exports=function(t,e,n){var c,o=e.constructor;return o!==n&&"function"==typeof o&&(c=o.prototype)!==n.prototype&&i(c)&&r&&r(t,c),t}},"5df3":function(t,e,n){"use strict";var i=n("02f4")(!0);n("01f9")(String,"String",function(t){this._t=String(t),this._i=0},function(){var t,e=this._t,n=this._i;return n>=e.length?{value:void 0,done:!0}:(t=i(e,n),this._i+=t.length,{value:t,done:!1})})},6762:function(t,e,n){"use strict";var i=n("5ca1"),r=n("c366")(!0);i(i.P,"Array",{includes:function(t){return r(this,t,arguments.length>1?arguments[1]:void 0)}}),n("9c6c")("includes")},"67ab":function(t,e,n){var i=n("ca5a")("meta"),r=n("d3f4"),c=n("69a8"),o=n("86cc").f,s=0,a=Object.isExtensible||function(){return!0},u=!n("79e5")(function(){return a(Object.preventExtensions({}))}),f=function(t){o(t,i,{value:{i:"O"+ ++s,w:{}}})},l=function(t,e){if(!r(t))return"symbol"==typeof t?t:("string"==typeof t?"S":"P")+t;if(!c(t,i)){if(!a(t))return"F";if(!e)return"E";f(t)}return t[i].i},h=function(t,e){if(!c(t,i)){if(!a(t))return!0;if(!e)return!1;f(t)}return t[i].w},d=function(t){return u&&p.NEED&&a(t)&&!c(t,i)&&f(t),t},p=t.exports={KEY:i,NEED:!1,fastKey:l,getWeak:h,onFreeze:d}},"7f7f":function(t,e,n){var i=n("86cc").f,r=Function.prototype,c=/^\s*function ([^ (]*)/,o="name";o in r||n("9e1e")&&i(r,o,{configurable:!0,get:function(){try{return(""+this).match(c)[1]}catch(t){return""}}})},"8b97":function(t,e,n){var i=n("d3f4"),r=n("cb7c"),c=function(t,e){if(r(t),!i(e)&&null!==e)throw TypeError(e+": can't set as prototype!")};t.exports={set:Object.setPrototypeOf||("__proto__"in{}?function(t,e,i){try{i=n("9b43")(Function.call,n("11e9").f(Object.prototype,"__proto__").set,2),i(t,[]),e=!(t instanceof Array)}catch(r){e=!0}return function(t,n){return c(t,n),e?t.__proto__=n:i(t,n),t}}({},!1):void 0),check:c}},aae3:function(t,e,n){var i=n("d3f4"),r=n("2d95"),c=n("2b4c")("match");t.exports=function(t){var e;return i(t)&&(void 0!==(e=t[c])?!!e:"RegExp"==r(t))}},ac6a:function(t,e,n){for(var i=n("cadf"),r=n("0d58"),c=n("2aba"),o=n("7726"),s=n("32e9"),a=n("84f2"),u=n("2b4c"),f=u("iterator"),l=u("toStringTag"),h=a.Array,d={CSSRuleList:!0,CSSStyleDeclaration:!1,CSSValueList:!1,ClientRectList:!1,DOMRectList:!1,DOMStringList:!1,DOMTokenList:!0,DataTransferItemList:!1,FileList:!1,HTMLAllCollection:!1,HTMLCollection:!1,HTMLFormElement:!1,HTMLSelectElement:!1,MediaList:!0,MimeTypeArray:!1,NamedNodeMap:!1,NodeList:!0,PaintRequestList:!1,Plugin:!1,PluginArray:!1,SVGLengthList:!1,SVGNumberList:!1,SVGPathSegList:!1,SVGPointList:!1,SVGStringList:!1,SVGTransformList:!1,SourceBufferList:!1,StyleSheetList:!0,TextTrackCueList:!1,TextTrackList:!1,TouchList:!1},p=r(d),_=0;_1?arguments[1]:void 0,3);while(n=n?n.n:this._f){i(n.v,n.k,this);while(n&&n.r)n=n.p}},has:function(t){return!!v(p(this,e),t)}}),h&&i(f.prototype,"size",{get:function(){return p(this,e)[_]}}),f},def:function(t,e,n){var i,r,c=v(t,e);return c?c.v=n:(t._l=c={i:r=d(e,!0),k:e,v:n,p:i=t._l,n:void 0,r:!1},t._f||(t._f=c),i&&(i.n=c),t[_]++,"F"!==r&&(t._i[r]=c)),t},getEntry:v,setStrong:function(t,e,n){u(t,e,function(t,n){this._t=p(t,e),this._k=n,this._l=void 0},function(){var t=this,e=t._k,n=t._l;while(n&&n.r)n=n.p;return t._t&&(t._l=n=n?n.n:t._t._f)?f(0,"keys"==e?n.k:"values"==e?n.v:[n.k,n.v]):(t._t=void 0,f(1))},n?"entries":"values",!n,!0),l(e)}}},d2c8:function(t,e,n){var i=n("aae3"),r=n("be13");t.exports=function(t,e,n){if(i(e))throw TypeError("String#"+n+" doesn't accept regex!");return String(r(t))}},e0b8:function(t,e,n){"use strict";var i=n("7726"),r=n("5ca1"),c=n("2aba"),o=n("dcbc"),s=n("67ab"),a=n("4a59"),u=n("f605"),f=n("d3f4"),l=n("79e5"),h=n("5cc5"),d=n("7f20"),p=n("5dbc");t.exports=function(t,e,n,_,v,g){var b=i[t],y=b,S=v?"set":"add",x=y&&y.prototype,m={},w=function(t){var e=x[t];c(x,t,"delete"==t?function(t){return!(g&&!f(t))&&e.call(this,0===t?0:t)}:"has"==t?function(t){return!(g&&!f(t))&&e.call(this,0===t?0:t)}:"get"==t?function(t){return g&&!f(t)?void 0:e.call(this,0===t?0:t)}:"add"==t?function(t){return e.call(this,0===t?0:t),this}:function(t,n){return e.call(this,0===t?0:t,n),this})};if("function"==typeof y&&(g||x.forEach&&!l(function(){(new y).entries().next()}))){var L=new y,O=L[S](g?{}:-0,1)!=L,E=l(function(){L.has(1)}),j=h(function(t){new y(t)}),T=!g&&l(function(){var t=new y,e=5;while(e--)t[S](e,e);return!t.has(-0)});j||(y=e(function(e,n){u(e,y,t);var i=p(new b,e,y);return void 0!=n&&a(n,v,i[S],i),i}),y.prototype=x,x.constructor=y),(E||T)&&(w("delete"),w("has"),v&&w("get")),(T||O)&&w(S),g&&x.clear&&delete x.clear}else y=_.getConstructor(e,t,v,S),o(y.prototype,n),s.NEED=!0;return d(y,t),m[t]=y,r(r.G+r.W+r.F*(y!=b),m),g||_.setStrong(y,t,v),y}},f400:function(t,e,n){"use strict";var i=n("c26b"),r=n("b39a"),c="Map";t.exports=n("e0b8")(c,function(t){return function(){return t(this,arguments.length>0?arguments[0]:void 0)}},{get:function(t){var e=i.getEntry(r(this,c),t);return e&&e.v},set:function(t,e){return i.def(r(this,c),0===t?0:t,e)}},i,!0)},fbe2:function(t,e,n){"use strict";n.d(e,"a",function(){return o}),n.d(e,"b",function(){return s});var i=n("6dd8");const r="undefined"===typeof window,c=function(t){for(let e of t){const t=e.target.__resizeListeners__||[];t.length&&t.forEach(t=>{t()})}},o=function(t,e){r||(t.__resizeListeners__||(t.__resizeListeners__=[],t.__ro__=new i["default"](c),t.__ro__.observe(t)),t.__resizeListeners__.push(e))},s=function(t,e){t&&t.__resizeListeners__&&(t.__resizeListeners__.splice(t.__resizeListeners__.indexOf(e),1),t.__resizeListeners__.length||t.__ro__.disconnect())}}}]); -------------------------------------------------------------------------------- /preview/static/js/app.6a3a718f.js: -------------------------------------------------------------------------------- 1 | (function(e){function t(t){for(var o,c,r=t[0],s=t[1],f=t[2],l=0,p=[];l