是否有可能在HTML5画布的路径上绘制图像
Is it possible to draw an image on a path in HTML5 canvas?
例如,假设我有以下路径:
<canvas id="main" width="500" height="250"></canvas>
var canvas = document.getElementById("main");
var ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.moveTo(20,20);
ctx.lineTo(100,20);
ctx.arcTo(150,20,150,70,50);
ctx.lineTo(150,120);
ctx.lineWidth = 3;
ctx.stroke();
可以在直线的圆弧上画图像吗?如果有,是怎么做到的?
将图像切片以绘制在曲线上。
是的,这是可能的,虽然理想情况下这将是WebGL的工作。下一个最好的解决方案是扫描线渲染,但这对可怜的Javascript来说是一种很大的CPU负载管理方式。
下一个最好的我的意思是"OK sort of."选项是一点图像切片。
您只需在圆弧周围绘制图像的薄片。2D渲染器并不完美,并试图尽可能地绘制半像素。结果是在每个切片的边缘都有一些噪点,在那里你可以看到。为了克服这个问题,我把每一片画得稍微宽一点,以掩盖任何洞。
如果你需要高质量,在屏幕外画布上以两倍的大小渲染,然后缩小到屏幕上的画布(不要忘记平滑),会让大多数人认为它是那样绘制的。
由于圆弧的内外边缘具有不同的周长,因此必须压缩或拉伸图像的某些部分。在演示中,我将图像的内边缘保持在正确的宽度,并拉伸外边缘。这很容易改变,但要确保使用外缘来锻炼要绘制多少片。
WARNING给出的半径是内边。它被检查以防止for循环变得太长而阻塞页面。您可能想要限制半径,使内周长与图像宽度相同。radius = radius < img.width / (Math.PI * 2) ? img.width / (Math.PI * 2) : radius;
很容易适应线条和曲线。所有你需要的是切线或曲线法线(应该是单位向量即长度1)使用这个向量来设置变换ctx.setTransform(nx,ny,tx,ty,px,py)
。前两个值从图像的底部指向顶部,接下来的两个数字沿着从左到右的切线。最后两个点是曲线上用来绘制切片的点。
// creates a blank image with 2d context
var createImage=function(w,h){var i=document.createElement("canvas");i.width=w;i.height=h;i.ctx=i.getContext("2d");return i;}
// create a canvas and add to dom
var can = createImage(512,512);
document.body.appendChild(can);
var ctx = can.ctx;
// create a image (canvas) to draw on the arc.
const textToDisplay = "<<Image on arc>>"
ctx.font = "64px arial";
var w = ctx.measureText(textToDisplay).width + 8;
var text = createImage(w + 64,84);
text.ctx.fillStyle = "#F90";
text.ctx.strokeStyle = "black";
text.ctx.lineWidth = 16;
text.ctx.fillRect(0,0,text.width,text.height);
text.ctx.strokeRect(0,0,text.width,text.height);
text.ctx.font = "64px arial";
text.ctx.fillStyle = "#0F0";
text.ctx.strokeStyle = "Black";
text.ctx.lineWidth = 4;
text.ctx.strokeText(textToDisplay,38,58);
text.ctx.fillText(textToDisplay,38,58);
// draws image on arc
// img image to render
// x,y center of arc
// radius the inner edge (bottom of image) radius
// fromAng The angle to start drawing the image in radians
// toAng (optional if not given image width will be used to get toAng)
// returns undefined
function drawArcImage(img,x,y,radius,fromAng,toAng){
// WARNING if you let the radius get to small the ratio between the inner and out circumference
// gets very large. This will result in the image being stretched over a quintabazzilon pixels.
// so must vet the radius or you will block the page and upset the browser gods.
radius = Math.abs(radius); // only positive
radius = radius < img.height / 8 ? img.height / 8 : radius;
var outRad = radius + img.height;
var cir = Math.PI * 2 * radius; // get inner circumference
if(toAng === undefined){
var toAng = (img.width / cir) * Math.PI * 2 ; // get the angle the image will cover
}
var cirOut = toAng * outRad; // get the out edge distance in pixels
var imgStep = img.width / cirOut; // the image step per slice
var imgX = 0; // track the image line to draw
var angStep = toAng / cirOut; // the angle steps
// For each pixel on the out edge draw a slice
for(var i = 0; i < toAng; i += angStep){
var dx = Math.cos(fromAng + i);
var dy = Math.sin(fromAng + i);
// set up the transform to draw a slice from the inner to outer edges
ctx.setTransform(dy,-dx,-dx,-dy,dx * radius + x,dy * radius + y);
// get and draw the slice. I stretch it a little (2pix) to cover imperfect rendering
ctx.drawImage(img,imgX,0,imgStep,img.height,-1,-img.height,2,img.height);
// move to next slice
imgX += imgStep;
}
ctx.setTransform(1,0,0,1,0,0); // reset the transform
}
// animate the image to prove it is real.. LOL
var animTick = 0;
var animRate = 0.01;
var pos = 0;
// update function call via RAF
function update(){
animTick += animRate; // update tick
// random anim sin waves.
var rad = Math.sin(animTick) * (256-text.height - 20) + 20;
pos += Math.sin(animTick*10) * 0.02;
pos += Math.sin(animTick/ 3) * 0.02;
pos += Math.sin(animTick/ 7) * 0.05;
// clear
ctx.clearRect(0,0,can.width,can.height)
// draw
drawArcImage(text,256,256,rad,pos)
// do again and again and again
requestAnimationFrame(update);
}
update();
这是一个类似问题的答案:
你可以在draw循环中实现一个"线条绘制算法",它不精确地绘制一条线,而是在该点所在的位置绘制一个项目。不过,将此处的直线算法替换为绘制圆弧。
function line(x0, y0, x1, y1){
var dx = Math.abs(x1-x0);
var dy = Math.abs(y1-y0);
var sx = (x0 < x1) ? 1 : -1;
var sy = (y0 < y1) ? 1 : -1;
var err = dx-dy;
while(true){ // put draw loop here.
drawImage(image,x0,y0);//setPixel(x0,y0); // Do what you need to for this
if ((x0==x1) && (y0==y1)) break;
var e2 = 2*err;
if (e2 >-dy){ err -= dy; x0 += sx; }
if (e2 < dx){ err += dx; y0 += sy; }
}
}
代码取自:Javascript中的Bresenham算法
我建议使用像p5.js这样的库来做这样的事情。http://p5js.org
- 使用onclick绘制SVG路径
- Html5-使用SVG路径绘制的组织层次结构在左手边被剪裁
- 使用javascript中的for循环在画布上绘制路径
- 绘制动画openlayers线条字符串路径
- 在html画布中绘制更平滑的路径
- 我无法使用 gmaps.js 绘制路径
- 如何在拉斐尔中删除我可能想要在两秒钟后重新绘制的路径
- 绘制 SVG 拉斐尔路径会出错并且不接受变量
- Javascript:如何确定SVG路径绘制方向
- JavaScript - 有没有办法在内容下绘制SVG路径
- 如何更改拉斐尔 JS 绘制的路径宽度和高度
- 从 GPS 捕捉到道路的 GEO 位置绘制路径
- 谷歌地图API - 在数组中使用Lat Lng坐标绘制折线飞行路径
- Javascript HTML5 Canvas 绘制路径问题
- 在HTML5中绘制路径,然后绘制图像
- 填充路径取决于绘制顺序
- 使用 jQuery SVG 绘制外部 svg 路径
- SVG路径绘制和擦除动画
- 路径绘制与d3
- SVG路径绘制和图像填充