/* * general */ export function randomString(n = 8, prefix = "") { const length = n - prefix.length; return Math.random().toString(36).substring(2, 2 + length); } export function calcAngle(a, b) { //已经a与b是直角三角两边,求b与c的夹角 const angleRad = Math.atan(b / a); return 90 - angleRad * (180 / Math.PI); } /* * slidev */ export function isShow(rng, click) { if (Array.isArray(rng)) { return rng.includes(click) } else { return [-1, click].includes(rng) } } /* * css */ export function mergeTransform(baseTransform, additionalTransform) { // If there's no base transform, just return the additional one. if (!baseTransform) return additionalTransform; // Split the base transform into an array, assuming each transformation is separated by a space. let transforms = baseTransform.split(' '); // Check if the additional transform is already present to avoid duplication. // This is a simplistic check and assumes the additional transform does not contain complex cases like chained transformations. if (!transforms.includes(additionalTransform)) { // If it's not present, append the new transformation ensuring there's a space before it for proper CSS formatting. transforms.push(additionalTransform); } // Join the array back into a single string and return. return transforms.join(' '); } /* * svg paths */ export function _buildChatBotClipPath(id_, rectWidth, rectHeight, triangleSide, side, borderRadius) { const triangleHeight = triangleSide * Math.sqrt(3) / 2; // 根据正三角形性质计算高度 let [x0, y0, x1, y1, x2, y2] = [0, 0, 0, 0, 0, 0, 0, 0] let [rx, ry, rw, rh] = [0, 0, rectWidth, rectHeight] if (side === "right") { x0 = x1 = rectWidth - triangleHeight y0 = rectHeight / 2 - triangleSide / 2 y1 = rectHeight / 2 + triangleSide / 2 x2 = rectWidth y2 = rectHeight / 2 //for the rect rx = 0 ry = 0 rw = rectWidth - triangleHeight rh = rectHeight } else if (side === "left") { x0 = x1 = triangleHeight y0 = rectHeight / 2 - triangleSide / 2 y1 = rectHeight / 2 + triangleSide / 2 y2 = rectHeight / 2 //for the rect rx = triangleHeight ry = 0 rw = rectWidth - triangleHeight rh = rectHeight } else if (side === "top") { x0 = rectWidth / 2 - triangleSide / 2 x1 = rectWidth / 2 + triangleSide / 2 y0 = y1 = triangleHeight x2 = rectWidth / 2 //for the rect rx = triangleHeight ry = 0 rw = rectWidth rh = rectHeight - triangleHeight } else { y0 = y1 = rectHeight x0 = rectWidth / 2 - triangleSide / 2 x1 = rectWidth / 2 + triangleSide / 2 x2 = rectWidth / 2 y2 = triangleHeight / 2 + rectHeight //for the rect rx = 0 ry = 0 rw = rectWidth rh = rectHeight - triangleHeight } const polygonPoints = [ `${x0} ${y0}`, `${x1} ${y1}`, `${x2} ${y2}` ].join(', '); return ` `; } //chatbox是指一个矩形,其中一边有三角形凸起。 export function buildChatBotClipPath(rectWidth, rectHeight, side = "left", triSideLen = 0, borderRadius = 10, id_ = "") { if (!id_) { id_ = randomString(); } if (!triSideLen) { if (side in ["left", "right"]) { triSideLen = rectHeight / 7 } else { triSideLen = rectWidth / 7 } } const svgDefs = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); svgDefs.setAttribute('xmlns', 'http://www.w3.org/2000/svg'); svgDefs.setAttribute('width', '0'); svgDefs.setAttribute('height', '0'); let clipPath = _buildChatBotClipPath(id_, rectWidth, rectHeight, triSideLen, side, borderRadius); svgDefs.innerHTML = clipPath document.body.appendChild(svgDefs); console.debug("clip path is", clipPath); //返回clipPath, 可以用el.style.clipPath = buildChatBotClipPath()... return `url(#${id_})`; } /** * * @param a 边长A * @param b 边长B * @param c 边长C * @param deg a与b的夹角 */ export function trianglePathData(a: number, b: number, c?: number, thetaDegrees?: number, offset?: Array): string { let [x, y] = offset ? offset : [0, 0]; if (thetaDegrees !== undefined && thetaDegrees !== 0) { // 使用两边和夹角计算路径 if (c !== undefined) { console.info("trianglePath: 当提供了θ时,边长c将被忽略。"); } const thetaRadians = thetaDegrees * (Math.PI / 180); let p1 = [0 + x, 0 + y]; let p2 = [a + x, 0 + y]; let p3 = [b * Math.cos(thetaRadians) + x, b * Math.sin(thetaRadians) + y]; let d = `M${p1.join(' ')} L${p2.join(' ')} L${p3.join(' ')} Z`; return `` } else if (c !== undefined) { if (a + b <= c || a + c <= b || b + c <= a) { throw new Error("给定边长无法构成三角形。"); } // 使用余弦定理计算角度 const alphaRad = Math.acos((b * b + c * c - a * a) / (2 * b * c)); const betaRad = Math.acos((a * a + c * c - b * b) / (2 * a * c)); const gammaRad = Math.PI - alphaRad - betaRad; const p1 = [0 + x, 0 + y]; const p2 = [c + x, 0 + y]; const p3 = [ p2[0] + b * Math.cos(gammaRad) + x, p2[1] + b * Math.sin(gammaRad) + y ]; let d = `M${p1.join(' ')} L${p2.join(' ')} L${p3.join(' ')} Z` return `` } else { throw new Error("必须提供θ(thetaDegrees)或边长c以确定三角形。"); } } export function createSVGFromPath(parentEl, path, fill, stroke, strokeWidth = "1") { try { const svgNS = "http://www.w3.org/2000/svg"; const svgElement = document.createElementNS(svgNS, "svg"); // svgElement.setAttribute("width", "600"); // svgElement.setAttribute("height", "400"); // 创建SVG路径元素并设置路径数据 svgElement.id = "test" const pathElement = document.createElementNS(svgNS, "path"); pathElement.setAttribute("d", path); pathElement.setAttribute("fill", fill); pathElement.setAttribute("stroke", stroke); pathElement.setAttribute("stroke-width", strokeWidth); svgElement.appendChild(pathElement); parentEl.appendChild(svgElement); } catch (error) { console.error(error.message); } }