Skip to content

Commit

Permalink
viliusle#143 - line stabiliser for brush
Browse files Browse the repository at this point in the history
  • Loading branch information
viliusle committed Oct 22, 2020
1 parent bb002c7 commit 40569c8
Show file tree
Hide file tree
Showing 3 changed files with 166 additions and 69 deletions.
34 changes: 2 additions & 32 deletions images/test-collection.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,24 +93,7 @@
7
],
[
123,
117,
8
],
[
107,
118,
9
],
[
101,
118,
10
],
[
99,
118,
9
null
],
[
97,
Expand Down Expand Up @@ -276,20 +259,7 @@
90
],
[
329,
94
],
[
324,
94
],
[
323,
94
],
[
322,
88
null
],
[
320,
Expand Down
2 changes: 1 addition & 1 deletion src/js/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ config.TOOLS = [
title: 'Brush',
attributes: {
size: 4,
smart_brush: true,
pressure: false,
},
},
{
Expand Down
199 changes: 163 additions & 36 deletions src/js/tools/brush.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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();
}

Expand All @@ -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();
}
Expand All @@ -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;

//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 {
data[group_index].data.push([legacy[i][0], legacy[i][1], legacy[i][2]]);
}
}
}

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();
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 {
//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();
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();
}
}
}
else if (data[i - 1] != null) {
//lines
ctx.lineWidth = data[i][2];
if (n == 1 || group_data[1] == null) {
//point
ctx.beginPath();
ctx.moveTo(data[i - 1][0], data[i - 1][1]);
ctx.lineTo(data[i][0], data[i][1]);
ctx.stroke();
ctx.arc(group_data[0][0], group_data[0][1], size / 2, 0, 2 * Math.PI, false);
ctx.fill();
}
}
}
if (n == 1 || data[1] == null) {

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(data[0][0], data[0][1], size / 2, 0, 2 * Math.PI, false);
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

ctx.translate(-layer.x, -layer.y);
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;

0 comments on commit 40569c8

Please sign in to comment.