先看一下效果,鼠标滑过标尺显示辅助线,点击标尺保留辅助线,双击辅助线消失
WeChatc9123af2459643ba9bfe6bb59be1e625.jpg
1.编写canvasRuler.js
const ruler = {
/**
* @el 容器 String
* @height 刻度尺高度 Number
* @maxScale 最大刻度 Number
* @startValue 开始的值 Number
* @region 区间 Array
* @background 刻度尺背景颜色 String
* @color 刻度线和字体的颜色 String
* @markColor 中心刻度标记颜色 String
* @isConstant 是否不断地获取值 Boolean
* @success(res) 滑动结束后的回调 Function
* */
initRow: function (params) {
const initParams = {
el: params.el.current, // id or node
height: params.height || 60,
maxScale: params.maxScale || 200,
startValue: params.startValue || 0,
region: params.region || false,
background: params.background || false,
color: params.color || false,
markColor: params.markColor || '#FFCC33',
isConstant: params.isConstant || false,
startGap: params.startGap || 0,
};
const elNode =
initParams.el instanceof HTMLElement ? initParams.el : document.querySelector(initParams.el);
if (!elNode) {
console.warn('缺少容器');
return false;
}
const rulerWrap = elNode; // 获取容器
rulerWrap.style.height = initParams.height + 'px';
// 最大刻度的小值是50
initParams.maxScale = initParams.maxScale < 50 ? 50 : initParams.maxScale;
if (initParams.startValue > initParams.maxScale) {
initParams.startValue = initParams.maxScale;
}
const count = initParams.startValue; // 初始值
const winWidth = rulerWrap.offsetWidth; // 容器宽度
const division = 10; // 每个刻度的距离 分割线
let canvas = rulerWrap.getElementsByTagName('canvas')[0]; // 获取容器下的canvas标签
// 没有canvas就创建一个
if (!canvas) {
canvas = document.createElement('canvas'); // 创建canvas标签
canvas.width = winWidth;
canvas.height = initParams.height;
rulerWrap.appendChild(canvas);
}
const cxt = canvas.getContext('2d');
if (window.devicePixelRatio) {
canvas.width = window.devicePixelRatio * winWidth;
canvas.height = window.devicePixelRatio * initParams.height;
cxt.scale(window.devicePixelRatio, window.devicePixelRatio);
}
// 画刻度尺
function drawRuler(count) {
// count = count - 25
// 清空画布
cxt.clearRect(0, 0, winWidth, initParams.height);
// 刻度尺背景
if (initParams.background) {
cxt.fillStyle = initParams.background;
cxt.fillRect(0, 0, canvas.width, initParams.height);
}
// 画刻度线
for (let i = 0; i < initParams.maxScale; i++) {
cxt.beginPath();
cxt.save();
cxt.strokeStyle = initParams.color ? initParams.color : '#bbb';
cxt.lineWidth = 1;
cxt.lineCap = 'round';
const x = division * i - count * division + initParams.startGap;
cxt.moveTo(x, initParams.height);
cxt.lineTo(x, Math.floor(initParams.height * 0.8));
if (i % 5 === 0) {
cxt.strokeStyle = initParams.color ? initParams.color : '#666';
cxt.lineTo(x, Math.floor(initParams.height * 0.5));
}
if (i % 10 === 0) {
cxt.strokeStyle = initParams.color ? initParams.color : '#666';
cxt.font = '10px Arial';
cxt.fillStyle = initParams.color ? initParams.color : '#333';
cxt.textAlign = 'left';
cxt.textBaseline = 'middle';
cxt.lineTo(x, 0);
cxt.fillText(String(i * division), x + 2, Math.floor(initParams.height * 0.5));
}
cxt.stroke();
cxt.restore();
cxt.closePath();
}
// 底部线条
cxt.beginPath();
cxt.save();
cxt.strokeStyle = initParams.color ? initParams.color : '#bbb';
cxt.lineWidth = 1;
cxt.lineCap = 'round';
cxt.moveTo(0, initParams.height - 1);
cxt.lineTo(winWidth, initParams.height - 1);
cxt.stroke();
cxt.restore();
cxt.closePath();
}
if (window.devicePixelRatio) {
canvas.style.transform = 'scale(' + 1 / window.devicePixelRatio + ')';
canvas.style.transformOrigin = 'left top';
}
drawRuler(count);
},
initColumn: function (params) {
const initParams = {
el: params.el.current, // id or node
width: params.width || 60,
maxScale: params.maxScale || 200,
startValue: params.startValue || 0,
region: params.region || false,
background: params.background || false,
color: params.color || false,
markColor: params.markColor || '#FFCC33',
isConstant: params.isConstant || false,
startGap: params.startGap || 0,
};
const elNode =
initParams.el instanceof HTMLElement ? initParams.el : document.querySelector(initParams.el);
if (!elNode) {
console.warn('缺少容器');
return false;
}
const rulerWrap = elNode; // 获取容器
rulerWrap.style.width = initParams.height + 'px';
// 最大刻度的小值是50
initParams.maxScale = initParams.maxScale < 50 ? 50 : initParams.maxScale;
if (initParams.startValue > initParams.maxScale) {
initParams.startValue = initParams.maxScale;
}
const count = initParams.startValue; // 初始值
const winHeight = rulerWrap.offsetHeight; // 容器宽度
const division = 10; // 每个刻度的距离 分割线
let canvas = rulerWrap.getElementsByTagName('canvas')[0]; // 获取容器下的canvas标签
// 没有canvas就创建一个
if (!canvas) {
canvas = document.createElement('canvas'); // 创建canvas标签
canvas.height = winHeight;
canvas.width = initParams.width;
rulerWrap.appendChild(canvas);
}
const cxt = canvas.getContext('2d');
if (window.devicePixelRatio) {
canvas.height = window.devicePixelRatio * winHeight;
canvas.width = window.devicePixelRatio * initParams.width;
cxt.scale(window.devicePixelRatio, window.devicePixelRatio);
}
// 画刻度尺
function drawRuler(count) {
// count = count - 25
// 清空画布
cxt.clearRect(0, 0, initParams.width, winHeight);
// 刻度尺背景
if (initParams.background) {
cxt.fillStyle = initParams.background;
cxt.fillRect(0, 0, canvas.width, winHeight);
}
// 画刻度线
for (let i = 0; i < initParams.maxScale; i++) {
cxt.beginPath();
cxt.save();
cxt.strokeStyle = initParams.color ? initParams.color : '#bbb';
cxt.lineWidth = 1;
cxt.lineCap = 'round';
const y = division * i - count * division + initParams.startGap;
cxt.moveTo(initParams.width, y);
cxt.lineTo(Math.floor(initParams.width * 0.8), y);
if (i % 5 === 0) {
cxt.strokeStyle = initParams.color ? initParams.color : '#666';
cxt.lineTo(Math.floor(initParams.width * 0.5), y);
}
if (i % 10 === 0) {
cxt.strokeStyle = initParams.color ? initParams.color : '#666';
cxt.font = '10px Arial';
cxt.fillStyle = initParams.color ? initParams.color : '#333';
cxt.textAlign = 'left';
cxt.textBaseline = 'middle';
cxt.lineTo(0, y);
cxt.fillText(String(i * division), 0, y + 8);
}
cxt.stroke();
cxt.restore();
cxt.closePath();
}
cxt.beginPath();
cxt.save();
cxt.strokeStyle = initParams.color ? initParams.color : '#bbb';
cxt.lineWidth = 1;
cxt.lineCap = 'round';
cxt.moveTo(initParams.width - 1, 0);
cxt.lineTo(initParams.width - 1, winHeight);
cxt.stroke();
cxt.restore();
cxt.closePath();
}
if (window.devicePixelRatio) {
canvas.style.transform = 'scale(' + 1 / window.devicePixelRatio + ')';
canvas.style.transformOrigin = 'left top';
}
drawRuler(count);
},
};
export default ruler;
2.创建ruler.tsx文件
import { useState, useEffect, useRef } from 'react';
import type { MutableRefObject } from 'react';
import styles from './index.less';
import ruler from './canvasRuler';
import { useModel } from 'umi';
interface RulerProps {
top: number;
left: number;
}
function Ruler(props: RulerProps) {
// const LEFT_SIDE_WIDTH = 240 // 左侧边栏的宽度
const TOP_RULER_HEIGHT = 21; // 顶部标尺高度
// const mainPanelScrollY = 0
// console.log(useModel)
const { addReferenceLinecol, addReferenceLinerow, removeReferenceLine, removeReferenceLinerow } =
useModel('useRuler', (data) => ({
addReferenceLinecol: data.addReferenceLinecol,
addReferenceLinerow: data.addReferenceLinerow,
removeReferenceLine: data.removeReferenceLine,
removeReferenceLinerow: data.removeReferenceLinerow,
}));
const { referenceLine } = useModel('useRuler');
const [topMoving, settopMoving] = useState('none');
const [columnX, setcolumnX] = useState(0);
const [leftMoving, setleftMoving] = useState('none');
const [colHandleMoveReady, setcolHandleMoveReady] = useState(false);
const [rowHandleMoveReady, setrowHandleMoveReady] = useState(false);
const [rowY, setrowY] = useState(0);
const columnXRef = useRef(columnX);
const rowYRef = useRef(rowY);
const columnXInRuler = () => {
return columnX - TOP_RULER_HEIGHT;
};
const rowYInRuler = () => {
return rowY - 50;
};
const addColumn = (value?: number) => {
if (value) {
addReferenceLinecol(value);
} else {
addReferenceLinecol(columnX);
}
};
const addRow = (value?: number) => {
// debugger
if (value) {
addReferenceLinerow(value);
} else {
addReferenceLinerow(rowY);
}
};
// const rowElPositionFix = () => {
// return {
// transform: `translateY(${mainPanelScrollY}px)`
// }
// }
const topRuler: MutableRefObject<any> = useRef(null);
const leftRuler: MutableRefObject<any> = useRef(null);
const topMouseUp = (e: React.MouseEvent<HTMLDivElement, globalThis.MouseEvent>): void => {
if (colHandleMoveReady) {
return;
}
addColumn();
};
const topMouseEnter = (e: React.MouseEvent<HTMLDivElement, globalThis.MouseEvent>) => {
settopMoving('block');
setcolumnX(e.pageX - props.left);
};
const topMouseMove = (e: React.MouseEvent<HTMLDivElement, globalThis.MouseEvent>) => {
setcolumnX(e.pageX - props.left);
};
const topMouseLeave = () => {
if (colHandleMoveReady) {
return;
}
settopMoving('none');
};
const leftMouseUp = (e: React.MouseEvent<HTMLDivElement, globalThis.MouseEvent>) => {
if (rowHandleMoveReady) {
return;
}
addRow();
};
const leftMouseEnter = () => {
setleftMoving('block');
};
const leftMouseMove = (e: React.MouseEvent<HTMLDivElement, globalThis.MouseEvent>) => {
// console.log(e.pageY - props.top)
setrowY(e.pageY - props.top);
};
const leftMouseLeave = () => {
if (rowHandleMoveReady) {
return;
}
setleftMoving('none');
};
//添加topruler辅助线拖动功能
const colHandleDown = (
e: React.MouseEvent<HTMLDivElement, globalThis.MouseEvent>,
index: number,
) => {
setcolHandleMoveReady(true);
let invoked = false;
document.body.style.cursor = 'col-resize';
const mouseMoveFn = (_e: any) => {
if (!invoked) {
removeReferenceLine(index);
topMouseEnter(_e);
invoked = true;
}
topMouseMove(_e);
};
const mouseUpFn = () => {
if (invoked) {
// console.log(columnXRef.current)
addColumn(columnXRef.current);
}
setcolHandleMoveReady(false);
topMouseLeave();
document.removeEventListener('mousemove', mouseMoveFn);
document.removeEventListener('mouseup', mouseUpFn);
document.body.style.cursor = 'initial';
};
document.addEventListener('mousemove', mouseMoveFn);
document.addEventListener('mouseup', mouseUpFn);
};
//添加leftruler辅助线拖动功能
const rowHandleDown = (
e: React.MouseEvent<HTMLDivElement, globalThis.MouseEvent>,
index: number,
) => {
setrowHandleMoveReady(true);
let invoked = false;
document.body.style.cursor = 'row-resize';
const mouseMoveFn = (_e: any) => {
if (!invoked) {
removeReferenceLinerow(index);
leftMouseEnter();
invoked = true;
}
leftMouseMove(_e);
// console.log(_e.pageY)
};
const mouseUpFn = () => {
if (invoked) {
// console.log(columnXRef.current)
addRow(rowYRef.current);
}
setrowHandleMoveReady(false);
leftMouseLeave();
document.removeEventListener('mousemove', mouseMoveFn);
document.removeEventListener('mouseup', mouseUpFn);
document.body.style.cursor = 'initial';
};
document.addEventListener('mousemove', mouseMoveFn);
document.addEventListener('mouseup', mouseUpFn);
};
useEffect(() => {
columnXRef.current = columnX;
rowYRef.current = rowY;
ruler.initRow({
el: topRuler,
height: TOP_RULER_HEIGHT,
color: 'rgba(255, 255, 255, 0.2)',
background: '#0B0C12',
startGap: TOP_RULER_HEIGHT - 1,
});
ruler.initColumn({
el: leftRuler,
width: TOP_RULER_HEIGHT,
color: 'rgba(255, 255, 255, 0.2)',
background: '#0B0C12',
startGap: 50 - 1,
maxScale: 501,
});
}, [columnX, rowY]);
const referenceLineColList = referenceLine.col.map((item, index) => {
return (
<div
key={'col' + index + item}
className={`${styles.referenceLine} ${styles.column}`}
style={{ left: item + 'px' }}
onMouseDown={(e) => {
colHandleDown(e, index);
}}
onDoubleClick={() => {
removeReferenceLine(index);
}}
></div>
);
});
const referenceLineRowList = referenceLine.row.map((item, index) => {
return (
<div
key={'row' + index + item}
className={`${styles.referenceLine} ${styles.row}`}
style={{ top: item + 'px' }}
onMouseDown={(e) => {
rowHandleDown(e, index);
}}
onDoubleClick={() => {
removeReferenceLinerow(index);
}}
></div>
);
});
return (
<div className={styles.posterRuler}>
<div className={styles.topRuler}>{referenceLineColList}</div>
<div className={styles.leftRuler}>{referenceLineRowList}</div>
<div
onMouseEnter={(e) => {
topMouseEnter(e);
}}
onMouseMove={(e) => {
topMouseMove(e);
}}
onMouseLeave={(e) => {
topMouseLeave();
}}
onMouseUp={(e) => {
topMouseUp(e);
}}
ref={topRuler}
className={styles.topRuler}
>
<div
style={{ left: columnX + 'px', display: topMoving }}
className={`${styles.referenceLine} ${styles.column}`}
>
<div
className={styles.tip}
draggable="false"
onDragStart={() => {
return false;
}}
>
{columnXInRuler()}
</div>
</div>
</div>
<div
onMouseEnter={(e) => {
leftMouseEnter();
}}
onMouseMove={(e) => {
leftMouseMove(e);
}}
onMouseLeave={(e) => {
leftMouseLeave();
}}
onMouseUp={(e) => {
leftMouseUp(e);
}}
ref={leftRuler}
className={styles.leftRuler}
>
<div
style={{ top: rowY + 'px', display: leftMoving }}
className={`${styles.referenceLine} ${styles.row} ${styles.moving}`}
>
<div
className={styles.tip}
draggable="false"
onDragStart={() => {
return false;
}}
>
{rowYInRuler()}
</div>
</div>
</div>
</div>
);
}
export default Ruler;
index.less文件
.posterRuler {
position: absolute;
z-index: 10;
}
.topRuler {
position: absolute;
top: 0;
left: 0;
z-index: 100;
width: 5000px;
height: 22px;
cursor: col-resize;
}
.leftRuler {
position: absolute;
top: 0;
left: 0;
z-index: 99;
width: 22px;
height: 6000px;
cursor: row-resize;
transition: 0.5s;
}
.tip {
position: absolute;
padding: 4px 6px;
// background-color: rgba($color: #000000, $alpha: 0.6);
color: #fff;
font-size: 13px;
border-radius: 4px;
user-select: none;
pointer-events: none;
}
.column {
top: 0;
width: 3px;
height: 5000px;
margin-left: -2px;
// background-color: #4A83FF;
background: linear-gradient(90deg, transparent 33.3%, #eceef0 0, #53ebef 66.6%, transparent 0);
cursor: col-resize;
.tip {
top: 30px;
left: 10px;
}
}
.row {
left: 0;
width: 5000px;
height: 3px;
margin-top: -2px;
background: linear-gradient(0deg, transparent 33.3%, #eceef0 0, #53ebef 66.6%, transparent 0);
cursor: row-resize;
transition: 0.1s;
.tip {
top: -30px;
left: 30px;
}
}
.moving {
transition: none;
}
.referenceLine {
position: absolute;
z-index: 99;
}
引入useModel(umi的redux)
import { useModel } from 'umi';
useRuler.js文件
import { useState, useCallback, useEffect, useRef } from 'react';
const useRuler = () => {
const [referenceLine, setreferenceLine] = useState({
row: [],
col: [],
});
const [referenceLineOpened, setreferenceLineOpened] = useState(true);
const [matchedLine, setmatchedLine] = useState(null);
const [mainPanelScrollY, setmainPanelScrollY] = useState(0);
let referenceLineOpenedRef = useRef(referenceLine);
const SET_REFERENCE_LINE_VISIBLE = () => {
setreferenceLineOpened(!referenceLineOpened);
};
const addReferenceLinecol = useCallback(
(c) => {
setreferenceLine({
row: [...referenceLine.row],
col: [...referenceLineOpenedRef.current.col, c],
});
},
[referenceLine.row],
);
const removeReferenceLine = useCallback(
(index) => {
let oldcol = referenceLineOpenedRef.current.col;
oldcol.splice(index, 1);
setreferenceLine({
row: [...referenceLine.row],
col: [...oldcol],
});
},
[referenceLine.row],
);
const removeReferenceLinerow = useCallback(
(index) => {
let oldrow = referenceLineOpenedRef.current.row;
// debugger
oldrow.splice(index, 1);
setreferenceLine({
row: [...oldrow],
col: [...referenceLine.col],
});
},
[referenceLine.col],
);
const addReferenceLinerow = useCallback(
(c) => {
setreferenceLine({
row: [...referenceLineOpenedRef.current.row, c],
col: [...referenceLine.col],
});
},
[referenceLine.col],
);
useEffect(() => {
referenceLineOpenedRef.current = referenceLine;
}, [referenceLine]);
return {
referenceLine,
referenceLineOpened,
matchedLine,
mainPanelScrollY,
SET_REFERENCE_LINE_VISIBLE,
addReferenceLinecol,
addReferenceLinerow,
removeReferenceLine,
removeReferenceLinerow,
};
};
export default useRuler;
3.引入ruler组件,传入距离top和left的值
import Ruler from './ruler/rulers';
<Ruler top={100} left={280}></Ruler>
4.下面附加一个vue2版本的
<template>
<div class="poster-ruler">
<template v-if="referenceLineOpened">
<!-- 纵向参考线 -->
<div
v-for="(item, index) in referenceLine.col"
:key="'col' + index + item"
class="reference-line column"
:style="{ left: item + 'px' }"
@dblclick="removeReferenceLine({ type: 'col', index })"
@mousedown="colHandleDown($event, index)"
/>
<!-- 横向参考线 -->
<div
v-for="(item, index) in referenceLine.row"
:key="'row' + index + item"
class="reference-line row"
:style="{ top: item + 'px', ...rowElPositionFix }"
@dblclick="removeReferenceLine({ type: 'row', index })"
@mousedown="rowHandleDown($event, index)"
/>
</template>
<!-- 顶部标尺 -->
<div
ref="topRuler"
class="top-ruler"
@mouseenter="topMouseEnter"
@mousemove="topMouseMove"
@mouseleave="topMouseLeave"
@mouseup="topMouseUp"
>
<div
v-if="topMoving"
class="reference-line column"
:style="{ left: columnX + 'px' }"
>
<div class="tip" draggable="false" ondragstart="return false">
{{ columnXInRuler }}
</div>
</div>
</div>
<!-- 左侧标尺 -->
<div
ref="leftRuler"
class="left-ruler"
:style="rowElPositionFix"
@mouseenter="leftMouseEnter"
@mousemove="leftMouseMove"
@mouseleave="leftMouseLeave"
@mouseup="leftMouseUp"
>
<div
v-if="leftMoving"
class="reference-line row moving"
:style="{ top: rowY + 'px' }"
>
<div class="tip" draggable="false" ondragstart="return false">
{{ rowYInRuler }}
</div>
</div>
</div>
<!-- 动态匹配的参考线 -->
<matched-line :row-el-position-fix="rowElPositionFix" />
</div>
</template>
<script>
import ruler from 'poster/utils/canvasRuler'
import { mapState, mapActions } from 'poster/poster.vuex'
import matchedLine from './matchedLine'
const LEFT_SIDE_WIDTH = 240 // 左侧边栏的宽度
const TOP_RULER_HEIGHT = 21 // 顶部标尺高度
export default {
components: { matchedLine },
data() {
return {
topMoving: false,
columnX: 0,
leftMoving: false,
rowY: 0
}
},
computed: {
...mapState(['referenceLine', 'referenceLineOpened', 'mainPanelScrollY']),
columnXInRuler() {
return this.columnX - TOP_RULER_HEIGHT
},
rowYInRuler() {
return this.rowY - 50
},
rowElPositionFix() {
return {
transform: `translateY(${this.mainPanelScrollY}px)`
}
}
},
mounted() {
ruler.initRow({
el: this.$refs.topRuler,
height: TOP_RULER_HEIGHT,
color: 'rgba(255, 255, 255, 0.5)',
background: '#0B0C12',
startGap: TOP_RULER_HEIGHT - 1
})
ruler.initColumn({
el: this.$refs.leftRuler,
width: TOP_RULER_HEIGHT,
color: 'rgba(255, 255, 255, 0.5)',
background: '#0B0C12',
startGap: 50 - 1,
maxScale: 501
})
},
methods: {
...mapActions(['addReferenceLine', 'removeReferenceLine']),
addColumn() {
this.addReferenceLine({ type: 'col', position: this.columnX })
},
addRow() {
this.addReferenceLine({ type: 'row', position: this.rowY })
},
topMouseEnter(e) {
this.topMoving = true
this.columnX = e.pageX - LEFT_SIDE_WIDTH
},
topMouseMove(e) {
this.columnX = e.pageX - LEFT_SIDE_WIDTH
},
topMouseLeave() {
if (this.colHandleMoveReady) {
return
}
this.topMoving = false
},
topMouseUp() {
if (this.colHandleMoveReady) {
return
}
this.addColumn()
},
leftMouseEnter(e) {
this.leftMoving = true
// this.rowY = e.pageY - this.mainPanelScrollY
},
leftMouseMove(e) {
this.rowY = e.pageY - this.mainPanelScrollY
},
leftMouseLeave() {
if (this.rowHandleMoveReady) {
return
}
this.leftMoving = false
},
leftMouseUp() {
if (this.rowHandleMoveReady) {
return
}
this.addRow()
},
colHandleDown(e, index) {
this.colHandleMoveReady = true
let invoked = false
document.body.style.cursor = 'col-resize'
const mouseMoveFn = _e => {
if (!invoked) {
this.removeReferenceLine({ type: 'col', index })
this.topMouseEnter(_e)
invoked = true
}
this.topMouseMove(_e)
}
const mouseUpFn = () => {
if (invoked) {
this.addColumn()
}
this.colHandleMoveReady = false
this.topMouseLeave()
document.removeEventListener('mouseup', mouseUpFn)
document.removeEventListener('mousemove', mouseMoveFn)
document.body.style.cursor = 'initial'
}
document.addEventListener('mousemove', mouseMoveFn)
document.addEventListener('mouseup', mouseUpFn)
},
rowHandleDown(e, index) {
this.rowHandleMoveReady = true
let invoked = false
document.body.style.cursor = 'row-resize'
const mouseMoveFn = _e => {
if (!invoked) {
this.removeReferenceLine({ type: 'row', index })
this.leftMouseEnter(_e)
invoked = true
}
this.leftMouseMove(_e)
}
const mouseUpFn = () => {
if (invoked) {
this.addRow()
}
this.rowHandleMoveReady = false
this.leftMouseLeave()
document.removeEventListener('mouseup', mouseUpFn)
document.removeEventListener('mousemove', mouseMoveFn)
document.body.style.cursor = 'initial'
}
document.addEventListener('mousemove', mouseMoveFn)
document.addEventListener('mouseup', mouseUpFn)
}
}
}
</script>
<style lang="scss" scoped>
.poster-ruler {
z-index: 10;
}
.top-ruler {
position: absolute;
top: 0;
left: 0;
height: 22px;
width: 5000px;
/* border-bottom: 1px solid #bac3c9; */
z-index: 100;
cursor: col-resize;
}
.left-ruler {
position: absolute;
top: 0;
left: 0;
width: 22px;
height: 6000px;
z-index: 99;
/* border-right: 1px solid #bac3c9; */
cursor: row-resize;
transition: 0.5s;
}
.reference-line {
/* background-color: #ff0000; */
position: absolute;
z-index: 99;
.tip {
padding: 4px 6px;
border-radius: 4px;
background-color: rgba($color: #000000, $alpha: 0.6);
color: #fff;
font-size: 13px;
position: absolute;
user-select: none;
pointer-events: none;
}
&.column {
width: 3px;
height: 5000px;
margin-left: -2px;
top: 0;
cursor: col-resize;
background-color: #4A83FF;
background: linear-gradient(
90deg,
transparent 33.3%,
#4A83FF 66.6%,
#4A83FF 66.6%,
transparent 0
);
.tip {
top: 30px;
left: 10px;
}
}
&.row {
width: 5000px;
height: 3px;
margin-top: -2px;
left: 0;
cursor: row-resize;
transition: 0.1s;
background: linear-gradient(
0deg,
transparent 33.3%,
#4A83FF 66.6%,
#4A83FF 66.6%,
transparent 0
);
.tip {
top: -30px;
left: 30px;
}
&.moving {
transition: none;
}
}
}
</style>