var canvas = this.__canvas = new fabric.Canvas('canvas');
var canvas_objects = canvas._objects;
// create a rectangle with a fill and a different color stroke
var left = 150;
var top = 150;
var x=20;
var y=40;
var rect = new fabric.Rect({
left: left,
top: top,
width: x,
height: y,
angle:45,
fill: 'rgba(255,127,39,1)',
stroke: 'rgba(34,177,76,1)',
strokeWidth:0,
originX:'right',
originY:'top',
centeredRotation: false
});
canvas.add(rect);
for(var i=0;i<15;i++){
var rectangle = fabric.util.object.clone(getLastobject());
if(i%2==0){
rectangle.left = rectangle.oCoords.tr.x;
rectangle.top = rectangle.oCoords.tr.y;
rectangle.originX='right';
rectangle.originY='top';
rectangle.angle =-45;
}else{
fabric.log('rectangle: ', rectangle.toJSON());
rectangle.left = rectangle.oCoords.tl.x;
rectangle.top = rectangle.oCoords.tl.y;
fabric.log('rectangle: ', rectangle.toJSON());
rectangle.originX='left';
rectangle.originY='top';
rectangle.angle =45;
}
//rectangle.angle -90;
canvas.add(rectangle);
}
fabric.log('rectangle: ', canvas.toJSON());
canvas.renderAll();
function getLastobject(){
var last = null;
if(canvas_objects.length !== 0){
last = canvas_objects[canvas_objects.length -1]; //Get last object
}
return last;
}
如何使用svg或2d,3d方法在画布中绘制此模式。如果有任何第三方库也对我有好处。
我不知道从哪里开始以及如何绘制这种复杂的模式。
有人请帮我在画布上用动态颜色的矩形填充绘制这个图案。
这是我需要的示例输出。 herringbone pattern
我使用fabric.js库尝试了类似的东西,这里是我的JSFiddle
答案 0 :(得分:4)
要获得图案,您需要绘制矩形,每个水平平铺一个空格,每行向左或向右,垂直矩形相同。
矩形的宽度为2时间高度。
绘制图案很简单。
旋转很容易,更难的部分是找到绘制旋转瓷砖的位置。
为此,我创建了一个旋转的逆矩阵(它反转了一个旋转)。然后我将旋转应用到画布的{4}角,0,0
width,0
和width,height
,这使我在旋转空间中的4个点位于画布。
当我从左到右从上到下绘制瓷砖时,我发现左上角的最小角落,右下角的最大角落,将其展开一点,所以我不会错过任何像素并绘制瓷砖转换设置了旋转。
由于我无法锻炼你想要的角度,它会在任何角度绘制它。 On动画,另一个是顺时针60deg。
更新闪光就是在那里,所以做了一些改变,现在颜色是一个更令人愉悦的混合,并具有固定的绝对位置,并已将瓷砖原点绑定到鼠标位置,单击鼠标按钮也会循环显示某些尺寸。
0,height
&#13;
const ctx = canvas.getContext("2d");
const colours = []
for(let i = 0; i < 1; i += 1/80){
colours.push(`hsl(${Math.floor(i * 360)},${Math.floor((Math.sin(i * Math.PI *4)+1) * 50)}%,${Math.floor(Math.sin(i * Math.PI *8)* 25 + 50)}%)`)
}
const sizes = [0.04,0.08,0.1,0.2];
var currentSize = 0;
const origin = {x : canvas.width / 2, y : canvas.height / 2};
var size = Math.min(canvas.width * 0.2, canvas.height * 0.2);
function drawPattern(size,origin,ang){
const xAx = Math.cos(ang); // define the direction of xAxis
const xAy = Math.sin(ang);
ctx.setTransform(1,0,0,1,0,0);
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.setTransform(xAx,xAy,-xAy,xAx,origin.x,origin.y);
function getExtent(xAx,xAy,origin){
const im = [1,0,0,1]; // inverse matrix
const dot = xAx * xAx + xAy * xAy;
im[0] = xAx / dot;
im[1] = -xAy / dot;
im[2] = xAy / dot;
im[3] = xAx / dot;
const toWorld = (x,y) => {
var point = {};
var xx = x - origin.x;
var yy = y - origin.y;
point.x = xx * im[0] + yy * im[2];
point.y = xx * im[1] + yy * im[3];
return point;
}
return [
toWorld(0,0),
toWorld(canvas.width,0),
toWorld(canvas.width,canvas.height),
toWorld(0,canvas.height),
]
}
const corners = getExtent(xAx,xAy,origin);
var startX = Math.min(corners[0].x,corners[1].x,corners[2].x,corners[3].x);
var endX = Math.max(corners[0].x,corners[1].x,corners[2].x,corners[3].x);
var startY = Math.min(corners[0].y,corners[1].y,corners[2].y,corners[3].y);
var endY = Math.max(corners[0].y,corners[1].y,corners[2].y,corners[3].y);
startX = Math.floor(startX / size) - 2;
endX = Math.floor(endX / size) + 2;
startY = Math.floor(startY / size) - 2;
endY = Math.floor(endY / size) + 2;
// draw the pattern
ctx.lineWidth = size * 0.1;
ctx.lineJoin = "round";
ctx.strokeStyle = "black";
var colourIndex = 0;
for(var y = startY; y <endY; y+=1){
for(var x = startX; x <endX; x+=1){
if((x + y) % 4 === 0){
colourIndex = Math.floor(Math.abs(Math.sin(x)*size + Math.sin(y) * 20));
ctx.fillStyle = colours[(colourIndex++)% colours.length];
ctx.fillRect(x * size,y * size,size * 2,size);
ctx.strokeRect(x * size,y * size,size * 2,size);
x += 2;
ctx.fillStyle = colours[(colourIndex++)% colours.length];
ctx.fillRect(x * size,y * size, size, size * 2);
ctx.strokeRect(x * size,y * size, size, size * 2);
x += 1;
}
}
}
}
// Animate it all
var update = true; // flag to indecate something needs updating
function mainLoop(time){
// if window size has changed update canvas to new size
if(canvas.width !== innerWidth || canvas.height !== innerHeight || update){
canvas.width = innerWidth;
canvas.height = innerHeight
origin.x = canvas.width / 2;
origin.y = canvas.height / 2;
size = Math.min(canvas.width, canvas.height) * sizes[currentSize % sizes.length];
update = false;
}
if(mouse.buttonRaw !== 0){
mouse.buttonRaw = 0;
currentSize += 1;
update = true;
}
// draw the patter
drawPattern(size,mouse,time/2000);
requestAnimationFrame(mainLoop);
}
requestAnimationFrame(mainLoop);
mouse = (function () {
function preventDefault(e) { e.preventDefault() }
var m; // alias for mouse
var mouse = {
x : 0, y : 0, // mouse position
buttonRaw : 0,
over : false, // true if mouse over the element
buttonOnMasks : [0b1, 0b10, 0b100], // mouse button on masks
buttonOffMasks : [0b110, 0b101, 0b011], // mouse button off masks
bounds : null,
eventNames : "mousemove,mousedown,mouseup,mouseout,mouseover".split(","),
event(e) {
var t = e.type;
m.bounds = m.element.getBoundingClientRect();
m.x = e.pageX - m.bounds.left - scrollX;
m.y = e.pageY - m.bounds.top - scrollY;
if (t === "mousedown") { m.buttonRaw |= m.buttonOnMasks[e.which - 1] }
else if (t === "mouseup") { m.buttonRaw &= m.buttonOffMasks[e.which - 1] }
else if (t === "mouseout") { m.over = false }
else if (t === "mouseover") { m.over = true }
e.preventDefault();
},
start(element) {
if (m.element !== undefined) { m.remove() }
m.element = element === undefined ? document : element;
m.eventNames.forEach(name => document.addEventListener(name, mouse.event) );
document.addEventListener("contextmenu", preventDefault, false);
},
}
m = mouse;
return mouse;
})();
mouse.start(canvas);
&#13;
canvas {
position : absolute;
top : 0px;
left : 0px;
}
&#13;
<canvas id=canvas></canvas>
&#13;
const ctx = canvas.getContext("2d");
const colours = ["red","green","yellow","orange","blue","cyan","magenta"]
const origin = {x : canvas.width / 2, y : canvas.height / 2};
var size = Math.min(canvas.width * 0.2, canvas.height * 0.2);
function drawPattern(size,origin,ang){
const xAx = Math.cos(ang); // define the direction of xAxis
const xAy = Math.sin(ang);
ctx.setTransform(1,0,0,1,0,0);
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.setTransform(xAx,xAy,-xAy,xAx,origin.x,origin.y);
function getExtent(xAx,xAy,origin){
const im = [1,0,0,1]; // inverse matrix
const dot = xAx * xAx + xAy * xAy;
im[0] = xAx / dot;
im[1] = -xAy / dot;
im[2] = xAy / dot;
im[3] = xAx / dot;
const toWorld = (x,y) => {
var point = {};
var xx = x - origin.x;
var yy = y - origin.y;
point.x = xx * im[0] + yy * im[2];
point.y = xx * im[1] + yy * im[3];
return point;
}
return [
toWorld(0,0),
toWorld(canvas.width,0),
toWorld(canvas.width,canvas.height),
toWorld(0,canvas.height),
]
}
const corners = getExtent(xAx,xAy,origin);
var startX = Math.min(corners[0].x,corners[1].x,corners[2].x,corners[3].x);
var endX = Math.max(corners[0].x,corners[1].x,corners[2].x,corners[3].x);
var startY = Math.min(corners[0].y,corners[1].y,corners[2].y,corners[3].y);
var endY = Math.max(corners[0].y,corners[1].y,corners[2].y,corners[3].y);
startX = Math.floor(startX / size) - 4;
endX = Math.floor(endX / size) + 4;
startY = Math.floor(startY / size) - 4;
endY = Math.floor(endY / size) + 4;
// draw the pattern
ctx.lineWidth = 5;
ctx.lineJoin = "round";
ctx.strokeStyle = "black";
for(var y = startY; y <endY; y+=1){
for(var x = startX; x <endX; x+=1){
ctx.fillStyle = colours[Math.floor(Math.random() * colours.length)];
if((x + y) % 4 === 0){
ctx.fillRect(x * size,y * size,size * 2,size);
ctx.strokeRect(x * size,y * size,size * 2,size);
x += 2;
ctx.fillStyle = colours[Math.floor(Math.random() * colours.length)];
ctx.fillRect(x * size,y * size, size, size * 2);
ctx.strokeRect(x * size,y * size, size, size * 2);
x += 1;
}
}
}
}
canvas.width = innerWidth;
canvas.height = innerHeight
origin.x = canvas.width / 2;
origin.y = canvas.height / 2;
size = Math.min(canvas.width * 0.2, canvas.height * 0.2);
drawPattern(size,origin,Math.PI / 3);
&#13;
canvas {
position : absolute;
top : 0px;
left : 0px;
}
&#13;
答案 1 :(得分:1)
解决这个问题的最佳方法是检查模式并分析其对称性及其重复方式。
你可以看几种方法。例如,您可以将图案旋转45度,使得图块是平直的正交矩形。但是,让我们看看它是怎么回事。我将假设您对45度瓷砖感到满意。
与瓷砖本身一样,事实证明该图案的比例为2:1。如果我们水平和垂直地重复这个模式,我们可以用完整的模式填充画布。
我们可以看到有五个图块与我们的图案块重叠。但是,当我们绘制每个模式块时,我们不需要全部绘制它们。我们可以利用块重复的事实,我们可以将一些块的绘制留给以后的行和列。
假设我们正在从左到右,从上到下绘制图案块。我们需要绘制哪些图块,至少要确保完全绘制此图案块(考虑到相邻的图案块)?
由于我们将从左上角(向右和向下移动)开始,我们需要绘制第2块。这是因为该块不会被块块绘制在我们之下,或在我们右边的街区。这同样适用于图块3。 事实证明,这两个是我们需要为每个模式块绘制的。当我们下面的图案块分别绘制它们的图块2和3时,将绘制图块1和图4。当我们东南方的图案块绘制瓷砖1时,将绘制图块。
我们只需要记住,我们可能需要在右侧绘制一个额外的列,并在底部绘制,以确保完全绘制行尾和模式块。< / p>
要解决的最后一件事是我们的模式块有多大。
让我们调用图块a
和长边b
的短边。我们知道b = 2 * a
。我们可以使用毕达哥拉斯定理得出模式块的高度为:
h = sqrt(a^2 + a^2)
= sqrt(2 * a^2)
= sqrt(2) * a
我们可以看到的模式块的宽度为w = 2 * h
。
现在我们已经研究了如何绘制模式,让我们实现我们的算法。
const a = 60;
const b = 120;
const h = 50 * Math.sqrt(2);
const w = h * 2;
const h2 = h / 2; // How far tile 1 sticks out to the left of the pattern block
// Set of colours for the tiles
const colours = ["red","cornsilk","black","limegreen","deepskyblue",
"mediumorchid", "lightgrey", "grey"]
const canvas = document.getElementById("herringbone");
const ctx = canvas.getContext("2d");
// Set a universal stroke colour and width
ctx.strokeStyle = "black";
ctx.lineWidth = 4;
// Loop through the pattern block rows
for (var y=0; y < (canvas.height + h); y+=h)
{
// Loop through the pattern block columns
for (var x=0; x < (canvas.width + w); x+=w)
{
// Draw tile "2"
// I'm just going to draw a path for simplicity, rather than
// worrying about drawing a rectangle with rotation and translates
ctx.beginPath();
ctx.moveTo(x - h2, y - h2);
ctx.lineTo(x, y - h);
ctx.lineTo(x + h, y);
ctx.lineTo(x + h2, y + h2);
ctx.closePath();
ctx.fillStyle = colours[Math.floor(Math.random() * colours.length)];
ctx.fill();
ctx.stroke();
// Draw tile "3"
ctx.beginPath();
ctx.moveTo(x + h2, y + h2);
ctx.lineTo(x + w - h2, y - h2);
ctx.lineTo(x + w, y);
ctx.lineTo(x + h, y + h);
ctx.closePath();
ctx.fillStyle = colours[Math.floor(Math.random() * colours.length)];
ctx.fill();
ctx.stroke();
}
}
&#13;
<canvas id="herringbone" width="500" height="400"></canvas>
&#13;