鼠标框选/ctrl+单击选中多个元素拖拽,缩放单个元素

在这里插入图片描述1. 鼠标框选或ctrl+单击选中多个元素进行拖拽
2. 基于vue-drag-resize实现单个元素的大小缩放

(做的过程中比较坑的是vue-drag-resize)的拖动效果会和自己写的多个拖动事件之间有影响,所以就直接将vue-drag-resize的isDraggable设置为false,直接自己写拖动效果了)

<template>
  <div class="body">
    <div class="left">
      <div>
        上移:
        <el-input-number
          v-model="toTop"
          controls-position="right"
          @change="val => handleChange(val, 'top')" 
          :min="-1080"
          :max="1080">
        </el-input-number>
      </div>
      <div>
        下移:
        <el-input-number
          v-model="toBottom"
          controls-position="right"
          @change="val => handleChange(val, 'bottom')" 
          :min="-1080"
          :max="1080">
        </el-input-number>
      </div>
       <div>
        左移:
        <el-input-number
          v-model="toLeft"
          controls-position="right"
         @change="val => handleChange(val, 'left')" 
          :min="-1800"
          :max="1800">
        </el-input-number>
      </div>
       <div>
        右移:
        <el-input-number
          v-model="toRight"
          controls-position="right"
          @change="val => handleChange(val, 'right')" 
          :min="-1800"
          :max="1800">
        </el-input-number>
      </div>
    </div>
    <div class="main-container"
      @mousedown="handleMouseDown"
      @mousemove="handleMouseMove"
      @mouseup="handleMouseUp"
      ref="selectNodeExeCLC">
      <vue-drag-resize
        :dataChartId="item.id"
        v-for="item in datalist" :key="item.id"
        :isDraggable="false"
        :isResizable="item.dragging!==false && (!currentSelectChartIdArr.length || currentSelectChartIdArr.includes(item.id))"
        :w="item.w"
        :h="item.h"
        :x="item.x"
        :y="item.y"
        :parentLimitation="true"
        @mousedown.native="e => onChartDragStart(e, item)"
        @mousemove.native="e => onChartDragging(e, item)"
        @mouseup.native="e=> onChartDragStop(e, item)"
        @resizestop="data => onChartResizestop(data, item)"
        >
        {{currentSelectChartIdArr}}
        {{item.id}}
        {{item.dragging}}
      </vue-drag-resize>
    </div>
    <div class="right"></div>
    <SelectArea :startPoint="startPoint" :endPoint="endPoint"></SelectArea>
  </div>
</template>

<script>
import $ from 'jquery'
import vueDragResize from 'vue-drag-resize'
import SelectArea from './SelectArea.vue'
export default {
  components: {
    vueDragResize,
    SelectArea
  },
  data() {
    return {
      isPressCtrl: '',
      toTop: 0,
      toBottom: 0,
      toLeft: 0,
      toRight: 0,
      startPoint: {x: 0, y: 0},
      endPoint: {x: 0, y: 0},
      mouseKey: false,
      mouseComplete: false,
      currentSelectChartIdArr: [],
      currentChartDataArr: [],
      oldCurrentChartDataArr: [],
      selectedChartsDOM: [],
      datalist: [
        {
          id: '0',
          w: 100,
          h: 200,
          x: 0,
          y: 0,
          color:'rgba(10,33,190,.1)'
        },
        {
          id: '1',
          w: 200,
          h: 300,
          x: 200,
          y: 50,
          color:'rgba(10,83,190,.1)'
        },
        {
          id: '2',
          w: 200,
          h: 300,
          x: 600,
          y: 50,
          color:'rgba(10,83,190,.1)'
        }
      ],
      dragFlag: false,
      startX: 0,
      startY: 0,
      clickStartTime: 0,
      clickEndTime: 0,
      containerClickStartTime: 0,
      containerClickEndTime: 0,
      isSingleFlag: true
    }
  },
  watch: {
    currentSelectChartIdArr: {
      handler() {
        this.toTop = 0
        this.toBottom = 0
        this.toLeft = 0
        this.toRight = 0
      },
      deep: true
    }
  },
  mounted() {
    this.setup();
  },
  beforeDestroy() {
    window.removeEventListener('mouseup', this.handleMouseUp);
    window.removeEventListener('keydown', this.handleKeydown);
    window.removeEventListener('keyup', this.handleKeyup);
  },
  methods: {
    handleChange(value, type) {
      this.getOutermost()
      if(type === 'left') {
        this.moveChart(0-value, 0)
      } else if(type === 'right') {
        this.moveChart(value, 0)
      } else if(type === 'top') {
        this.moveChart(0, 0-value)
      } else if(type === 'bottom') {
        this.moveChart(0, value)
      }
    },
    setup() {
      this.mouseKey = false; // 是否监听鼠标移动(移出编辑区范围,不再监听鼠标移动事件)
      this.mouseComplete = false; // 鼠标移动事件是否完成(鼠标按下到抬起的流程)
      window.addEventListener('mouseup', this.handleMouseUp);
      window.addEventListener('keydown', this.handleKeydown)
      window.addEventListener('keyup', this.handleKeyup)
    },
    handleKeydown(e) {
      console.log(e,e.keyCode)
      if(e.keyCode == 17) {
        this.isPressCtrl = true
      }
    },
    handleKeyup(e){
      this.isPressCtrl = false
    },
    // 画选中框 - 鼠标按下
    handleMouseDown(e) {
      this.containerClickStartTime = +new Date()
      this.startPoint.x = e.clientX;
      this.startPoint.y = e.clientY;
      this.mouseKey = true;
      this.mouseComplete = false;
    },
    // 画选中框 - 鼠标按下并移动
    handleMouseMove(e) {
      if (this.mouseKey && !this.mouseComplete) {
        this.endPoint.x = e.clientX
        this.endPoint.y = e.clientY
        this.getSelectCharts()
      }
    },
     // 根据选中的内容,处理数据和选中图表的样式
    getSelectCharts() {
      const selectAreaBox = document.getElementById('selectAreaBox')
      let {left, right, bottom, top} = selectAreaBox.getBoundingClientRect()

      let allCharts = document.querySelectorAll('.vdr')
      let selectedChartsDOM = []
      let currentSelectChartIdArr = []
      let currentChartDataArr = []
      allCharts.forEach(item => {
        item.classList.remove('active')
        item.classList.remove('inactive')
        item.classList.add('inactive')
        let child = item.getBoundingClientRect()
        if (child.left > left && child.top > top && child.bottom < bottom && child.right < right) {
          item.classList.remove('inactive')
          item.classList.add('active')
          item.style.backgroundColor='#00aaff'
          selectedChartsDOM.push(item);

          let chartId = item.getAttribute('dataChartId')
          currentSelectChartIdArr.push(chartId)
          let chartData = this.datalist.find(item => item.id === chartId)
          if(chartData) {
            currentChartDataArr.push(chartData)
          }
        } else {
          item.style.backgroundColor='#fff'
        }
      })
      this.selectedChartsDOM = selectedChartsDOM
      this.currentSelectChartIdArr = currentSelectChartIdArr
      // 在这里把所有数据的dragging重置为false,避免vueDragResize和自己写的拖动事件发生冲突
      currentChartDataArr.forEach((item, index) => {
        item.dragging = false
      })
      this.currentChartDataArr = currentChartDataArr
      this.oldCurrentChartDataArr = JSON.parse(JSON.stringify(currentChartDataArr))
      if(this.currentChartDataArr.length === 0) {
        this.isSingleFlag = true
      } else {
        this.isSingleFlag = false
      }
    },
    // 画选中框 -- 鼠标抬起, 如果是点击主区域除图表外的其他地方,取消所有图表的选中状态
    handleMouseUp(e){
      this.mouseKey = false;
      this.mouseComplete = true;
      this.startPoint.x = 0;
      this.startPoint.y = 0;
      this.endPoint.x = 0;
      this.endPoint.y = 0;
      this.containerClickEndTime = +new Date()
      if(this.containerClickEndTime - this.containerClickStartTime <= 300) {
        this.resetSelectMuti()
        this.isSingleFlag = true
      }
    },
    // 拖拽图表 -- 鼠标按下
    onChartDragStart(e, data) {
      this.clickStartTime = +new Date()
      if(this.isPressCtrl) {
        return false
      }
      if(this.currentSelectChartIdArr.length === 0 || this.isSingleFlag) {
        this.resetSelectMuti(e, data)
      }
      
      this.dragFlag = true
      this.startX = e.clientX
      this.startY = e.clientY

      // 找出最左,最右,最上,最下的元素
      this.getOutermost()
    },
    getOutermost() {
      let leftArr = [], rightArr = [], topArr = [], bottomArr = []
      this.oldCurrentChartDataArr.forEach(item => {
        leftArr.push(item.x)
        topArr.push(item.y)
        rightArr.push(item.x + item.w)
        bottomArr.push(item.y + item.h)
      })
      this.leftMax = Math.min(...leftArr)
      this.rightMax = Math.max(...rightArr)
      this.topMax = Math.min(...topArr)
      this.bottomMax = Math.max(...bottomArr)
    },
    moveChart(moveX, moveY) {
      const {width, height} = document.querySelector('.main-container').getBoundingClientRect()
      let {leftMax, rightMax, topMax, bottomMax} = this
      if(this.currentSelectChartIdArr.length) {
        this.currentChartDataArr.forEach((item, index) => {
          if(moveX < 0 && leftMax + moveX >= 0 || moveX > 0 && rightMax + moveX <= width) {
            item.x = this.oldCurrentChartDataArr[index].x + moveX
          }
          if(moveY < 0 && topMax + moveY >= 0 || moveY > 0 && bottomMax + moveY <= height) {
            item.y = this.oldCurrentChartDataArr[index].y + moveY
          }
        })
      }
    },
    // 多选时拖拽图表 -- 鼠标按住拖拽
    onChartDragging(e) {
      if(!this.dragFlag) {
        return false
      }
      if(this.isPressCtrl) {
        return false
      }
      let moveX = e.clientX - this.startX
      let moveY = e.clientY - this.startY
      this.moveChart(moveX, moveY)
    },
    // 多选时拖拽图表 -- 拖拽结束, 如果是单击了某个图表,取消其他图表的选中状态
    onChartDragStop(e, data) {
      this.clickEndTime = +new Date()
      this.oldCurrentChartDataArr = JSON.parse(JSON.stringify(this.currentChartDataArr))
      this.dragFlag = false
      this.clickEndTime = +new Date()
      if(this.clickEndTime - this.clickStartTime <=300) {
        // ctrl + 单击 多选
        if(this.isPressCtrl) {
          data.dragging = false
          let vdrBox = $(e.target).parents(".vdr")[0]
          
          let chartId = vdrBox.getAttribute('dataChartId')
          let index = this.currentSelectChartIdArr.indexOf(chartId)
          if(index > -1) {
            this.currentSelectChartIdArr.splice(index, 1)
            this.currentChartDataArr.splice(index, 1)
            this.selectedChartsDOM.splice(index, 1)
            vdrBox.style.backgroundColor = '#fff'
          } else {
            this.currentSelectChartIdArr.push(chartId)
            this.currentChartDataArr.push(data)
            this.selectedChartsDOM.push(vdrBox)
            vdrBox.style.backgroundColor = '#00aaff'
          }
          this.oldCurrentChartDataArr = JSON.parse(JSON.stringify(this.currentChartDataArr))
          this.isSingleFlag = this.currentSelectChartIdArr.length === 0
        } else {
          this.resetSelectMuti(e, data)
          this.isSingleFlag = true
        }
      }
    },
    // 重置图表的选中状态
    resetSelectMuti(e, data) {
      this.currentSelectChartIdArr = []
      this.datalist.forEach(item => {
        item.dragging = false
      })
      this.selectedChartsDOM.forEach(item => {
        item.style.backgroundColor = '#fff'
      })
      this.currentChartDataArr = []
      this.selectedChartsDOM = []
      this.oldCurrentChartDataArr = []
      if(data) {
        data.dragging = true
        let vdrBox = $(e.target).parents(".vdr")[0]
        let chartId = vdrBox.getAttribute('dataChartId')
        this.currentSelectChartIdArr.push(chartId)
        this.currentChartDataArr.push(data)
        this.selectedChartsDOM.push(vdrBox)
        this.oldCurrentChartDataArr = JSON.parse(JSON.stringify(this.currentChartDataArr))
      }
    }
  }
}
</script>

<style lang="less">
* {
  margin: 0;
  padding: 0;
}
.body {
  width: 100%;
  height: 100vh;
  position: relative;
  >div {
    height: 100%;
    &.left {
      position: absolute;
      width: 300px;
      left: 0;
      top: 0;
      background: rgb(228, 125, 189);
    }
    
    &.main-container {
      margin: 0 100px 0 300px;
      position: relative;
      background: rgb(224, 247, 182);
      >div{
        background: #fff;
      }
    }
    
    &.right {
      position: absolute;
      width: 100px;
      right: 0;
      top: 0;
      background: rgb(228, 125, 189);
    }
  }
}
</style>

组件selectArea

<template>
  <div
    id="selectAreaBox"
    class="select-area"
    :style="[
      { width: size.width + 'px' },
      { height: size.height + 'px' },
      { top: Point.y + 'px' },
      { left: Point.x + 'px' },
    ]"
  >
  </div>
</template>

<script>
export default {
  name: 'SelectArea',
  props: {
    startPoint: {
      type: Object,
      required: true,
    },
    endPoint: {
      type: Object,
      required: true,
    },
  },
  computed:{
    Point() {
      let x = this.endPoint.x === 0 ? this.startPoint.x : Math.min(this.startPoint.x, this.endPoint.x);
      let y =  this.endPoint.y === 0  ? this.startPoint.y : Math.min(this.startPoint.y, this.endPoint.y);
      return {
        x,
        y,
      };
    },
    size(){
      let width = this.endPoint.x === 0 ? 0 : Math.abs(this.startPoint.x - this.endPoint.x);
      let height = this.endPoint.y === 0 ? 0 : Math.abs(this.startPoint.y - this.endPoint.y);
      return {
        width,
        height,
      };
    }
  },
}
</script>
<style lang="less">
.select-area {
  position: fixed;
  background-color: rgba(255, 192, 203, 0.1);
  border: 1px solid red;
  z-index: 9;
}
</style>
<think>好的,我现在需要处理用户关于PyMOL中碳地图相关的鼠标操作或功能的查询。首先,我需要确认用户提到的“碳地图”具体指的是什么。在PyMOL中,常见的术语有碳链显示、碳原子高亮等,但“碳地图”可能是指展示碳原子分布或碳链结构的可视化模式。 接下来,我会检查用户提供的引用内容,引用[1]提到的是颜色设置函数,可能与对象的颜色分配有关。用户可能想通过鼠标操作调整碳原子的颜色或显示方式。此外,我需要回忆PyMOL中常用的鼠标操作,比如旋转、平移、缩放,以及择特定原子或残基的方式。 然后,考虑用户可能需要的具体功能,例如通过鼠标点击择碳原子,或者调整碳链的显示样式(如stick、sphere等)。PyMOL中通常使用鼠标右键菜单或快捷键来切换显示模式。例如,按住Shift和右键点击对象,可以择不同的显示方式。 另外,用户可能希望了解如何通过鼠标操作生成碳相关的表面图或静电势图,这可能需要结合其他命令,如“show surface”或“util.protein_contact_dots”。不过需要确认这些功能是否直接与鼠标操作相关。 可能还需要检查是否有特定的插件或脚本可以实现碳地图的交互式操作。例如,使用“carbonmap”命令或相关脚本,但需要验证是否存在这样的功能。 最后,整理出常见的鼠标操作步骤,并确保每个步骤都符合PyMOL的实际操作,同时引用正确的文档或参考资料。如果某些功能不明确,可能需要建议用户查阅PyMOL的官方手册或社区论坛获取更详细的信息。</think>### PyMOL中与碳原子相关的鼠标操作及功能 在PyMOL中,直接与“碳地图”(可能指碳原子可视化或碳链结构)相关的鼠标操作主要集中在**原子择**和**显示模式调整**上。以下是具体操作步骤: 1. **择碳原子**: - **单击择**:按住`Ctrl`键 + **左键单击**碳原子,可选中单个碳原子。 - **框选多个原子**:按住`Ctrl+Shift`键 + **左键拖拽**框选区域,多个碳原子[^1]。 2. **调整碳链显示模式**: - **右键菜单操作**:在对象上按住`Shift`键 + **右键单击**,择显示模式如`sticks`(棍状模型)或`spheres`(球体模型),突出显示碳链结构[^1]。 - **快捷键切换**:选中原子后,按`S`键切换为棍状模型,按`A`键切换为球体模型。 3. **颜色设置**: - 通过`Color`菜单或命令行设置碳原子颜色,例如输入命令`color green, name C`将所有碳原子设为绿色。 4. **表面图生成**: - 对选中的碳链区域,使用菜单`Show > Surface`或命令`show surface`生成静电势或疏水表面图,结合鼠标拖拽旋转查看分布。 ```python # 示例:PyMOL命令行操作(非鼠标,但可辅助功能) cmd.select("carbons", "name C") # 择所有碳原子 cmd.show("sticks", "carbons") # 显示为棍状模型 cmd.color("green", "carbons") # 设为绿色 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值