admin管理员组文章数量:1304931
I am currently working on a side project, where I want to "draw" diagrams. At the moment you just drag "sticky notes" to a grid, move, resize and label them. I now want to connect these notes with arrows. I got the calculations for length (pythagoras) and the angle of the line down.
calculateAngle(): number {
return Math.atan2(this._start.y - this._end.y, this._start.x - this._end.x) * 180 / Math.PI + 180;
}
calculateLength(): number {
return Math.round(Math.sqrt(Math.pow(this._start.y - this._end.y, 2) + Math.pow(this._start.x - this._end.x, 2)));
}
I also found a simple CSS solution for the arrows which work perfectly for horizontal and vertical arrows, but as soon the angle isn't dividable by 90deg the position is of course of.
This is based of a solution I found in SO and just added the transform. If you play around with the deg value, you can see how the base and head move around in the 2D space: /
Does anyone know a good way to calculate the "new" top and left values if the rotation is taken into account? Or maybe I just offset the position with margins if this calulation is easier.
I used to be good at math in school but that was a few decades ago.
I am currently working on a side project, where I want to "draw" diagrams. At the moment you just drag "sticky notes" to a grid, move, resize and label them. I now want to connect these notes with arrows. I got the calculations for length (pythagoras) and the angle of the line down.
calculateAngle(): number {
return Math.atan2(this._start.y - this._end.y, this._start.x - this._end.x) * 180 / Math.PI + 180;
}
calculateLength(): number {
return Math.round(Math.sqrt(Math.pow(this._start.y - this._end.y, 2) + Math.pow(this._start.x - this._end.x, 2)));
}
I also found a simple CSS solution for the arrows which work perfectly for horizontal and vertical arrows, but as soon the angle isn't dividable by 90deg the position is of course of.
This is based of a solution I found in SO and just added the transform. If you play around with the deg value, you can see how the base and head move around in the 2D space: https://jsfiddle/0r7k6L4c/
Does anyone know a good way to calculate the "new" top and left values if the rotation is taken into account? Or maybe I just offset the position with margins if this calulation is easier.
I used to be good at math in school but that was a few decades ago.
Share Improve this question asked Feb 3 at 21:43 ThomasThomas 7,1185 gold badges36 silver badges77 bronze badges 2- 1 That's a very old and obsolete way to draw triangles (and shapes in general). See this: css-shape/arrow – Temani Afif Commented Feb 3 at 21:51
- See also the answer based on SVG-defined clip path – Sergey A Kryukov Commented Feb 4 at 1:26
3 Answers
Reset to default 1You could use the newly available CSS hypot
and atan2
functions. Define the two points A, B using CSS Properties ax, ay
and bx, by
.
Make your element position fixed or absolute, set the CSS transform-origin
point to be X left Y 50%, and rotate it by atan2
radians:
.arrow {
--t: 5px; /* tail size */
position: absolute;
transform-origin: left 50%;
left: calc(var(--ax) * 1px);
top: calc(var(--ay) * 1px);
height: var(--t);
width: calc(hypot(calc(var(--by) - var(--ay)), calc(var(--bx) - var(--ax))) * 1px);
rotate: atan2(calc(var(--by) - var(--ay)), calc(var(--bx) - var(--ax)));
background: #000;
}
<div class="arrow" style="--ax:10; --ay:10; --bx:50; --by:100;"></div>
and to create the arrow shape, either use the :before
pseudo or like the following where I borrowed Temani's cool solution using clip-path:
.arrow {
--t: 5px; /* tail size */
--h: 10px; /* head size */
position: absolute;
transform-origin: left 50%;
left: calc(var(--ax) * 1px);
top: calc(var(--ay) * 1px);
height: var(--h);
width: calc(hypot(calc(var(--by) - var(--ay)), calc(var(--bx) - var(--ax))) * 1px);
rotate: atan2(calc(var(--by) - var(--ay)), calc(var(--bx) - var(--ax)));
clip-path: polygon(0 calc(50% - var(--t)/2),calc(100% - var(--h)) calc(50% - var(--t)/2),calc(100% - var(--h)) 0,100% 50%,calc(100% - var(--h)) 100%,calc(100% - var(--h)) calc(50% + var(--t)/2),0 calc(50% + var(--t)/2));
background: #000;
}
<div class="arrow" style="--ax:10; --ay:10; --bx:50; --by:100;"></div>
By default transform-origin
refers to the center. So if your original (left, top) is (100, 100) and width is 80, then center is at (100 + 80 / 2) etc.
In our example I've used 4 variables to make the point clear. The x
, y
, radius
and deg
of angle. I added also 3 pixels for the origin, the center, and the target point. The formula is simple sin
and cos
, you can look at the code.
I've also added some JS as a proof of concept.
var deg = 0
setInterval(function() {
deg += 1
document.documentElement.style.setProperty("--deg", deg + "deg")
}, 40)
:root {
--origin-x: 100px;
--origin-y: 100px;
--radius: 40px;
--deg: 45deg;
}
.arrow {
position: absolute;
left: var(--origin-x);
top: var(--origin-y);
width: calc(var(--radius) * 2);
height: 0;
border-bottom: 5px solid #000000;
transform: rotate(var(--deg));
}
.arrow::after {
content: "";
border-top: 10px solid transparent;
border-bottom: 10px solid transparent;
border-left: 20px solid #000000;
position: absolute;
right: -10px;
top: -8px;
}
.cavnas {
border: 1px solid gray;
position: relative;
width: 300px;
height: 180px;
overflow: hidden;
}
.pixel {
width: 3px;
height: 3px;
background: red;
position: absolute;
}
.pixel-origin {
left: var(--origin-x);
top: var(--origin-y);
}
.pixel-center {
left: calc(var(--origin-x) + var(--radius));
top: var(--origin-y);
}
.pixel-target {
left: calc(var(--origin-x) + var(--radius) + var(--radius) * cos(var(--deg)));
top: calc(var(--origin-y) + var(--radius) * sin(var(--deg)));
}
<div class="cavnas">
<div class="arrow"></div>
<div class="pixel pixel-origin"></div>
<div class="pixel pixel-center"></div>
<div class="pixel pixel-target"></div>
</div>
You can make it a lot simpler if you allow CSS to calculate rotation for your.
Here is the idea:
.arrow {
margin-bottom: 60px;
--t: 45%;
--h: 20%;
aspect-ratio: 10/2;
width: 100px;
background: black;
clip-path: polygon(0 calc(50% - var(--t)/2),
calc(100% - var(--h)) calc(50% - var(--t)/2),
calc(100% - var(--h)) 0, 100% 50%,
calc(100% - var(--h)) 100%,
calc(100% - var(--h)) calc(50% + var(--t)/2),
0 calc(50% + var(--t)/2));
}
.r10 { transform: rotate(10deg); }
.r45 { transform: rotate(45deg); }
.r90 { transform: rotate(90deg); }
.r135 { transform: rotate(135deg); }
.r180 { transform: rotate(180deg); }
<!DOCTYPE html>
<html>
<body>
<section class="arrow"></section>
<section class="arrow r10"></section>
<section class="arrow r45"></section>
<section class="arrow r90"></section>
<section class="arrow r135"></section>
<section class="arrow r180"></section>
</body>
</html>
Pay attention for transform: rotate()
.
The main outline is borrowed from The Ultimate Collection of CSS-only Shapes.
本文标签: javascriptCSS Arrow with any angle but fixed start and end pointStack Overflow
版权声明:本文标题:javascript - CSS Arrow with any angle but fixed start and end point - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741796268a2397955.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论