mirror of
https://github.com/viliusle/miniPaint.git
synced 2026-02-06 11:21:47 +00:00
#143 - line stabiliser for brush
This commit is contained in:
parent
bb002c70dc
commit
40569c8c71
@ -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,
|
||||
|
||||
@ -44,7 +44,7 @@ config.TOOLS = [
|
||||
title: 'Brush',
|
||||
attributes: {
|
||||
size: 4,
|
||||
smart_brush: true,
|
||||
pressure: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user