鼠标拖拽—自定义布局(电影院)

  • Post author:
  • Post category:其他




鼠标拖拽点击—电影院自定义布局



标签

鼠标拖拽、自定义布局



效果

自定义布局-电影院



目的

疫情期间,电影院都是隔空而坐,想用

html



css



js



jq

做个简单的自定义布局。



介绍

自定义布局中有银幕、列号、过道、座位和预留五个元素,可通过鼠标点击和鼠标拖拽选中格子,进行个性化定制



用法

  1. 首先输入布局的宽高
  2. 点击按钮,生成空白座位图
  3. 选择颜色块中的一个标识,进行定制

    1. 点击红色块,进行座位选中,可用单击可用鼠标拖动,按照拖动方向正序生成数字
    2. 点击紫色块,进行预留选中,可用单击选中
    3. 点击橙色块,进行座位和预留取消,可用单击可用鼠标拖动
    4. 点击粉紫块,进行第一行选中,可用单击选中取消
    5. 点击灰色块,进行过道选中,可用单击可用鼠标拖动
  4. 定制完成后,可点击按钮进行预览



代码




html

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>自定义布局</title>
	<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
	<link rel="stylesheet" type="text/css" href="templateLayout.css">
</head>
<body>
	<div class="wrapper">
		<div id="moveSelected"></div>
		<div class="flexBox">
			<div class="designBox">
				<div class="title">疫情期间电影院自定义布局</div>
				<!-- 布局长宽 -->
				<div class="inputBox">
					<p>
						横: <input type="number" id="sideWidth" name="sideWidth" onchange="setWidth()" value="30">
						纵: <input type="number" id="sideHeight" name="sideHeight" onchange="setHeight()" value="5">
					</p>
					<p>
						是否显示:
						<input type="radio" name="rostrum" onchange="setRostrum()" value="yes" checked><input type="radio" name="rostrum" onchange="setRostrum()" value="no"></p>
				</div>

				<!-- 布局按钮 -->
				<div class="btnBox">
					<div>
						<button onclick="createCanvas()">生成座位图</button>
						<button class="preview" onclick="toPreview()">布局预览</button>
					</div>
					<div onclick="selectSeat()"><span class="selectBtn seat"></span>座位</div>
					<div onclick="selectReverse()"><span class="selectBtn reverse"></span>预留</div>
					<div onclick="cancelSelect()"><span class="selectBtn cancel"></span>取消</div>
					<div onclick="selectColumn()"><span class="selectBtn column"></span>列号</div>
					<div onclick="selectRoad()"><span class="selectBtn road"></span>过道</div>
				</div>
			</div>
			<div class="operationBox">
				<div class="title">使用说明</div>
				<ol>
					<li>首先输入布局的宽高</li>
					<li>点击按钮,生成空白座位图</li>
					<li>
						<div>选择颜色块中的一个标识,进行定制</div>
						<ol type="i" class="colorExplain">
							<li>点击红色块,进行座位选中,可用单击可用鼠标拖动,按照拖动方向正序生成数字</li>
							<li>点击紫色块,进行预留选中,可用单击选中</li>
							<li>点击橙色块,进行座位和预留取消,可用单击可用鼠标拖动</li>
							<li>点击粉紫块,进行第一行选中,可用单击选中取消</li>
							<li>点击灰色块,进行过道选中,可用单击可用鼠标拖动</li>
						</ol>
					</li>
					<li>定制完成后,可点击按钮进行预览</li>
				</ol>
			</div>
		</div>

		<!-- 布局内容 -->
		<div>
			<div class="ulBox">
				<div class="rostrum">
					银幕
					<div class="line"></div>
				</div>
			</div>
			<div class="ulBox">
				<ul class="flexBox getAllLi columnList" onclick="setColumn(event)"></ul>
			</div>
			<div class="ulBox">
				<ul class="ulList getAllLi flexBox" onmousedown="mouseDown(event)"></ul>
			</div>
		</div>
	</div>
	<script type="text/javascript" src="templateLayout.js"></script>
</body>
</html>




css

*{
	margin: 0;
	padding:0;
}
.wrapper{
	padding:10px;
}
.title{
	font-weight: bold;
	font-size:24px;
}
.inputBox{
	margin:10px 0;
}
.inputBox input[type='number']{
	height:32px;
	line-height: 32px;
	outline: none;
	border:1px solid #ddd;
	padding-left:5px;
}
.inputBox p{
	line-height: 32px;
}
ul li{
	list-style: none;
}
.newBtna a{
    display: inline;
    background-color: transparent;
    border: 0;
    border-radius: 0;
    color: $editBtnColor;
    font-size: 17px;
    padding: 8px 15px 8px 0;
    // margin-right: 5px;
}
.version{
  padding-top:3px;
}
.btnBox{
  display: flex;
  /*margin-left:20px;*/
  align-items: center;
  height:35px;
}
.btnBox button{
	border:0;
	outline: none;
	color:#fff;
	background-color: #2582EB;
	padding: 6px 12px;
	border-radius: 4px;
	cursor: pointer;
}
.btnBox button + button{
	margin-right:20px;
}
.btnBox > div *{
  vertical-align: middle;
}
.btnBox > div + div{
  margin-left:20px;
}
.selectBtn{
  display: inline-block;
  width:35px;
  height:35px;
  margin-right:5px;
  cursor: pointer;
}
.seat{
	background:#F75A1C;
}
.reverse{
	background: #C61CF7;
}
.cancel{
	background:#F7B21C;
}
.column{
	background:#F71CC9;
}
.ulBox{
	overflow: auto;
}
.flexBox{
	display: flex;
}
.designBox, .operationBox{
	width: 50%;
}
.ulList,.columnList{
	width:0px;
	height:0px;
	flex-wrap: wrap;
	margin: 10px 0 0 30px;
}
.liItem{
	width:29px;
	height:29px;
	margin:0 9px 9px 0;
	border:1px solid pink;
	cursor: pointer;
	border-radius: 8px;
}
.selectedSeat{
	background:#F75A1C;
	color:#fff;
	text-align:center;
	line-height: 30px;
	border-color: #F75A1C;
}
.selectedRemain{
	background:#C61CF7;
	color:#C61CF7;
	border-color:#C61CF7 !important;
}
.selectedColumn{
	background:#F71CC9;
	color:#fff;
	text-align:center;
	line-height: 30px;
	border-color:#F71CC9 !important;
}
.road{
	background:#ddd;
	color:#ddd;
	text-align:center;
	border-color:#ddd !important;
}
#moveSelected{
	position: absolute;
	width:0;
	height:0;
	left:0;
	top:0;
	opacity:0.2;
	background:#000;
}
.version-record{
	margin-top:30px;
}
.rostrum{
	position: relative;
	display: none;
	/*background:#BCBCBC;*/
	text-align: center;
	line-height: 40px;
	margin: 30px 0 0 30px;
	overflow: hidden;
	font-size:12px;
	color:#aaa;
}
.line{
	position: absolute;
	width: 80%;
	height:100%;
	top:5px;
	left:10%;
	border-top:5px solid pink;
	border-radius: 100%;
	/*box-shadow: 1px 2px 3px pink;*/
}
.colorExplain{
	padding-left:20px;
}




javascript

let sideWidth = 30 //画布宽
let sideHeight = 5 //画布长
let createFlag = false //生成画布标志
let liDomCollect = ''
let selectedSeatArr = [] //选择的座位(需要排序)
let selectColumnArr = [] //选择的列号(需要排序)
let selectType = ''//选择座位、预留、取消选择等
let dragFlag = false //鼠标拖动标志
let oldTop = '' // 鼠标点下位置
let oldLeft = '' // 鼠标点下位置
let moveSelected = $("#moveSelected") //鼠标拖动遮罩层
let dragDirection = 0 //拖动方向,左下、左上、右上、右下
let previewFlag = true //预览标志
let setFirstRow = '' //设置列号或者过道
let isFullCol = false //是否选满列号

let seat = ''//座位实际位置
let reserveseat = ''//预留实际位置
let seatamount = ''//座位+预留的实际位置数目
let seatnum = ''//座位和预留的按照顺序来序号,预留的都用0表示,座位会按照拖动顺序生成序号
let isHasRostrum = '0'//是否有主席台  (0无1有)
let isHasCol = '0'//是否有列号  (0无1有)

/**
* 是否显示银幕
*/
function setRostrum(){
	let val = $("input[name='rostrum']:checked").val()
	if(val == 'yes'){
		$('.rostrum').css('display','block')
	}else{
		$('.rostrum').css('display','none')
	}
}

/**
* 设置布局长度
*/
function setWidth(){
	sideWidth = $('#sideWidth').val()
	console.log(sideWidth)
}
/**
* 设置布局宽度
*/
function setHeight(){
	sideHeight = $('#sideHeight').val()
	console.log(sideHeight)
}
/**
* 生成画布
*/
function createCanvas(){
	let wide = Number(sideHeight);
	let long= Number(sideWidth);
	if( !(wide > 0 && long > 0) ){
		alert('请输入合适的数值')
		return
	}
	$('.rostrum').css('display','block')
	createFlag = true;
	let numLi = long*wide
	
	// 生成主席台
	$(".rostrum").css({"width":long*40 - 9 + 'px',"height":'40px'})
	
	// 生成列号
	$(".columnList").css({"width":long*40 + 'px',"height":'40px'})
	let columnLi = ""
	let createColumn = long
	while(createColumn>0){
		columnLi += '<li class="liItem" data='+(long - createColumn + 1)+'></li>'
		createColumn--
	}
	$(".columnList").html('')
	$(".columnList").append(columnLi)
	
	// 生成画布
	$(".ulList").css({"width":long*40 + 'px',"height":wide*40 + 'px'});
	let liDom = ""
	let loopNum = numLi
	while(numLi>0){
		liDom += '<li class="liItem" data='+(loopNum - numLi + 1)+'></li>'
		numLi--;
	}
	liDomCollect = liDom
	$(".ulList").html('');
	selectedSeatArr = [];
	selectColumnArr = [];
	$(".ulList").append(liDomCollect)
}

/**
* 设置列号,并对布局中选中的进行处理
*/
function setColumn(e){
	if(e.target.tagName == 'UL'){
		return
	}
	switch(setFirstRow){
		case 'column':
			if($(e.target).hasClass('road')){
				$(e.target).removeClass('road');
				clearColumn($(e.target).attr('data'),true);
			}
			if($(e.target).hasClass('selectedColumn')){
				$(e.target).removeClass('selectedColumn');
				$(e.target).text("");
				removeItem(selectColumnArr,e.target);
				sortSelectedArr(selectColumnArr);
			}else{
				let columnLen = selectColumnArr.length;
				$(e.target).addClass('selectedColumn');
				$(e.target).text(columnLen + 1);
				selectColumnArr.push(e.target);
			}
			break;
		case 'road':
			let isClearRoad = false;
			if($(e.target).hasClass('selectedColumn')){
				$(e.target).removeClass('selectedColumn');
				removeItem(selectColumnArr,e.target);
				sortSelectedArr(selectColumnArr);
				$(e.target).addClass('road');
				$(e.target).text("-1");
			}else if($(e.target).hasClass('road')){
				$(e.target).removeClass('road');
				$(e.target).text("");
				isClearRoad = true;
			}else{
				$(e.target).addClass('road');
				$(e.target).text("-1");
			}
			clearColumn($(e.target).attr('data'),isClearRoad)
			break;
		default :
			alert("请选择列号或者过道")
			break;
	}
	
}
// 处理选中过道之后画布的清空操作
function clearColumn(realColumn,isClearRoad){
	let columnNum = Number(sideHeight);
	let width = Number(sideWidth);
	let index = Number(realColumn);
	let columnLiArr = []; 
	for(let i=0; i<columnNum;i++){
		let findIndex = index + i*width
		columnLiArr.push($(".ulList li[data="+findIndex+"]")[0]);
	}
	for(let j=0; j<columnLiArr.length; j++){
		if(!isClearRoad){
			$(columnLiArr[j]).addClass('road');
			// 去掉预留
			if($(columnLiArr[j]).hasClass('selectedRemain')){
				$(columnLiArr[j]).removeClass('selectedRemain');
			}
			// 去掉座位
			if($(columnLiArr[j]).hasClass('selectedSeat')){
				$(columnLiArr[j]).removeClass('selectedSeat');
				$(columnLiArr[j]).text("");
				removeItem(selectedSeatArr,columnLiArr[j])
			}
		}
		else{
			$(columnLiArr[j]).removeClass('road');
		}
	}
	sortSelectedArr(selectedSeatArr);
}
// 鼠标按下
function mouseDown(e){
	console.log(e)
	if(selectType === ''){
		alert('请选择座位位置或者预留位置');
		return;
	}
	//选中座位区域
	console.log(moveSelected)
	if(selectType === 'seat' || selectType === 'cancelFlag'){
		dragFlag = true;
		oldTop = e.pageY;
		oldLeft = e.pageX;
		moveSelected.css({"top":oldTop+'px',"left":oldLeft+'px'});
		e.preventDefault();
		e.stopPropagation();
	}
	// 选择预留座位
	if(selectType === 'reverse'){
		// 当前为过道不可选
		if($(e.target).hasClass('road')){
			alert('过道不可选')
			return;
		}
		let curTarget = $(e.target);
		if(curTarget.hasClass("liItem")){
			if(curTarget.hasClass("selectedSeat") && !(curTarget.hasClass("selectedRemain"))){
				curTarget.removeClass("selectedSeat").addClass("selectedRemain");
				curTarget.text("");
				// this.selectedReverseArr.push(curTarget);
				removeItem(selectedSeatArr,e.target);
				sortSelectedArr(selectedSeatArr);
			}else if(curTarget.hasClass("selectedRemain")){
				// 删除已选预留
				curTarget.removeClass("selectedRemain");
				// this.removeItem(this.selectedReverseArr,e.target);
			}else{
				// 添加已选预留
				curTarget.addClass("selectedRemain");
				// this.selectedReverseArr.push(curTarget);
			}
		}
	}
	document.onmousemove = (e) => {
		if(!dragFlag) return
		if(selectType === 'seat' || selectType === 'cancelFlag'){
			let newTop = e.pageY;
			let newLeft = e.pageX;
			let moveWidth = oldLeft - newLeft;
			let moveHeight = newTop - oldTop;
			// 四个方向   需要处理左下选中超过两行 右上选中超过两行
			// 向左拖动
			if(newLeft < oldLeft){
				// that.moveSelected.css({"left":newLeft+'px',"width":moveWidth+'px'})
				if(newTop > oldTop){
					// 左下 需要处理
					dragDirection = 2;
					moveSelected.css({"height":moveHeight+'px',"left":newLeft+'px',"width":moveWidth+'px'})
				}else{
					// 左上
					dragDirection = 1;
					moveSelected.css({"top":newTop+'px',"height":(oldTop-newTop)+'px',"left":newLeft+'px',"width":moveWidth+'px'})
				}
			}
			// 向右拖动
			else{
				// that.moveSelected.css({"width":(newLeft-that.oldLeft)+'px'});
				if(newTop > oldTop){
					// 右下 需要处理
					dragDirection = 0;
					moveSelected.css({"height":moveHeight+'px',"width":(newLeft-oldLeft)+'px'})
				}else{
					// 右上
					dragDirection = 3;
					moveSelected.css({"top":newTop+'px',"height":(oldTop-newTop)+'px',"width":(newLeft-oldLeft)+'px'})
				}
			}
		}
	}
	// $(document).mousemove( )
	document.onmouseup = (e) => {
		if(selectType === 'seat' || selectType === 'cancelFlag'){
			let right = moveSelected.width() + moveSelected.offset().left + 'px';
			let bottom = moveSelected.height() + moveSelected.offset().top + 'px';
			moveSelected.css({"right":right,"bottom":bottom});
			findSelectLi();
			dragFlag = false;
			initmoveSelected();
			e.preventDefault();
			e.stopPropagation();
		}
		dragFlag=false;
		moveSelected.css({"width":"0px","height":"0px","top":"0px","left":"0px"});
		$(document).unbind("mousemove");
		$(document).unbind("mouseup");
	}
}
/**
*	预览功能
*/
function toPreview(){
	if(previewFlag){
		$("li").css("border-color","#fff");
		$(".preview").text("取消预览");
	}else{
		$("li").css("border-color","pink");
		$(".preview").text("生成预览");
	}
	previewFlag = !previewFlag;
}
/**
*	选择座位
*/
function selectSeat(){
	selectType = 'seat';
}
/**
*	选择预留
*/
function selectReverse(){
	selectType = 'reverse';
}
/**
*	取消选择
*/
function cancelSelect(){
	selectType = 'cancelFlag';
}
/**
*	选择选择列号
*/
function selectColumn(){
	setFirstRow = 'column';
}
/**
*	选择过道
*/
function selectRoad(){
	setFirstRow = 'road';
}
// 选择选中的li
function findSelectLi(){
	let selectedLi = [];
	let prevLen = selectedSeatArr.length;
	let blockLi = $(".ulList").find("li");
	let len = blockLi.length
	for(let i=0;i<len;i++){
		// 获取方块位置
		let left = $(blockLi[i]).offset().left;
		let right = $(blockLi[i]).width() + left;
		let top = $(blockLi[i]).offset().top;
		let bottom = $(blockLi[i]).height() + top;

		// 获取遮罩层的位置
		let moveSelectedLeft = moveSelected.offset().left;
		let moveSelectedRight = Number(moveSelected.css("right").split('px')[0]);
		let moveSelectedTop = moveSelected.offset().top;
		let moveSelectedBottom = Number(moveSelected.css("bottom").split('px')[0]);
		if(right > moveSelectedLeft && bottom > moveSelectedTop && left < moveSelectedRight && top < moveSelectedBottom){
			// this.cancelFlag ? $(blockLi[i]).removeClass("selectedSeat") : $(blockLi[i]).addClass("selectedSeat");
			selectedLi.push(blockLi[i]);
		}
	}
	if(selectType === 'seat'){
		// 处于选中座位的状态下,不处于拖动取消的状态,如果拖动选择的格子包含已选格子,则无效
		// 选中一个的时候
		//let hasRoad = false;//判断是否包含过道
		let repeatNum = 0;
		let curSelectNum = selectedLi.length;
		for(let i=0;i<curSelectNum;i++){
			// 包含过道就无效,return终止循环
			if($(selectedLi[i]).hasClass('road')){
				return;
			}
			for(let j=0;j<selectedSeatArr.length;j++){
				selectedSeatArr[j] == selectedLi[i] ? repeatNum++ : '';
			}
		}

		// 点击一个已选格子,将其取消
		if(curSelectNum === 1 && $(selectedLi[0]).hasClass("selectedSeat")){
			$(selectedLi[0]).removeClass("selectedSeat");
			$(selectedLi[0]).text("");
			removeItem(selectedSeatArr,selectedLi[0]);
			// 删除后重新排序
			sortSelectedArr(selectedSeatArr);
			return;
		}
		if(repeatNum >= 1 && curSelectNum > 1){
			selectedLi = [];
		}else{
			switch(dragDirection){
				// 右下,不需要处理
				case 0:
					selectedLi = processLi(selectedLi,prevLen);
					break;
				// 左上 逆序
				case 1:
					selectedLi.reverse();
					selectedLi = processLi(selectedLi,prevLen)
					break;
				// 左下 需要处理
				case 2:
					selectedLi = processSpecialLi(selectedLi,prevLen);
					break;
				// 右上 需要处理
				case 3:
					selectedLi = processSpecialLi(selectedLi,prevLen);
					break;
				default:
					break;
				}
				let prevArr = selectedSeatArr;
				// console.log('处理之后的selectedLi',selectedLi);
				selectedSeatArr = prevArr.concat(selectedLi);
			}
		}else{
			// 判断取消座位,拖动选择的格子去掉类名和序号,并且已选格子重新排序。
			let curSelectNum = selectedLi.length;
			for(let i=0;i<curSelectNum;i++){
				// 取消绿色格子并重新排序
				if($(selectedLi[i]).hasClass("selectedSeat")){
					$(selectedLi[i]).removeClass("selectedSeat");
					$(selectedLi[i]).text("");
					removeItem(selectedSeatArr,selectedLi[i]);
				}
				// 取消蓝色格子
				if($(selectedLi[i]).hasClass("selectedRemain")){
					$(selectedLi[i]).removeClass("selectedRemain");
					// this.removeItem(this.selectedReverseArr,selectedLi[i]);
				}
			}
			sortSelectedArr(selectedSeatArr);
		}
}
// 从座位数组或者预留数组里面删除特定项
function removeItem(arr,item){
	let arrLength = arr.length;
	if(arrLength !== 0){
		for(let i=0;i<arrLength;i++){
			if(arr[i] == item){
				arr.splice(i,1);
			}
		}
	}
}
// 动态排序已选中座位
function sortSelectedArr(arr){
	let arrLength = arr.length;
	if(arrLength !== 0){
		for(let i=0;i<arrLength;i++){
			$(arr[i]).text(i+1);
		}
	}
}
// 处理
function processLi(arr,prevLen){
	for(let i=0;i<arr.length;i++){
		if($(arr[i]).hasClass("selectedRemain")){
			$(arr[i]).removeClass("selectedRemain")
		}
		$(arr[i]).text(prevLen+i+1);
		$(arr[i]).addClass("selectedSeat");
	}
	return arr;
}
//处理左上和右下方向拖动选中的li
function processSpecialLi(arr,prevLen){
	let cutNum = 0;
	let cutLen = 0;
	let finalArr = [];
	let loopLen = arr.length;
	// 截取多少段
	for(let i=0;i<loopLen-1;i++){
		if($(arr[i]).attr("data") - $(arr[i+1]).attr("data") !== -1){
			cutNum++;
		}
	}
	// 每一段截取的长度
	cutLen = parseInt(loopLen / (cutNum+1));
	if(cutLen > Number(sideWidth)){
		cutLen = Number(sideWidth);
	}
	
	// 获取每一行被截断的li数组
	let cutArr = group(arr,cutLen);
	
	// 如果鼠标往右上角拉动时,截取的cutArr需要做一个逆序的处理
	if(dragDirection === 3){
		cutArr.reverse();
	}else{
		// 否则是右下角拉动鼠标的时候,li数组内需要做一个逆序的处理
		cutArr.forEach(function(value,index){
			value.reverse();
		})
	}
	cutArr.map(function(value,index){
		finalArr = finalArr.concat(value);
	})
	let arrNeed = processLi(finalArr,prevLen);
	return arrNeed;
}
function group(array, subGroupLength){
	var index = 0;
	var newArray = [];
	while(index < array.length) {
	newArray.push(array.slice(index, index += subGroupLength));
	}
	return newArray;
}
// 初始化moveSelected
function initmoveSelected(){
	moveSelected.css({"width":"0px","height":"0px","top":"0px","left":"0px","bottom":"0px","right":"0px"});
}

// 获取要保存或者发布的数据
function obtainSaveData(){
	let finalLi = $(".ulList").find("li");
	let loopLen = finalLi.length;
	let seatString = '';
	let reverseString = '';
	let total = 0;
	let order = '';
	// 获取的画布中的座位和预留
	for(let i=0;i<loopLen;i++){
		if($(finalLi[i]).hasClass("selectedRemain") || $(finalLi[i]).hasClass("selectedSeat")){
			if($(finalLi[i]).hasClass("selectedRemain")){
				order +=  "0";
				reverseString += $(finalLi[i]).attr("data") + ',';

			}else{
				seatString += $(finalLi[i]).attr("data") + ',';
				order +=  $(finalLi[i]).text();
			}
			total++;
			order += ',';
		}
	}
	// 获取列号和过道
	if(showColumnRow){
		isHasCol = '1';
		let realCol = '';
		let showCol = '';
		let selectCol = 0;
		let colLi = $(".columnList").find("li");
		for(let i=0; i<colLi.length; i++){
			realCol += $(colLi[i]).attr('data') + ',';
			showCol += $(colLi[i]).text() + ',';
			if($(colLi[i]).text() !== ''){
				selectCol++;
			}
		}
		if(selectCol == colLi.length){
			isFullCol = true;
		}
		// this.formData.realCol = realCol.substring(0,realCol.length-1);
		// this.formData.showCol = showCol.substring(0,showCol.length-1);
	}
	
	// this.formData.seat = seatString.substring(0,seatString.length-1);
	// this.formData.reserveseat = reverseString.substring(0,reverseString.length-1);
	// this.formData.seatamount = String(total);
	// this.formData.seatnum = order.substring(0,order.length-1);
	// this.showRostrum ? this.formData.isHasRostrum = '1': '';
	// let sendData = this.formData
	// return sendData;
}



版权声明:本文为weixin_42060560原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。