<template>
  <div class="designePanel" ref="designePanel" v-on:click="onceClick($event)">
    <div class="widget-panel">
      <div v-if="data.list.length == 0" class="form-empty">
        <el-image :src="noDataImg"></el-image>
        <p class="no-data-text">暂无组件，请拖拽组件库组件进行大屏设计</p>
      </div>
      <div
        v-show="menuVisible"
        class="container"
        :style="{zoom: 1, left: left + 'px', top: top + 'px'}"
      >
        <div class="m-ctxMenu">
          <ul>
            <li class="z-clickable" v-if="select" @click="handleWidgetClone">
              复制
            </li>
            <li class="z-clickable" @click="handleWidgetDelete">删除</li>
            <li
              class="z-clickable"
              v-if="select"
              @click="handleWidgetRank('top')"
            >
              置于顶层
            </li>
            <li
              class="z-clickable"
              v-if="select"
              @click="handleWidgetRank('bottom')"
            >
              置于底层
            </li>
            <li
              class="z-clickable"
              v-if="select"
              @click="handleWidgetRank('pre')"
            >
              上移一层
            </li>
            <li
              class="z-clickable"
              v-if="select"
              @click="handleWidgetRank('next')"
            >
              下移一层
            </li>
            <li class="z-clickable" @click="addToUnit()">添加到组件库</li>
          </ul>
        </div>
      </div>
      <span
        v-if="isOndrop"
        class="auxiliary-value-x"
        :style="{top: auxiliary_span_x_top, left: auxiliary_span_x_left}"
        >{{ auxiliary_x }}</span
      >
      <div
        v-if="isOndrop"
        class="auxiliary-line-x"
        :style="{top: auxiliary_x_top}"
      ></div>
      <div
        v-if="isOndrop"
        class="auxiliary-line-y"
        :style="{height: auxiliary_y_height, left: auxiliary_y_left}"
      ></div>
      <draggable
        v-model="data.list"
        v-bind="{
          group: 'datav',
          ghostClass: 'ghost',
          animation: 200,
          handle: '.drag-widget',
        }"
        @end="handleMoveEnd"
        @add="handleWidgetAdd"
        class="datavPanel"
      >
        <el-form
          ref="designForm"
          :size="data.config.size"
          :label-position="data.config.labelPosition"
          :label-width="data.config.labelWidth + 'px'"
          class="fullheight"
          :style="bgStyle"
        >
          <transition-group
            name="fade"
            tag="div"
            class="widget-form-list"
            :style="canvasStyle"
          >
            <template
              v-for="(element, index) in data.list.filter((d) => d.key)"
            >
              <template>
                <design-datav-item
                  :key="element.key"
                  :element="element"
                  :select.sync="selectWidget"
                  :selectKeyMap.sync="selectWidgetMap"
                  :index="index"
                  :data="widgetForm"
                  @contextmenu.prevent.native="openMenu(element, index)"
                  @onDrag="onItemDrag"
                  @onDragstop="onItemDragstop"
                ></design-datav-item>
              </template>
            </template>
          </transition-group>
        </el-form>
      </draggable>
    </div>

    <el-dialog
      title="添加到组件库"
      :visible.sync="releaseDialogVisible"
      class="datavAdd"
      append-to-body
      width="40%"
      top="25vh"
      :close-on-click-modal="false"
    >
      <div style="height:'280px',paddingLeft: '20px'}">
        <el-form v-model="releaseDatav" data-vv-scope="releaseDatavForm">
          <ht-form-item label="组件名称" label-width="100px" prop="name">
            <ht-input
              v-model="releaseDatav.name"
              autocomplete="off"
              :validate="{required: true}"
              placeholder="请输入名称"
              :maxlength="50"
              :showWordLimit="true"
            ></ht-input>
          </ht-form-item>
          <ht-form-item label="组件别名" label-width="100px" prop="name">
            <ht-input
              v-model="releaseDatav.alias"
              autocomplete="off"
              :validate="{
                required: true,
                isExist:
                  '${portal}/portal/sysIndexLayoutManage/sysIndexLayoutManage/v1/checkKey?key=',
                regex: {
                  exp: '^[a-zA-Z][a-zA-Z0-9_]*$',
                  message: '只能输入字母、数字、下划线，且以字母开头',
                },
              }"
              :maxlength="50"
              :showWordLimit="true"
              placeholder="请输入别名"
            ></ht-input>
          </ht-form-item>
          <ht-form-item
            label="组件类型"
            label-width="100px"
            style="width: 100%"
          >
            <el-radio-group :disabled="true" v-model="releaseDatav.layoutType">
              <el-radio-button :label="0">管理端</el-radio-button>
              <el-radio-button :label="1">移动端</el-radio-button>
              <el-radio-button :label="2">应用端</el-radio-button>
            </el-radio-group>
          </ht-form-item>
          <ht-form-item label="大屏尺寸" label-width="100px" prop="memo">
            <el-input
              type="number"
              :disabled="true"
              v-model="releaseDatav.width"
              style="width: 220px"
            >
              <template slot="prepend">宽</template>
              <template slot="append">px</template>
            </el-input>
            <el-input
              type="number"
              :disabled="true"
              v-model="releaseDatav.height"
              style="width: 220px; margin-left: 5px"
            >
              <template slot="prepend">高</template>
              <template slot="append">px</template>
            </el-input>
          </ht-form-item>
          <ht-form-item label="组件描述" label-width="100px" prop="memo">
            <ht-input
              type="textarea"
              :rows="3"
              v-model="releaseDatav.memo"
              autocomplete="off"
              placeholder="请输入描述信息"
              :maxlength="200"
              :showWordLimit="true"
            ></ht-input>
          </ht-form-item>
        </el-form>
      </div>
      <span slot="footer" class="dialog-footer">
        <el-button @click="releaseDialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="releaseNew()">确 定</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
import Draggable from 'vuedraggable'
import DesignDatavItem from '@/components/portal/DesignDatavItem.vue'
import {datavToolMap, datavDecorationData} from '@/api/datavConfig.js'
import WidgetFormBus from '@/components/form/bus/WidgetFormBus.js'
import req from '@/request.js'

export default {
  name: 'design-panel',
  components: {
    Draggable,
    DesignDatavItem,
    WidgetFormBus,
  },
  props: {
    data: {
      type: Object,
      default() {
        return {}
      },
    },
    select: {
      type: Object,
      default() {
        return {alias: ''}
      },
    },
    selectMap: {
      type: Object,
      default() {
        return {}
      },
    },
    layoutObj: {
      type: Object,
      default() {
        return {}
      },
    },
    opacity: {
      type: Number,
      default() {
        return 0.9
      },
    },
  },
  data() {
    return {
      widgetForm: this.data,
      selectWidget: this.select,
      menuVisible: false,
      top: 0,
      left: 0,
      scaleHeight: 1, //乘以比例高度
      selectIndex: -1,
      gapHeight: 0,
      datavToolMap: JSON.parse(JSON.stringify(datavToolMap)),
      decorationMap: JSON.parse(JSON.stringify(datavDecorationData)),
      templateDataMap: {}, //图表、datav组件
      bgStyle: {
        position: 'absolute',
        justifyContent: 'center',
        background: '#080D27',
        alignItems: 'center',
        width: '100%',
        overflow: 'hidden',
        opacity: 0.4,
      },
      canvasStyle: {
        position: 'relative',
        width: this.data.config.width + 'px',
        height: this.data.config.height + 'px',
        transformOrigin: '0 0',
      },
      uploadUrl: window.context.portal + '/system/file/v1/upload',
      keyDownCtrl: false,
      selectWidgetMap: this.selectMap,
      releaseDialogVisible: false,
      releaseDatav: {},
      isOndrop: false,
      widthRatio: 1,
      heightRatio: 1,
      auxiliary_y_height: '0px',
      auxiliary_x_top: '0px',
      auxiliary_y_left: '0px',
      auxiliary_span_x_top: '0px',
      auxiliary_span_x_left: '0px',
      auxiliary_x: 'x:0px',
      noDataImg: require('@/assets/nodata_images/no-data.png'),
    }
  },
  mounted() {
    document.body.ondrop = function (event) {
      let isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1
      if (isFirefox) {
        event.preventDefault()
        event.stopPropagation()
      }
    }
    //由于会影响到其他页面操作，暂时先屏蔽
    // document.addEventListener('keydown',this.deleteEventListener, true);
  },
  destroyed() {
    // window.removeEventListener("keydown", this.deleteEventListener, true);
  },
  methods: {
    handleMoveEnd({newIndex, oldIndex}) {
      this.onItemDragstop()
    },
    handleSelectWidget(index) {
      this.selectWidget = this.widgetForm.list[index]
    },
    handleWidgetAdd(evt) {
      let newIndex = evt.newIndex
      if (
        newIndex >= this.widgetForm.list.length ||
        newIndex < this.widgetForm.list.length - 1
      ) {
        newIndex = this.widgetForm.list.length - 1
      }
      if (
        this.widgetForm.list[evt.newIndex] &&
        this.widgetForm.list[evt.newIndex].designHtml
      ) {
        const designJson = JSON.parse(
          Base64.decode(this.widgetForm.list[evt.newIndex].designHtml)
        )
        this.widgetForm.list.splice(evt.newIndex, 1)
        if (designJson.list && designJson.list.length > 0) {
          for (let index = 0; index < designJson.list.length; index++) {
            let itemJson = designJson.list[index]
            itemJson.key =
              Date.parse(new Date()) + '_' + Math.ceil(Math.random() * 99999)
            this.$set(this.widgetForm.list, newIndex, itemJson)
            ++newIndex
          }
        }
      } else {
        const to = evt.to
        //为拖拽到容器的元素添加唯一 key
        const key =
          Date.parse(new Date()) + '_' + Math.ceil(Math.random() * 99999)
        if (!this.widgetForm.list[newIndex].key) {
          const itemTemplateData = this.getItemTemplate(
            this.widgetForm.list[newIndex].alias
          )
          this.$set(this.widgetForm.list, newIndex, {
            ...itemTemplateData,
            key,
          })
        } else {
          this.widgetForm.list[newIndex].key = key
        }
        if (window.event) {
          this.$emit(
            'initItemPosition',
            newIndex,
            window.event.x,
            window.event.y
          )
        }
        let zIndex = this.getCurrentMaxZindex() + 1
        this.widgetForm.list[newIndex].zIndex = zIndex
        this.selectWidget = this.widgetForm.list[newIndex]
        this.selectIndex = newIndex
      }
      this.onItemDragstop()
    },
    deleteEventListener(e) {
      switch (e.keyCode) {
        case 8: //回车
        case 46: //删除
          if (this.selectWidget) {
            this.$confirm('确定删除吗？', '提示', {
              confirmButtonText: '确定',
              cancelButtonText: '取消',
              type: 'warning',
            }).then(() => {
              for (
                let index = 0;
                index < this.widgetForm.list.length;
                index++
              ) {
                if (this.selectWidget.key == this.widgetForm.list[index].key) {
                  this.widgetForm.list.splice(index, 1)
                }
              }
            })
          }
          break
      }
    },
    changeBgStyle() {
      switch (this.widgetForm.config.backgroundType) {
        case 'color':
          this.bgStyle.background = this.widgetForm.config.backgroundColor
          break
        case 'image':
          this.bgStyle.background = `url(${require('@/assets/img/datav/datav_' +
            this.widgetForm.config.backgroundImage +
            '.png')}) 100%  no-repeat`
          break
        case 'file':
          if (
            this.widgetForm.config.backgroundFile &&
            this.widgetForm.config.backgroundFile.id
          ) {
            let _this = this
            req
              .get(
                window.context.portal +
                  '/system/file/v1/preview?fileId=' +
                  this.widgetForm.config.backgroundFile.id,
                'blob'
              )
              .then(
                (response) => {
                  if (response.data.size > 0) {
                    var blob = response.data
                    var reader = new FileReader()
                    reader.readAsDataURL(blob)
                    reader.onload = function (e) {
                      _this.bgStyle.background = `url(${e.target.result}) 100%  no-repeat`
                    }
                  }
                },
                function errorCallback() {
                  _this.$message.success('获取背景图片失败。')
                }
              )
          }
          break
      }
    },
    recordCanvasSize(
      elHeight,
      scaleHeight,
      width,
      reverse,
      panelWidth,
      panelHeight
    ) {
      //画布设置缩放
      let height = scaleHeight
      if (!reverse) {
        this.scaleHeight = height
        try {
          this.gapHeight = (elHeight - scaleHeight) / 2
        } catch (error) {}
      } else {
        height = elHeight
      }
      this.$set(this.bgStyle, 'height', height + 'px')
      this.$set(this.bgStyle, 'width', width + 'px')
      this.$set(this.canvasStyle, 'height', panelHeight + 'px')
      this.$set(this.canvasStyle, 'width', panelWidth + 'px')
      this.widthRatio = width / panelWidth
      this.heightRatio = height / panelHeight
      this.$set(
        this.canvasStyle,
        'transform',
        'scale(' + this.widthRatio + ',' + this.heightRatio + ')'
      )
    },
    getItemTemplate(alias) {
      const templateData = this.templateDataMap[alias]
      if (templateData) {
        return JSON.parse(JSON.stringify(templateData))
      }
      return {}
    },
    openMenu(el, index) {
      if (
        (el && this.selectWidget && this.selectWidget.key === el.key) ||
        (this.selectWidgetMap && JSON.stringify(this.selectWidgetMap) != '{}')
      ) {
        this.left = window.event.clientX - 230
        this.top = window.event.clientY - this.gapHeight - 40 // fix 位置bug
        this.menuVisible = true
        this.selectIndex = index
      }
    },
    closeMenu() {
      this.menuVisible = false
    },
    onceClick(evt) {
      if (!this.selectWidget) {
        this.closeMenu()
      } else {
        if (
          !(
            evt.x >= this.selectWidget.x &&
            evt.x <= this.selectWidget.x + this.selectWidget.width &&
            evt.y >= this.selectWidget.y &&
            evt.y <= this.selectWidget.y + this.selectWidget.height
          )
        ) {
          this.closeMenu()
        }
      }
    },
    handleWidgetDelete() {
      if (this.select) {
        const index = this.selectIndex
        if (this.widgetForm.list.length - 1 === index) {
          if (index === 0) {
            this.selectWidget = {}
          } else {
            this.selectWidget = this.widgetForm.list[index - 1]
          }
        } else {
          this.selectWidget = this.widgetForm.list[index + 1]
        }

        this.$nextTick(() => {
          this.widgetForm.list.splice(index, 1)
        })
      } else if (
        this.selectMap &&
        JSON.stringify(this.selectMap) != '{}' &&
        this.widgetForm.list.length > 0
      ) {
        let _this = this
        const nList = this.widgetForm.list.filter((item) => {
          return _this.selectMap[item.key] !== true
        })
        this.$set(this.widgetForm, 'list', nList)
        this.selectMap = {}
      }
      this.closeMenu()
    },
    handleWidgetRank(type) {
      if (this.selectWidget) {
        switch (type) {
          case 'top':
            const maxIndex = this.getCurrentMaxZindex()
            this.selectWidget.zIndex = maxIndex + 1
            break
          case 'bottom':
            const minIndex = this.getCurrentMinZindex()
            this.selectWidget.zIndex = minIndex - 1
            break
          case 'pre':
            ++this.selectWidget.zIndex
            break
          case 'next':
            --this.selectWidget.zIndex
            break
        }
      }
      this.closeMenu()
      this.savePic()
    },
    handleWidgetClone() {
      let index = this.selectIndex
      if (this.selectWidget) {
        let cloneData = {
          ...this.selectWidget,
          options: {...this.selectWidget.options},
          key: Date.parse(new Date()) + '_' + Math.ceil(Math.random() * 99999),
        }
        this.widgetForm.list.splice(index, 0, cloneData)

        this.$nextTick(() => {
          let newIndex = index + 1
          this.selectWidget = this.widgetForm.list[newIndex]
          this.selectIndex = newIndex
        })
        this.closeMenu()
      }
    },
    onClick(el, index) {
      if (this.selectWidget && el.key === this.selectWidget.key) {
        this.selectIndex = index
      }
    },
    getCurrentMaxZindex() {
      //获取当前元素中最大的z-index值
      let array = this.getCurrentZindexSort()
      if (array && array.length > 0) {
        return array[array.length - 1].zIndex
      }
      return 0
    },
    getCurrentMinZindex() {
      //获取当前元素中最大的z-index值
      let array = this.getCurrentZindexSort()
      if (array && array.length > 0) {
        return array[0].zIndex
      }
      return 0
    },
    getCurrentZindexSort() {
      //所有元素按z-index排序
      try {
        let arr = JSON.parse(JSON.stringify(this.widgetForm.list))
        arr.sort((obj1, obj2) => {
          return obj1.zIndex - obj2.zIndex
        })
        return arr
      } catch (error) {
        return null
      }
    },
    savePic: function () {
      var getPixelRatio = function (context) {
        // 获取设备的PixelRatio
        var backingStore =
          context.backingStorePixelRatio ||
          context.webkitBackingStorePixelRatio ||
          context.mozBackingStorePixelRatio ||
          context.msBackingStorePixelRatio ||
          context.oBackingStorePixelRatio ||
          context.backingStorePixelRatio ||
          1
        return (window.devicePixelRatio || 1) / backingStore
      }
      var captureContent = this.$refs.designForm.$el
      var width = captureContent.offsetWidth
      var height = captureContent.offsetHeight
      var canvas = document.createElement('canvas')
      var context = canvas.getContext('2d')
      var scale = getPixelRatio(context)
      canvas.width = width * scale
      canvas.height = height * scale
      canvas.style.width = width + 'px'
      canvas.style.height = height + 'px'
      context.scale(scale, scale)

      var opts = {
        useCORSOnly: true,
        // allowTaint :true,
        scale: scale,
        canvas: canvas,
        width: width,
        height: height,
        dpi: window.devicePixelRatio,
      }
      return {content: captureContent, opts: opts}
    },
    addToUnit() {
      this.releaseDialogVisible = true
      this.menuVisible = false
      this.releaseDatav = {}
      this.$set(this.releaseDatav, 'width', this.widgetForm.config.width)
      this.$set(this.releaseDatav, 'height', this.widgetForm.config.height)
      this.$set(this.releaseDatav, 'layoutType', this.layoutObj.layoutType)
      this.$set(this.releaseDatav, 'type', 'unit')
    },
    releaseNew() {
      if (!this.releaseDatav.name) {
        this.$message.warning('请输入组件名称')
        return
      }
      if (!this.releaseDatav.alias) {
        this.$message.warning('请输入组件别名')
        return
      }
      let configJson = JSON.parse(JSON.stringify(this.widgetForm))
      configJson.list = []
      let _this = this
      if (
        this.selectWidgetMap &&
        JSON.stringify(this.selectWidgetMap) != '{}'
      ) {
        this.widgetForm.list.forEach((item) => {
          if (_this.selectWidgetMap[item.key] === true) {
            configJson.list.push(item)
          }
        })
      } else if (this.selectWidget) {
        configJson.list.push(this.selectWidget)
      } else {
        this.$message.success('请选择要添加的组件！')
        return
      }
      this.releaseDatav.designHtml = Base64.encode(JSON.stringify(configJson))
      req
        .post(
          window.context.portal +
            '/portal/sysIndexLayoutManage/sysIndexLayoutManage/v1/saveLayout',
          this.releaseDatav
        )
        .then((response) => {
          if (response.data.state) {
            this.$message.success('添加到组件库成功。')
            this.releaseDialogVisible = false
            this.$set(this, 'releaseDatav', {})
          } else {
            this.$message.error(response.data.message)
          }
        })
    },
    onItemDrag(x, y) {
      this.isOndrop = true
      this.$set(this.bgStyle, 'opacity', 0.5)
      if (x || y) {
        x = Math.round(x * 10) / 10
        y = Math.round(y * 10) / 10
        this.$set(this, 'auxiliary_x', 'x:' + x + '，y:' + y)
        const ratioX = x * this.widthRatio
        const ratioY = y * this.heightRatio
        this.$set(this, 'auxiliary_x_top', ratioY + 'px')
        this.$set(
          this,
          'auxiliary_y_height',
          this.data.config.height * this.heightRatio + 'px'
        )
        this.$set(this, 'auxiliary_y_left', ratioX + 'px')
        this.$set(
          this,
          'auxiliary_span_x_top',
          ratioY + (ratioY > 20 ? -15 : 10) + 'px'
        )
        this.$set(this, 'auxiliary_span_x_left', ratioX + 6 + 'px')
      }
    },
    onItemDragstop(x, y) {
      this.isOndrop = false
      this.$set(this.bgStyle, 'opacity', this.opacity)
    },
  },
  created() {
    WidgetFormBus.$on('datavHandleMoveStart', () => {
      this.onItemDrag()
    })
    let _this = this
    for (const key in this.datavToolMap) {
      if (Object.hasOwnProperty.call(this.datavToolMap, key)) {
        const obj = this.datavToolMap[key]
        if (obj.items && obj.items.length > 0) {
          obj.items.forEach((item) => {
            _this.templateDataMap[item.alias] = JSON.parse(JSON.stringify(item))
          })
        }
      }
    }
    for (const key in this.decorationMap) {
      if (Object.hasOwnProperty.call(this.decorationMap, key)) {
        const obj = this.decorationMap[key]
        if (obj.items && obj.items.length > 0) {
          obj.items.forEach((item) => {
            _this.templateDataMap[item.alias] = JSON.parse(JSON.stringify(item))
          })
        }
      }
    }
  },
  watch: {
    select: {
      handler(val) {
        this.selectWidget = val
      },
      deep: true,
    },
    selectWidget: {
      handler(val) {
        this.menuVisible = false
        this.$emit('update:select', val)
      },
      deep: true,
    },
    selectMap: {
      handler(val) {
        this.selectWidgetMap = val
      },
      deep: true,
    },
    selectWidgetMap: {
      handler(val) {
        this.$emit('update:selectMap', val)
      },
      deep: true,
    },
    data: {
      handler(val) {
        this.widgetForm = val
      },
      deep: true,
    },
    widgetForm: {
      handler(val) {
        this.$emit('update:data', val)
      },
      deep: true,
    },
    'data.config': {
      handler(val) {
        this.changeBgStyle()
      },
      deep: true,
    },
    opacity: {
      handler(val) {
        this.$set(this.bgStyle, 'opacity', val)
      },
    },
  },
}
</script>
<style lang="scss" scoped>
.designePanel {
  height: 100%;
  width: 100%;
  overflow: hidden;
  position: relative;
  box-shadow: 0px 0px 11px 1px rgba(8, 13, 39, 0.7);
}
.datavPanel {
  width: 100%;
  height: 100%;
  position: relative;
}
.widget-panel {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  height: 100%;
}

.widget-form-list {
  /* border: 1px solid #dfdfdf; */
  height: calc(100vh - 1px);
  overflow: hidden;
}

.form-empty {
  position: absolute;
  text-align: center;
  width: 380px;
  font-size: 20px;
  top: 250px;
  left: 50%;
  margin-left: -150px;
  color: #ccc;
  .no-data-text {
    font-size: 14px;
    color: #fff;
    margin: 0;
  }
}
li {
  display: list-item;
  text-align: -webkit-match-parent;
}
.container {
  width: 200px;
  position: absolute;
  z-index: 2004;
}
.m-ctxMenu {
  background: #fff;
  border: 1px solid #ccc;
  box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.16);
  border-radius: 2px;
}
.m-ctxMenu li {
  cursor: pointer;
  position: relative;
  font-size: 12px;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  -ms-box-sizing: border-box;
  -o-box-sizing: border-box;
  box-sizing: border-box;
  padding-left: 24px;
  padding-right: 18px;
  height: 32px;
  line-height: 32px;
  min-width: 180px;
  background-color: #fff;
  white-space: nowrap;
}
.m-ctxMenu li:before {
  position: absolute;
  left: 8px;
  line-height: 32px;
}
.m-ctxMenu li:hover {
  background: #ccc;
}
.m-ctxMenu .z-disabled {
  color: #ccc;
}
.m-ctxMenu .shortcut {
  float: right;
  color: #8f8f8f;
}
.m-ctxMenu li .u-icn-angle-right {
  left: auto;
  right: 8px;
}
.m-ctxMenu li .u-icn {
  position: absolute;
  left: 8px;
  top: 10px;
  font-size: 12px;
}
.u-icn {
  display: inline-block;
  font-family: 'youdata';
  font-style: normal;
  font-weight: normal;
  font-variant: normal;
  line-height: 1;
  text-decoration: inherit;
  text-rendering: optimizeLegibility;
  text-transform: none;
  -moz-osx-font-smoothing: grayscale;
  -webkit-font-smoothing: antialiased;
  vertical-align: middle;
  margin-bottom: 2px;
}
.m-ctxMenu li > ul.right {
  left: 100%;
}
.m-ctxMenu li > ul {
  position: absolute;
  border: 1px solid #ccc;
}
ol,
ul {
  list-style: none;
  padding-left: 0px;
}
.m-ctxMenu li > ul.bottom {
  top: 0;
}
.content-box {
  display: grid;
  grid-template-columns: 2fr 3fr 5fr 3fr 2fr;
}
.auxiliary-line-y {
  border-color: #22c7f8;
  border-left-style: dashed;
  width: 1px;
  border-left-width: 1px;
  position: inherit;
}
.auxiliary-line-x {
  border-color: #22c7f8;
  border-bottom-style: dashed;
  width: 100%;
  border-bottom-width: 1px;
  position: inherit;
}
.auxiliary-value-x {
  font-size: 13px;
  color: #22c7f8;
  position: inherit;
}
.auxiliary-value-y {
  width: 0px;
  font-size: 13px;
  color: #22c7f8;
  position: inherit;
}
.design-panel__empty-block {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  .no-data-text {
    color: #fff;
  }
}
</style>
