123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332 |
- const { abs, sqrt, sin, cos, max, min, PI } = Math
- /**
- * @description Clone an object or array
- * @param {Object|Array} object Cloned object
- * @param {Boolean} recursion Whether to use recursive cloning
- * @return {Object|Array} Clone object
- */
- export function deepClone (object, recursion = false) {
- if (!object) return object
- const { parse, stringify } = JSON
- if (!recursion) return parse(stringify(object))
- const clonedObj = object instanceof Array ? [] : {}
- if (object && typeof object === 'object') {
- for (let key in object) {
- if (object.hasOwnProperty(key)) {
- if (object[key] && typeof object[key] === 'object') {
- clonedObj[key] = deepClone(object[key], true)
- } else {
- clonedObj[key] = object[key]
- }
- }
- }
- }
- return clonedObj
- }
- /**
- * @description Eliminate line blur due to 1px line width
- * @param {Array} points Line points
- * @return {Array} Line points after processed
- */
- export function eliminateBlur (points) {
- return points.map(([x, y]) => [parseInt(x) + 0.5, parseInt(y) + 0.5])
- }
- /**
- * @description Check if the point is inside the circle
- * @param {Array} point Postion of point
- * @param {Number} rx Circle x coordinate
- * @param {Number} ry Circle y coordinate
- * @param {Number} r Circle radius
- * @return {Boolean} Result of check
- */
- export function checkPointIsInCircle (point, rx, ry, r) {
- return getTwoPointDistance(point, [rx, ry]) <= r
- }
- /**
- * @description Get the distance between two points
- * @param {Array} point1 point1
- * @param {Array} point2 point2
- * @return {Number} Distance between two points
- */
- export function getTwoPointDistance ([xa, ya], [xb, yb]) {
- const minusX = abs(xa - xb)
- const minusY = abs(ya - yb)
- return sqrt(minusX * minusX + minusY * minusY)
- }
- /**
- * @description Check if the point is inside the polygon
- * @param {Array} point Postion of point
- * @param {Array} points The points that makes up a polyline
- * @return {Boolean} Result of check
- */
- export function checkPointIsInPolygon (point, polygon) {
- let counter = 0
- const [x, y] = point
- const pointNum = polygon.length
- for (let i = 1, p1 = polygon[0]; i <= pointNum; i++) {
- const p2 = polygon[i % pointNum]
- if (x > min(p1[0], p2[0]) && x <= max(p1[0], p2[0])) {
- if (y <= max(p1[1], p2[1])) {
- if (p1[0] !== p2[0]) {
- const xinters = (x - p1[0]) * (p2[1] - p1[1]) / (p2[0] - p1[0]) + p1[1]
- if (p1[1] === p2[1] || y <= xinters) {
- counter++
- }
- }
- }
- }
- p1 = p2
- }
- return counter % 2 === 1
- }
- /**
- * @description Check if the point is inside the sector
- * @param {Array} point Postion of point
- * @param {Number} rx Sector x coordinate
- * @param {Number} ry Sector y coordinate
- * @param {Number} r Sector radius
- * @param {Number} startAngle Sector start angle
- * @param {Number} endAngle Sector end angle
- * @param {Boolean} clockWise Whether the sector angle is clockwise
- * @return {Boolean} Result of check
- */
- export function checkPointIsInSector (point, rx, ry, r, startAngle, endAngle, clockWise) {
- if (!point) return false
- if (getTwoPointDistance(point, [rx, ry]) > r) return false
- if (!clockWise) [startAngle, endAngle] = deepClone([endAngle, startAngle])
- const reverseBE = startAngle > endAngle
- if (reverseBE) [startAngle, endAngle] = [endAngle, startAngle]
- const minus = endAngle - startAngle
- if (minus >= PI * 2) return true
- const [x, y] = point
- const [bx, by] = getCircleRadianPoint(rx, ry, r, startAngle)
- const [ex, ey] = getCircleRadianPoint(rx, ry, r, endAngle)
- const vPoint = [x - rx, y - ry]
- let vBArm = [bx - rx, by - ry]
- let vEArm = [ex - rx, ey - ry]
- const reverse = minus > PI
- if (reverse) [vBArm, vEArm] = deepClone([vEArm, vBArm])
- let inSector = isClockWise(vBArm, vPoint) && !isClockWise(vEArm, vPoint)
- if (reverse) inSector = !inSector
- if (reverseBE) inSector = !inSector
- return inSector
- }
- /**
- * @description Determine if the point is in the clockwise direction of the vector
- * @param {Array} vArm Vector
- * @param {Array} vPoint Point
- * @return {Boolean} Result of check
- */
- function isClockWise (vArm, vPoint) {
- const [ax, ay] = vArm
- const [px, py] = vPoint
- return -ay * px + ax * py > 0
- }
- /**
- * @description Check if the point is inside the polyline
- * @param {Array} point Postion of point
- * @param {Array} polyline The points that makes up a polyline
- * @param {Number} lineWidth Polyline linewidth
- * @return {Boolean} Result of check
- */
- export function checkPointIsNearPolyline (point, polyline, lineWidth) {
- const halfLineWidth = lineWidth / 2
- const moveUpPolyline = polyline.map(([x, y]) => [x, y - halfLineWidth])
- const moveDownPolyline = polyline.map(([x, y]) => [x, y + halfLineWidth])
- const polygon = [...moveUpPolyline, ...moveDownPolyline.reverse()]
- return checkPointIsInPolygon(point, polygon)
- }
- /**
- * @description Check if the point is inside the rect
- * @param {Array} point Postion of point
- * @param {Number} x Rect start x coordinate
- * @param {Number} y Rect start y coordinate
- * @param {Number} width Rect width
- * @param {Number} height Rect height
- * @return {Boolean} Result of check
- */
- export function checkPointIsInRect ([px, py], x, y, width, height) {
- if (px < x) return false
- if (py < y) return false
- if (px > x + width) return false
- if (py > y + height) return false
- return true
- }
- /**
- * @description Get the coordinates of the rotated point
- * @param {Number} rotate Degree of rotation
- * @param {Array} point Postion of point
- * @param {Array} origin Rotation center
- * @param {Array} origin Rotation center
- * @return {Number} Coordinates after rotation
- */
- export function getRotatePointPos (rotate = 0, point, origin = [0, 0]) {
- if (!point) return false
- if (rotate % 360 === 0) return point
- const [x, y] = point
- const [ox, oy] = origin
- rotate *= PI / 180
- return [
- (x - ox) * cos(rotate) - (y - oy) * sin(rotate) + ox,
- (x - ox) * sin(rotate) + (y - oy) * cos(rotate) + oy
- ]
- }
- /**
- * @description Get the coordinates of the scaled point
- * @param {Array} scale Scale factor
- * @param {Array} point Postion of point
- * @param {Array} origin Scale center
- * @return {Number} Coordinates after scale
- */
- export function getScalePointPos (scale = [1, 1], point, origin = [0, 0]) {
- if (!point) return false
- if (scale === 1) return point
- const [x, y] = point
- const [ox, oy] = origin
- const [xs, ys] = scale
- const relativePosX = x - ox
- const relativePosY = y - oy
- return [
- relativePosX * xs + ox,
- relativePosY * ys + oy
- ]
- }
- /**
- * @description Get the coordinates of the scaled point
- * @param {Array} translate Translation distance
- * @param {Array} point Postion of point
- * @return {Number} Coordinates after translation
- */
- export function getTranslatePointPos (translate, point) {
- if (!translate || !point) return false
- const [x, y] = point
- const [tx, ty] = translate
- return [x + tx, y + ty]
- }
- /**
- * @description Get the distance from the point to the line
- * @param {Array} point Postion of point
- * @param {Array} lineBegin Line start position
- * @param {Array} lineEnd Line end position
- * @return {Number} Distance between point and line
- */
- export function getDistanceBetweenPointAndLine (point, lineBegin, lineEnd) {
- if (!point || !lineBegin || !lineEnd) return false
- const [x, y] = point
- const [x1, y1] = lineBegin
- const [x2, y2] = lineEnd
- const a = y2 - y1
- const b = x1 - x2
- const c = y1 * (x2 - x1) - x1 * (y2 - y1)
- const molecule = abs(a * x + b * y + c)
- const denominator = sqrt(a * a + b * b)
- return molecule / denominator
- }
- /**
- * @description Get the coordinates of the specified radian on the circle
- * @param {Number} x Circle x coordinate
- * @param {Number} y Circle y coordinate
- * @param {Number} radius Circle radius
- * @param {Number} radian Specfied radian
- * @return {Array} Postion of point
- */
- export function getCircleRadianPoint (x, y, radius, radian) {
- return [x + cos(radian) * radius, y + sin(radian) * radius]
- }
- /**
- * @description Get the points that make up a regular polygon
- * @param {Number} x X coordinate of the polygon inscribed circle
- * @param {Number} y Y coordinate of the polygon inscribed circle
- * @param {Number} r Radius of the polygon inscribed circle
- * @param {Number} side Side number
- * @param {Number} minus Radian offset
- * @return {Array} Points that make up a regular polygon
- */
- export function getRegularPolygonPoints (rx, ry, r, side, minus = PI * -0.5) {
- const radianGap = PI * 2 / side
- const radians = new Array(side).fill('').map((t, i) => i * radianGap + minus)
- return radians.map(radian => getCircleRadianPoint(rx, ry, r, radian))
- }
- export default {
- deepClone,
- eliminateBlur,
- checkPointIsInCircle,
- checkPointIsInPolygon,
- checkPointIsInSector,
- checkPointIsNearPolyline,
- getTwoPointDistance,
- getRotatePointPos,
- getScalePointPos,
- getTranslatePointPos,
- getCircleRadianPoint,
- getRegularPolygonPoints,
- getDistanceBetweenPointAndLine
- }
|