我试图将此线条绘制在我的canvas
的中心,当我尝试使用moveTo(100,400)作为x轴时,它不会将水平起始位置更改为100.如果我尝试相同的事情使用y轴,它将沿x轴移动线。
我还需要帮助,沿着y轴垂直绘制y轴数字1-9,它似乎只是水平对齐。编辑!:我已经手动抚摸了y轴上的每个点,所以我在那里有数字,现在我只想知道如何将图形移动到中心!
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.linecap = 'round';
// draw a scale with the numbers on it
ctx.lineWidth = 2;
ctx.strokeStyle = '#FF9900';
ctx.fillStyle = 'blue';
ctx.beginPath();
ctx.moveTo(100, 400);
for (i = 0; i <= 6; i+=1) {
//put a stroke mark
ctx.lineTo(100*i,400);
ctx.lineTo(100*i,405); //markers
ctx.lineTo(100*i,400);
// write the number 10px below
ctx.strokeStyle = '#000000';
// default size is 10px
ctx.strokeText(i, 100*i, 415);
ctx.strokeStyle = '#FF9900';
}
// draw a vertical scale with lines on it
ctx.moveTo(0, -100);
for (b = 0; b <= 9; b+=1) {
//put a stroke mark
ctx.lineTo(0,44.5*b);
ctx.lineTo(5,44.5*b);
ctx.lineTo(0,44.5*b);
// write the number 10px below
ctx.strokeStyle = '#000000';
// default size is 10px
}
ctx.strokeStyle = '#000000'
ctx.strokeText(1, 8, 365);
ctx.strokeText(2, 8, 320.5);
ctx.strokeText(3, 8, 276);
ctx.strokeText(4, 8, 231.5);
ctx.strokeText(5, 8, 187);
ctx.strokeText(6, 8, 142.5);
ctx.strokeText(7, 8, 98);
ctx.strokeText(8, 8, 53.5);
ctx.strokeText(9, 8, 9);
ctx.strokeStyle = '#FF9900';
ctx.stroke();
<!DOCTYPE html>
<html>
<head>
<title>Canvas Axis calibration</title>
<link rel="stylesheet" type="text/css" href="base.css"/>
</head>
<body>
<canvas id="myCanvas" width="1600" height="500"style="border:1px solid #c3c3c3;">
Canvas is not playing!
</canvas>
</body>
</html>
moveTo()只是设置你的线的起点,它不是绘制实际线。使用lineTo()绘制实际行。所以moveTo()来自或开始的地方,而lineTo()就是你去的地方。因此x轴的起点必须为moveTo(800,0)。
var c = document.getElementById("myCanvas"),
ctx = c.getContext("2d"),
lineWidth = 2,
xNumber = 6,
yNumber = 9,
xCenter = c.width / 2,
yCenter = 44.5 * yNumber + 44.5
ctx.linecap = 'round';
// draw a scale with the numbers on it
ctx.lineWidth = lineWidth;
ctx.strokeStyle = '#FF9900';
ctx.fillStyle = 'blue';
ctx.beginPath();
ctx.moveTo(xCenter, yCenter);
for (i = 0; i <= xNumber; ++i) {
//put a stroke mark
ctx.lineTo((xCenter + (100 * i)), yCenter);
ctx.lineTo((xCenter + (100 * i)), (yCenter + 5)); //markers
ctx.lineTo((xCenter + (100 * i)), yCenter);
// write the number 10px below
ctx.strokeStyle = '#000000';
// default size is 10px
ctx.strokeText(i, (xCenter + (100 * i)), (yCenter + 15));
}
ctx.strokeStyle = '#FF9900';
ctx.stroke()
// draw a vertical scale with lines on it
ctx.beginPath()
ctx.moveTo(xCenter, yCenter);
for (b = 0; b <= yNumber; ++b) {
//put a stroke mark
if(b === 0) continue;
ctx.lineTo(xCenter, (yCenter - (44.5 * b)));
ctx.lineTo((xCenter - 5), (yCenter - (44.5 * b)));
ctx.lineTo(xCenter, (yCenter - (44.5 * b)));
ctx.strokeStyle = '#000000';
ctx.strokeText(b, (xCenter - 15), (yCenter - (44.5 * b)));
}
ctx.strokeStyle = '#FF9900';
ctx.stroke();
<!DOCTYPE html>
<html>
<head>
<title>Canvas Axis calibration</title>
<link rel="stylesheet" type="text/css" href="base.css"/>
</head>
<body>
<canvas id="myCanvas" width="1600" height="500"style="border:1px solid #c3c3c3;">
Canvas is not playing!
</canvas>
</body>
</html>
CanvasRenderingContext2D
有一个方法:translate()
。它只是设置一个坐标移位,它将应用于您之后绘制的所有内容:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.linecap = 'round';
ctx.lineWidth = 2;
ctx.fillStyle = 'blue';
ctx.translate((1600-500)/2,0); // <-----------
ctx.strokeStyle = '#000000';
ctx.beginPath();
ctx.moveTo(100, 400);
for (var i = 0; i <= 6; i+=1) {
ctx.lineTo(100*i,400);
ctx.lineTo(100*i,405);
ctx.lineTo(100*i,400);
ctx.strokeText(i, 100*i, 415);
}
ctx.moveTo(0, -100);
for (var b = 0; b <= 9; b+=1) {
ctx.lineTo(0,44.5*b);
ctx.lineTo(5,44.5*b);
ctx.lineTo(0,44.5*b);
if(b<9)
ctx.strokeText(b+1, 8, 365-44.5*b);
}
ctx.strokeStyle = '#FF9900';
ctx.stroke();
<!DOCTYPE html>
<html>
<head>
<title>Canvas Axis calibration</title>
<link rel="stylesheet" type="text/css" href="base.css"/>
</head>
<body>
<canvas id="myCanvas" width="1600" height="500"style="border:1px solid #c3c3c3;">Canvas is not playing!</canvas>
</body>
</html>
在这里,我假设绘图是500单位宽,这似乎并不完全正确,但你肯定会看到translate()
的结果。可以使用translate()
调用重置setTransform(1, 0, 0, 1, 0, 0)
的效果(如果您熟悉齐次坐标和变换矩阵,请注意它有一个严格修改的顺序,请参阅文档)。它实际上是一个可以进行各种2D变换(平移,旋转,缩放,倾斜)的矩阵,translate()
只是一个便利函数(相当于调用probaby将是setTransform(1,0,0,1,(1600-500)/2,0)
,但我还没试过)。
细微变化:
var
-s添加到循环中:否则变量变为全局变量,这对于像i
这样的循环变量通常不是问题,但通常被认为是不好的做法stroke()
和两个strokeStyle
-s。事情就是用你在调用stroke()
的那一刻设置的设置绘制线条,弧线等,它们之间发生了什么并不重要。所以颜色在大多数时候是黑色的,因为strokeText()
是即时的,颜色变成米色/任何一个只是为了stroke()
当你得到一个建筑计划时,你没有得到一张巨大的纸张,因为你正在建造在burbs中,你想要在夏日阳光下移动一些窗户,你不要重绘计划每个墙的新坐标。
没有你得到适合小张的计划,计划是一个位置和方向。墙的位置固定在计划的当地坐标上。
2D绘图也是如此。您可以将框定义为原点周围的4个点。 [[-10,-10],[10,-10],[10,10],[-10,10]]
,当你绘制它时,你设置它的位置和方向,你不要改变每个点到新位置的位置。
在2D API中,通过变换设置位置和方向。
function drawPath(x,y, points) { // only position changes
ctx.setTransform(1,0,0,1,x,y); // set the location
ctx.beginPath();
for(const [x,y] of points) {
ctx.lineTo(x,y);
}
ctx.stroke();
}
const box = [[-10,-10],[10,-10],[10,10],[-10,10]];
drawPath(100, 100, box);
并具有刻度和旋转功能
function drawPath(x,y,scale, rotate, points) {
const xdx = Math.cos(rotate) * scale;
const xdy = Math.sin(rotate) * scale;
ctx.setTransform(xdx, xdy, -xdy, xdx, x, y); // set the location
ctx.beginPath();
for(const [x,y] of points) {
ctx.lineTo(x,y);
}
ctx.stroke();
}
drawPath(100, 100, 2, 0.5, box);
const box = [[-10,-10],[10,-10],[10,10],[-10,10]];
const W = canvas.width;
const H = canvas.height;
const ctx = canvas.getContext("2d");
ctx.font = "2opx arial";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillStyle = "red";
const rand = v => Math.random() * v;
drawRandom();
function drawPath(x, y,scale, rotate, points) {
const xdx = Math.cos(rotate) * scale;
const xdy = Math.sin(rotate) * scale;
ctx.setTransform(xdx, xdy, -xdy, xdx, x, y); // set the location
ctx.fillText("Hi",0,0);
ctx.beginPath();
for(const [x,y] of points) {
ctx.lineTo(x, y);
}
ctx.closePath();
ctx.setTransform(1, 0, 0, 1, 0, 0); // Resets so line width remains 1 px
ctx.stroke();
}
function drawRandom() {
drawPath(rand(W), rand(H), rand(2) + 0.5, rand(Math.PI * 2), box);
setTimeout(drawRandom, 500);
}
canvas {
border: 1px solid black;
}
<canvas id="canvas" width ="400" height="400"></canvas>
所有你需要的是ctx.setTransform
,也许ctx.transform
,如果你正在做装配动画的东西。我从来没有使用ctx.translate
,ctx.scale
,ctx.rotate
,因为它们很慢,很难想象你的位置,哦,我说它们很慢!
要重置变换(删除比例,旋转并移回0,0),请调用ctx.resetTransform()
或ctx.setTransform(1,0,0,1,0,0)
还有一些关于你的代码方法。
看起来你想画一个图。
手动绘制每个刻度,设置样式和数十个幻数和值都不会让它变得有趣。更糟糕的是,当需要进行更改时,它将需要永远。
你需要像懒惰的程序员一样思考。创建函数,这样你就不必一遍又一遍地做同样的事情。
例如,设置2D上下文样式很痛苦。绘图通常只有几种不同的样式,因此创建一个具有命名样式的对象
const styles = {
textHang: {
textAlign : "center",
textBaseline : "top",
fillStyle: "blue",
font: "16px Arial",
},
};
并且将设置样式的功能
const setStyle = (style, c = ctx) => Object.assign(c, style);
现在你可以设置一种风格
const ctx = myCanvas.getContext("2d");
setStyle(styles, styles.textHang);
ctx.fillText("The text", 100, 100);
你正在2D和2D工作使用很多点。您将一遍又一遍地添加乘法,复制...... 2D点。
只需7个功能即可减少打字并满足最基本的2D需求
const P2 = (x = 0, y = 0) => ({x,y});
const P2Set = (p, pAs) => (p.x = pAs.x, p.y = pAs.y, p);
const P2Copy = p => P2(p.x, p.y);
const P2Mult = (p, val) => (p.x *= val, p.y *= val, p);
const P2Add = (p, pAdd) => (p.x += pAdd.x, p.y += pAdd.y, p);
const P2Sub = (p, pSub) => (p.x -= pSub.x, p.y -= pSub.y, p);
const P2Dist = (p1, p2) => ((p1.x - p2.x) ** 2 + (p1.y - p2.y) ** 2) ** 0.5;
2D API很棒,但缺乏。只画一条线很疯狂,foo吧....
ctx.linecap = 'round';
ctx.lineWidth = 2;
ctx.strokeStyle = '#FF9900';
ctx.beginPath();
ctx.moveTo(10, 10);
ctx.lineTo(410, 410);
ctx.stroke();
无法创建函数,使用命名样式,不输入坐标使用点。
一些常见的2D任务作为函数
const clear = (c = ctx) => (setPos(), c.clearRect(0,0,c.canvas.width,c.canvas.height));
const line = (p1, p2, c = ctx) => (c.moveTo(p1.x, p1.y), c.lineTo(p2.x, p2.y))
const setPos = (p, c = ctx) => p ? c.setTransform(1, 0, 0, 1, p.x, p.y) : c.resetTransform();
const path = (p, path, c = ctx) => {
c.setTransform(1,0,0,1,p.x,p.y);
for(const seg of path) { // each segment
let first = true;
for(const p of seg) { // each point
first ? (c.moveTo(p.x,p.y), first = false):(c.lineTo(p.x, p.y));
}
}
}
以下所有内容将创建2轴。它可能看起来更多,但随着您的绘图增加复杂性,您很快就会发现您需要的代码越来越少。
/* Set up the context get common values eg W,H for width and height */
const W = canvas.width;
const H = canvas.height;
const ctx = canvas.getContext("2d");
// Helper functions will use a global ctx, or pass a 2d context as last argument
// P2 is a point. I use p to mean a point
const P2 = (x = 0, y = 0) => ({x,y});
const P2Set = (p, pAs) => (p.x = pAs.x, p.y = pAs.y, p);
const P2Copy = p => P2(p.x, p.y);
const P2Mult = (p, val) => (p.x *= val, p.y *= val, p);
const P2Add = (p, pAdd) => (p.x += pAdd.x, p.y += pAdd.y, p);
const P2Sub = (p, pSub) => (p.x -= pSub.x, p.y -= pSub.y, p);
const P2Dist = (p1, p2) => ((p1.x - p2.x) ** 2 + (p1.y - p2.y) ** 2) ** 0.5;
const setStyle = (style, c = ctx) => Object.assign(c, style);
const clear = (c = ctx) => (setPos(0, c), c.clearRect(0,0,c.canvas.width,c.canvas.height));
const line = (p1, p2, c = ctx) => (c.moveTo(p1.x, p1.y), c.lineTo(p2.x, p2.y))
const setPos = (p, c = ctx) => p ? c.setTransform(1, 0, 0, 1, p.x, p.y) : c.resetTransform();
const path = (p, path, c = ctx) => {
setPos(p,c);
for(const seg of path) { // each segment
let first = true;
for(const p of seg) { // each point
first ? (c.moveTo(p.x,p.y), first = false):(c.lineTo(p.x, p.y));
}
}
}
const styles = { // define any of the 2D context properties you wish to set
textHang: {textAlign : "center", textBaseline : "top"},
textLeft: {textAlign : "left", textBaseline : "middle"},
markTextStyle: {fillStyle: "blue", font: "16px Arial"},
markStyle: {
strokeStyle: "black",
lineCap: "round",
lineWidth: 2,
},
};
const paths = { // Array of arrays of points. each sub array is a line segment
markLeft: [[P2(-2, 0), P2(5, 0)]],
markUp: [[P2(0, 2), P2(0, -5)]],
}
// Draw an axis from point to point, using mark to mark, lineStyle for the line
// marks is an array of names for each mark, markStyle is the style for the text marks
// markDist is the distance out (90 to the right) to put the text marks
function drawAxis(fromP, toP, mark, lineStyle, marks, markStyle, markDist) {
const norm = P2Mult(P2Sub(P2Copy(toP), fromP), 1 / P2Dist(fromP, toP));
const step = P2Mult(P2Sub(P2Copy(toP), fromP), 1 / (marks.length-1));
const pos = P2Copy(fromP);
setStyle(lineStyle);
ctx.beginPath();
setPos(); // without argument pos is 0,0
line(fromP, toP);
for(const m of marks) {
path(pos, mark);
P2Add(pos, step);
}
ctx.stroke();
P2Set(pos, fromP);
setStyle(markStyle);
for(const m of marks) {
setPos(pos);
ctx.fillText(m,-norm.y * markDist, norm.x * markDist)
P2Add(pos, step)
}
}
const insetW = W * 0.1;
const insetH = H * 0.1;
const axisText = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"];
clear();
drawAxis(
P2(insetW, H - insetH), P2(insetW, insetH), paths.markLeft,
styles.markStyle,
axisText,
{...styles.textLeft, ...styles.markTextStyle},
-18
);
drawAxis(
P2(insetW, H - insetH), P2(W - insetW, H - insetH), paths.markUp,
styles.markStyle,
axisText,
{...styles.textHang, ...styles.markTextStyle},
6
);
canvas {
border: 1px solid black;
}
<canvas id="canvas" width ="400" height="400"></canvas>