gpt4 book ai didi

javascript - 在 HTML5 Canvas 中实现画笔厚度变化(示例想要在内部模拟)

转载 作者:行者123 更新时间:2023-11-28 18:48:57 24 4
gpt4 key购买 nike

我希望在下面的演示中指出算法方面的正确方向 http://sta.sh/muro/。还有它正在使用的 Canvas 工具 - 即它是绘制线条还是绘制许多弧线等

具体来说,我想模拟画笔转动,这会导致整个“画笔笔触”更粗。请参阅图像以了解我要模拟的画笔设置。

最终,我希望创建一个在转动时厚度会变化的画笔,就像下面的行为一样。

enter image description here

最佳答案

为此,您需要记录按下按钮时的鼠标点。然后,您需要检查每个线段以找到方向、线的长度以及该线段的归一化向量,以便您可以对鼠标样本进行过采样。

因此,如果您有一组从鼠标获取的点,则以下内容将获得所需的详细信息。

    for(var i = 0; i < len-1; i++){
var p1 = line[i];
var p2 = line[i+1];
var nx = p2.x - p1.x;
var ny = p2.y - p1.y;
p1.dir = ((Math.atan2(ny,nx)%PI2)+PI2)%PI2; // get direction
p1.len = Math.hypot(nx,ny); // get length
p1.nx = nx/p1.len; // get normalised vector
p1.ny = ny/p1.len;
}

一旦掌握了每条线段的详细信息,根据值更改绘图参数就很简单了。

我添加了一个演示。它与我可能会费心去了解示例一样接近,因为您提供的行没有提供绘制图像所显示内容的选项。该图像显示他们也使用阴影并进行子小鼠样本采样。他们绘制的圆形框可能是一个图像,比我绘制的框要快得多。我还对线条进行了一些平滑处理,因此绘图与最终确定并设置为背景图像之间存在一点滞后。

演示的顶部是一组控制各种设置的常量。添加输入选项和审查会花费太多时间,因此如果您发现代码有用,请使用它们。

抱歉,代码很困惑,但这只是一个示例,您必须自己将其拆开。

/** hypot.js begin **/
// ES6 new math function hypot. Sqrt of the sum of the squares
var hypot = Math.hypot;
if(typeof hypot === 'undefined'){
hypot = function(x,y){
return Math.sqrt(Math.pow(x,2)+Math.pow(y,2));
}
}

/** hypot.js end **/

// draw options
const SUB_SECTIONS = 5; // points between mouse samples
const SIZE_MULT = 3; // Max size multiplier
const SIZE_MIN = 0.1 // min size of line
const BIG_DIR = 0.6; // direction in radians for thickest line
const SMOOTH_MAX = 7; // number of smoothing steps performed on a line. Bigger that 20 will slow the rendering down
const SHAPE_ALPHA = 0.5; // the stoke alpha
const SHAPE_FILL_ALPHA = 0.75; // the fill alpha
const SHADOW_ALPHA = 0.1; // the shadow alpha
const SHADOW_BLUR = 5; // the shadow blur
const SHADOW_OFFX = 6; // shoadow offest x and y
const SHADOW_OFFY = 6;
const SHAPE_LINE_WIDTH = 0.6; // stroke width of shape. This is constant and is not scaled
const SHAPE_WIDTH = 4; // shape drawn width;
const SHAPE_LENGTH = 20; // shape drawn length
const SHAPE_ROUNDING = 2; // shape rounded corner radius. Warning invalid results if rounding is greater than half width or height which ever is the smallest
const SHAPE_TRAIL = 0; // offset draw shape. Negivive numbers trail drawing positive are infront

var div = document.createElement("div");
div.textContent = "Click drag mouse to draw, Right click to clear."
document.body.appendChild(div);

var mouse;
var demo = function(){

/** fullScreenCanvas.js begin **/
var canvas = (function(){
var canvas = document.getElementById("canv");
if(canvas !== null){
document.body.removeChild(canvas);
}
// creates a blank image with 2d context
canvas = document.createElement("canvas");
canvas.id = "canv";
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.style.position = "absolute";
canvas.style.top = "0px";
canvas.style.left = "0px";
canvas.style.zIndex = 1000;
canvas.ctx = canvas.getContext("2d");
document.body.appendChild(canvas);
return canvas;
})();
var ctx = canvas.ctx;

/** fullScreenCanvas.js end **/
/** MouseFull.js begin **/
if(typeof mouse !== "undefined"){ // if the mouse exists
if( mouse.removeMouse !== undefined){
mouse.removeMouse(); // remove previouse events
}
}
var canvasMouseCallBack = undefined; // if needed
mouse = (function(){
var mouse = {
x : 0, y : 0, w : 0, alt : false, shift : false, ctrl : false,
interfaceId : 0, buttonLastRaw : 0, buttonRaw : 0,
over : false, // mouse is over the element
bm : [1, 2, 4, 6, 5, 3], // masks for setting and clearing button raw bits;
getInterfaceId : function () { return this.interfaceId++; }, // For UI functions
startMouse:undefined,
mouseEvents : "mousemove,mousedown,mouseup,mouseout,mouseover,mousewheel,DOMMouseScroll".split(",")
};
function mouseMove(e) {
var t = e.type, m = mouse;
m.x = e.offsetX; m.y = e.offsetY;
if (m.x === undefined) { m.x = e.clientX; m.y = e.clientY; }
m.alt = e.altKey;m.shift = e.shiftKey;m.ctrl = e.ctrlKey;
if (t === "mousedown") { m.buttonRaw |= m.bm[e.which-1];
} else if (t === "mouseup") { m.buttonRaw &= m.bm[e.which + 2];
} else if (t === "mouseout") { m.buttonRaw = 0; m.over = false;
} else if (t === "mouseover") { m.over = true;
} else if (t === "mousewheel") { m.w = e.wheelDelta;
} else if (t === "DOMMouseScroll") { m.w = -e.detail;}
if (canvasMouseCallBack) { canvasMouseCallBack(mouse); }
e.preventDefault();
}
function startMouse(element){
if(element === undefined){
element = document;
}
mouse.element = element;
mouse.mouseEvents.forEach(
function(n){
element.addEventListener(n, mouseMove);
}
);
element.addEventListener("contextmenu", function (e) {e.preventDefault();}, false);
}
mouse.removeMouse = function(){
if(mouse.element !== undefined){
mouse.mouseEvents.forEach(
function(n){
mouse.element.removeEventListener(n, mouseMove);
}
);
canvasMouseCallBack = undefined;
}
}
mouse.mouseStart = startMouse;
return mouse;
})();
if(typeof canvas !== "undefined"){
mouse.mouseStart(canvas);
}else{
mouse.mouseStart();
}
/** MouseFull.js end **/
/** CreateImage.js begin **/
// 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;}

/** CreateImage.js end **/
/** FrameUpdate.js begin **/
var w = canvas.width;
var h = canvas.height;
var cw = w / 2;
var ch = h / 2;
var line = []; // line to hold drawing points
var image = createImage(w,h); // Background image to dump point to when soothed

var PI2 = Math.PI * 2; // 360 to save typing
var PIh = Math.PI / 2; // 90

// draws a rounded rectangle path
function roundedRect(ctx,x, y, w, h, r){

ctx.beginPath();
ctx.arc(x + r, y + r, r, PIh * 2, PIh * 3);
ctx.arc(x + w - r, y + r, r, PIh * 3, PI2);
ctx.arc(x + w - r, y + h - r, r, 0, PIh);
ctx.arc(x + r, y + h - r, r, PIh, PIh * 2);
ctx.closePath();
}

// this draws a section of line
function drawStroke(ctx,line){
var len = line.length;

ctx.shadowBlur = SHADOW_BLUR;
ctx.shadowOffsetX = SHADOW_OFFX;
ctx.shadowOffsetY = SHADOW_OFFY;
ctx.shadowColor = "rgba(0,0,0," + SHADOW_ALPHA + ")";
ctx.strokeStyle = "rgba(0,0,0," + SHAPE_FILL_ALPHA + ")";
ctx.fillStyle = "rgba(255,255,255," + SHAPE_ALPHA + ")";
for (var i = 0; i < len - 1; i++) { // for each point minus 1
var p1 = line[i];
var p2 = line[i + 1]; // get the point and one ahead
if (p1.dir && p2.dir) { // do both points have a direction
// divide the distance between the points by 5 and draw each sub section
for (var k = 0; k < p1.len; k += p1.len / SUB_SECTIONS) {
// get the points between mouse samples
var x = p1.x + p1.nx * k;
var y = p1.y + p1.ny * k;
var kk = k / p1.len; // get normalised distance
// tween direction but need to check cyclic
if (p1.dir > Math.PI * 1.5 && p2.dir < Math.PI / 2) {
var dir = ((p2.dir + Math.PI * 2) - p1.dir) * kk + p1.dir;
} else
if (p2.dir > Math.PI * 1.5 && p1.dir < Math.PI / 2) {
var dir = ((p2.dir - Math.PI * 2) - p1.dir) * kk + p1.dir;
} else {
var dir = (p2.dir - p1.dir) * kk + p1.dir;
}

// get size dependent on direction
var size = (Math.abs(Math.sin(dir + BIG_DIR)) + SIZE_MIN) * SIZE_MULT;
// caculate the transform requiered.
var xdx = Math.cos(dir) * size;
var xdy = Math.sin(dir) * size;
// set the line width to the invers scale so it remains constant
ctx.lineWidth = SHAPE_LINE_WIDTH * (1 / size); // make sure that the line width does not scale
// set the transform
ctx.setTransform(xdx, xdy, -xdy, xdx, x, y);
// draw the shape
roundedRect(ctx, -SHAPE_LENGTH / 2 - SHAPE_TRAIL, -SHAPE_WIDTH / 2, SHAPE_LENGTH, SHAPE_WIDTH, SHAPE_ROUNDING);
// fill and stroke
ctx.fill();
ctx.stroke();
}
}
}
// restore transform
ctx.setTransform(1, 0, 0, 1, 0, 0);
}

// update function will try 60fps but setting will slow this down.
function update(){
// restore transform
ctx.setTransform(1, 0, 0, 1, 0, 0);
// clear
ctx.clearRect(0, 0, w, h);
// get line length
var len = line.length;

if (mouse.buttonRaw !== 1) { // button up so draw all onto image
drawStroke(image.ctx, line)
line = [];
} else {
// remove trailing line segments that are no longer being smoothed
if (len > SMOOTH_MAX * 2) {
var a = line.splice(0, SMOOTH_MAX - 1)
a.push(line[0]);
drawStroke(image.ctx, a)
}
}
// draw background image
ctx.drawImage(image, 0, 0);

// is the button down
if (mouse.buttonRaw === 1) {
// if more than one point
if (line.length > 0) {
// only add a point if mouse has moved.
if (mouse.x !== line[line.length - 1].x || mouse.y !== line[line.length - 1].y) {
line.push({
x : mouse.x,
y : mouse.y,
s : 0
});
}
} else {
// add a point if no points exist
line.push({
x : mouse.x,
y : mouse.y,
s : 0
});
}
}
// get number of points
var len = line.length;


if(mouse.buttonRaw === 1){ // mouse down the do simple running average smooth
// This smooth will continue to refine points untill the it is outside the
// smoothing range/
for (var i = 0; i < len - 3; i++) {
var p1 = line[i];
var p2 = line[i + 1];
var p3 = line[i + 2];
if (p1.s < SMOOTH_MAX) {
p1.s += 1;
p2.x = ((p1.x + p3.x) / 2 + p2.x * 2) / 3;
p2.y = ((p1.y + p3.y) / 2 + p2.y * 2) / 3;
}
}
// caculate the direction, length and normalised vector for
// each line segment and add to the point
for(var i = 0; i < len-1; i++){
var p1 = line[i];
var p2 = line[i + 1];
var nx = p2.x - p1.x;
var ny = p2.y - p1.y;
p1.dir = ((Math.atan2(ny, nx) % PI2) + PI2) % PI2; // get direction
p1.len = hypot(nx, ny); // get length
p1.nx = nx / p1.len; // get normalised vector
p1.ny = ny / p1.len;

}
// draw the line points onto the canvas.
drawStroke(ctx,line)
}
if((mouse.buttonRaw & 4)=== 4){
line = [];
image.ctx.clearRect(0,0,w,h);
ctx.clearRect(0,0,w,h);
mouse.buttonRaw = 0;
}
if(!STOP){
requestAnimationFrame(update);
}else{
var can = document.getElementById("canv");
if(can !== null){
document.body.removeChild(can);
}
STOP = false;

}
}

update();

}
var STOP = false; // flag to tell demo app to stop
function resizeEvent(){
var waitForStopped = function(){
if(!STOP){ // wait for stop to return to false
demo();
return;
}
setTimeout(waitForStopped,200);
}
STOP = true;
setTimeout(waitForStopped,100);
}
window.addEventListener("resize",resizeEvent);
demo();
/** FrameUpdate.js end **/

关于javascript - 在 HTML5 Canvas 中实现画笔厚度变化(示例想要在内部模拟),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34823751/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com