简体   繁体   English

如何绘制从角度派生的点的线?

[英]How do I draw a line to point derived from angle?

I'm writing a component (React) which draws a fancy box around a bit of text with SVG.我正在编写一个组件 (React),它使用 SVG 在一些文本周围绘制一个漂亮的框。 The component receives the width and height of the dom element and draws a polygon derived from those values.该组件接收 dom 元素的宽度和高度,并根据这些值绘制一个多边形。 Simplified example follows:简化示例如下:

import React from 'react';

const Box = ({ dimensions }) => {
  const { width, height } = dimensions;
  const mod = 10;
  const tlX = 0;
  const tlY = 0;
  const trX = tlX + width;
  const trY = tlY;
  const brX = trX;
  const brY = trY + height;
  const blX = 0;
  const blY = tlY + height;

  return (
    <picture>
      <svg height={height + 50} width={width + 200}>
        <polygon
          points={`${tlX},${tlY} ${trX},${trY} ${brX},${brY} ${blX},${blY}`}
          style={{ fill: 'black', fillOpacity: '0.5' }}
        />
      </svg>
    </picture>
  );
};

In this stripped down example the result is a rectangle with straight corners based on the width and height of the supplied dom element.在这个精简的示例中,结果是一个带有直角的矩形,基于提供的 dom 元素的宽度和高度。 In reality these values are given some random modifiers to create more of a trapezoid, as in fig A.实际上,这些值被赋予了一些随机修饰符以创建更多梯形,如图 A 所示。

Illustration of desired result所需结果的插图

In the fig B you can see my problem with this method.在图 B 中,您可以看到我使用此方法的问题。 When drawing a longer or shorter box, the figure looks squished.绘制更长或更短的框时,图形看起来被压扁了。 What I want is for the box to behave like in fig C, in that it will draw the horizontal lines at a given angle until it has reached a certain width.我想要的是让盒子表现得像图 C 一样,因为它会以给定的角度绘制水平线,直到达到一定的宽度。

From what I can intuit this should be possible with some math savvy, but I am unable to quite figuring it out on my own.从我的直觉来看,这应该可以通过一些数学知识来实现​​,但我无法自己弄清楚。

Thanks in advance for any input, and please let me know if I'm being unclear on anything.提前感谢您的任何意见,如果我有什么不清楚的地方,请告诉我。

Edit: A "trapezoid" shape is apparently not what I'm looking for.编辑: “梯形”形状显然不是我想要的。 My apologies.我很抱歉。 I just want a sort of janky rectangle.我只想要一种简陋的矩形。 I was asked to show the code I've been using in more detail.我被要求更详细地展示我一直在使用的代码。 As you will see I am basically just taking the values from the last example and messing them up a bit by adding or subtracting semi-randomly.正如您将看到的,我基本上只是从上一个示例中获取值,并通过半随机地添加或减去来将它们弄乱。

import React from 'react';
import PropTypes from 'prop-types';

function getRandomArbitrary(min, max) {
  return Math.random() * (max - min) + min;
}

const point = (core, edge) => getRandomArbitrary(core - edge, core + edge);

const Box = ({ dimensions }) => {
  const { width, height } = dimensions;
  const mod = 10;
  const tlX = point(25, mod);
  const tlY = point(40, mod);
  const trX = point(width + 55, mod);
  const trY = point(25, mod);
  const brX = point(width + 25, mod);
  const brY = point(height - 25, mod);
  const blX = point(5, mod);
  const blY = point(height - 40, mod);

  return (
    <picture>
      <svg height={height + 50} width={width + 200}>
        <polygon
          points={`${tlX},${tlY} ${trX},${trY} ${brX},${brY} ${blX},${blY}`}
          style={{ fill: 'black', fillOpacity: '0.5' }}
        />
      </svg>
    </picture>
  );
};

Box.propTypes = {
  dimensions: PropTypes.shape({
    width: PropTypes.number,
    height: PropTypes.number,
  }).isRequired,
};

export default Box;

In order to calculate the y for the top right point I'm imagining a circle with the center in the top left point.为了计算右上角的 y,我想象了一个圆心在左上角的圆。 The radius of the circle is tlX - trX , The angle is -5 degs but you can change it to what you need.圆的半径为tlX - trX ,角度为 -5 度,但您可以将其更改为您需要的值。 In order to calculate the value for the y you can do为了计算你可以做的 y 的值

const trY = tlY - (tlX - trX)*Math.sin(a1)

To calculate the y for the bottom right point I'm doing the same only this time the angle is 5 degs, the center in the bottom left point and the radius of the circle is blX - brX为了计算右下点的 y,我只是在这一次做同样的事情,角度是 5 度,左下点的中心和圆的半径是blX - brX

const brY = blY - (blX - brX)*Math.sin(a2)

The important part of the demo is this:演示的重要部分是这样的:

  //calculating the points for the polygon

  const tlX = BB.x-10;
  const tlY = BB.y-5;
  const trX = tlX + 20 + BB.width;
  //const trY = tlY - 10;
  const trY = tlY - (tlX - trX)*Math.sin(a1)
  const brX = trX - 5;

  const blX = tlX + 5;
  const blY = tlY + 10 + BB.height;

  //const brY = trY + 30+ BB.height;
  const brY = blY - (blX - brX)*Math.sin(a2)

Next comes a demo where I'm using plain javascript.接下来是我使用纯 javascript 的演示。 Please change the length of the text to see if this is what you need.请更改文本的长度,看看这是否是您需要的。

 let bb = txt.getBBox(); let m = 10; // the blue rect updateSVGelmt({x:bb.xm,y:bb.ym,width:bb.width+2*m,height:bb.height+2*m},theRect) // the bounding box of the blue rect let BB = theRect.getBBox(); //the angles for the polygon let a1 = -5*Math.PI/180; let a2 = -a1; //calculating the points for the polygon const tlX = BB.x-10; const tlY = BB.y-5; const trX = tlX + 20 + BB.width; //const trY = tlY - 10; const trY = tlY - (tlX - trX)*Math.sin(a1) const brX = trX - 5; const blX = tlX + 5; const blY = tlY + 10 + BB.height; //const brY = trY + 30+ BB.height; const brY = blY - (blX - brX)*Math.sin(a2) let points = `${tlX},${tlY} ${trX},${trY} ${brX},${brY} ${blX},${blY}`; poly.setAttributeNS(null, "points", points) let polybox = poly.getBBox(); svg.setAttributeNS(null, "viewBox", `${polybox.x-2} ${polybox.y-2} ${polybox.width+4} ${polybox.height+4}`) svg.setAttributeNS(null, "width",3*(polybox.width+4)) function updateSVGelmt(o,elmt) { for (let name in o) { if (o.hasOwnProperty(name)) { elmt.setAttributeNS(null, name, o[name]); } } }
 svg{border:1px solid}
 <svg id="svg"> <polygon id="poly" points="" style="stroke: black; fill:none" /> <rect id="theRect" fill="#d9d9ff" /> <text id="txt" text-anchor="middle">element</text> </svg>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM