#143 - line stabiliser for brush

This commit is contained in:
viliusle 2020-10-22 22:59:15 +03:00
parent bb002c70dc
commit 40569c8c71
3 changed files with 171 additions and 74 deletions

View File

@ -93,24 +93,7 @@
7
],
[
123,
117,
8
],
[
107,
118,
9
],
[
101,
118,
10
],
[
99,
118,
9
null
],
[
97,
@ -276,20 +259,7 @@
90
],
[
329,
94
],
[
324,
94
],
[
323,
94
],
[
322,
88
null
],
[
320,

View File

@ -44,7 +44,7 @@ config.TOOLS = [
title: 'Brush',
attributes: {
size: 4,
smart_brush: true,
pressure: false,
},
},
{

View File

@ -118,6 +118,11 @@ class Brush_class extends Base_tools_class {
this.Base_layers.insert(this.layer);
this.params_hash = params_hash;
}
config.layer.data.push({
pressure: this.pressure_supported,
data: [],
});
}
mousemove(e) {
@ -131,22 +136,26 @@ class Brush_class extends Base_tools_class {
var max_speed = 20;
var power = 2; //how speed affects size
var params = this.getParams();
var n = config.layer.data.length;
var last_group = config.layer.data[n-1];
//detect line size
var size = params.size;
var new_size = size;
if (this.pressure_supported) {
new_size = size * this.pointer_pressure * 2;
}
else if (params.smart_brush == true) {
new_size = size + size / max_speed * mouse.speed_average * power;
new_size = Math.max(new_size, size / 4);
new_size = Math.round(new_size);
if (params.pressure == true) {
if (this.pressure_supported) {
new_size = size * this.pointer_pressure * 2;
}
else {
new_size = size + size / max_speed * mouse.speed_average * power;
new_size = Math.max(new_size, size / 4);
new_size = Math.round(new_size);
}
}
//more data
config.layer.data.push([mouse.x - config.layer.x, mouse.y - config.layer.y, new_size]);
last_group.data.push([mouse.x - config.layer.x, mouse.y - config.layer.y, new_size]);
config.layer.status = 'draft';
this.Base_layers.render();
}
@ -159,13 +168,16 @@ class Brush_class extends Base_tools_class {
//more data
var params = this.getParams();
var n = config.layer.data.length;
var last_group = config.layer.data[n-1];
var size = params.size;
var new_size = size;
if (this.pressure_supported) {
new_size = size * this.pointer_pressure * 2;
}
config.layer.data.push([mouse.x - config.layer.x, mouse.y - config.layer.y, new_size]);
config.layer.data.push(null);
last_group.data.push([mouse.x - config.layer.x, mouse.y - config.layer.y, new_size]);
config.layer.status = null;
this.Base_layers.render();
}
@ -182,49 +194,164 @@ class Brush_class extends Base_tools_class {
ctx.strokeStyle = layer.color;
ctx.lineWidth = params.size;
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
ctx.translate(layer.x, layer.y);
//draw
var data = layer.data;
var n = data.length;
var size = params.size;
ctx.beginPath();
ctx.moveTo(data[0][0], data[0][1]);
for (var i = 1; i < n; i++) {
if (data[i] === null) {
//break
ctx.beginPath();
}
else {
//line
ctx.lineWidth = data[i][2];
if (data[i - 1] == null && data[i + 1] == null) {
//exception - point
ctx.arc(data[i][0], data[i][1], size / 2, 0, 2 * Math.PI, false);
ctx.fill();
//check for legacy format
if(data.length > 0 && typeof data[0].data == "undefined"){
//convert
var legacy = JSON.parse(JSON.stringify(data));
data = [];
data.push({
pressure: true,
data: [],
});
var group_index = 0;
for(var i in legacy){
if(legacy[i][0] === null){
data.push({
pressure: false,
data: [],
});
group_index++;
}
else if (data[i - 1] != null) {
//lines
ctx.lineWidth = data[i][2];
ctx.beginPath();
ctx.moveTo(data[i - 1][0], data[i - 1][1]);
ctx.lineTo(data[i][0], data[i][1]);
ctx.stroke();
else {
data[group_index].data.push([legacy[i][0], legacy[i][1], legacy[i][2]]);
}
}
}
if (n == 1 || data[1] == null) {
//point
ctx.beginPath();
ctx.arc(data[0][0], data[0][1], size / 2, 0, 2 * Math.PI, false);
ctx.fill();
var n = data.length;
for (var k = 0; k < n; k++) {
var group = data[k]; //data from mouse down till mouse release
var group_data = group.data;
var group_n = group_data.length;
if (group.pressure == false) {
//stabilized lines method does not support multiple line sizes
this.render_stabilized(ctx, group_data);
}
else {
ctx.beginPath();
ctx.moveTo(group_data[0][0], group_data[0][1]);
for (var i = 1; i < group_n; i++) {
if (group_data[i] === null) {
//break
ctx.beginPath();
}
else {
//line
ctx.lineWidth = group_data[i][2];
if (group_data[i - 1] == null && group_data[i + 1] == null) {
//exception - point
ctx.arc(group_data[i][0], group_data[i][1], size / 2, 0, 2 * Math.PI, false);
ctx.fill();
}
else if (group_data[i - 1] != null) {
//lines
ctx.lineWidth = group_data[i][2];
ctx.beginPath();
ctx.moveTo(group_data[i - 1][0], group_data[i - 1][1]);
ctx.lineTo(group_data[i][0], group_data[i][1]);
ctx.stroke();
}
}
}
if (n == 1 || group_data[1] == null) {
//point
ctx.beginPath();
ctx.arc(group_data[0][0], group_data[0][1], size / 2, 0, 2 * Math.PI, false);
ctx.fill();
}
}
}
ctx.translate(-layer.x, -layer.y);
}
};
/**
* draw stabilized lines
* author: Manoj Verma
* source: https://stackoverflow.com/questions/7891740/drawing-smooth-lines-with-canvas/44810470#44810470
*
* @param ctx
* @param queue
*/
render_stabilized(ctx, queue) {
var data = JSON.parse(JSON.stringify(queue));
var n = data.length;
if (data.length == 1) {
//point
var point = data[0];
ctx.beginPath();
ctx.arc(point[0], point[1], point[2] / 2, 0, 2 * Math.PI, false);
ctx.fill();
return;
}
else if (data.length <= 5) {
//not enough points yet
for (var i = 1; i < n; i++) {
ctx.beginPath();
ctx.moveTo(data[i - 1][0], data[i - 1][1]);
ctx.lineTo(data[i][0], data[i][1]);
ctx.stroke();
}
return;
}
//fix for loose ending, so lets duplicate last point
data.push([data[n - 1][0], data[n - 1][1]]);
ctx.beginPath();
ctx.moveTo(data[0][0], data[0][1]);
//prepare
var tempdata1 = [data[0]];
var c, d;
for (var i = 1; i < data.length - 1; i = i+1) {
c = (data[i][0] + data[i + 1][0]) / 2;
d = (data[i][1] + data[i + 1][1]) / 2;
tempdata1.push([c, d]);
}
var tempdata2 = [tempdata1[0]];
for (var i = 1; i < tempdata1.length - 1; i = i+1) {
c = (tempdata1[i][0] + tempdata1[i + 1][0]) / 2;
d = (tempdata1[i][1] + tempdata1[i + 1][1]) / 2;
tempdata2.push([c, d]);
}
var tempdata = [tempdata2[0]];
for (var i = 1; i < tempdata2.length - 1; i = i+1) {
c = (tempdata2[i][0] + tempdata2[i + 1][0]) / 2;
d = (tempdata2[i][1] + tempdata2[i + 1][1]) / 2;
tempdata.push([c, d]);
}
//draw
for (var i = 1; i < tempdata.length - 2; i = i+1) {
c = (tempdata[i][0] + tempdata[i + 1][0]) / 2;
d = (tempdata[i][1] + tempdata[i + 1][1]) / 2;
ctx.quadraticCurveTo(tempdata[i][0], tempdata[i][1], c, d);
}
// For the last 2 points
ctx.quadraticCurveTo(
tempdata[i][0],
tempdata[i][1],
tempdata[i+1][0],
tempdata[i+1][1]
);
ctx.stroke();
}
}
export default Brush_class;