1
0
Fork 0

[client] Create skeleton for new eraser.

Also, send the actual absolute cursor position instead of the cursor
position in screen space.
This commit is contained in:
Starbeamrainbowlabs 2017-12-08 17:54:20 +00:00
parent 64667dcc10
commit d5f6407cf5
Signed by: sbrl
GPG Key ID: 1BE5172E637709C2
7 changed files with 59 additions and 10 deletions

View File

@ -185,7 +185,7 @@ class BoardWindow extends EventEmitter
}).bind(this)) }).bind(this))
// Keep the server up to date on our viewport and cursor position // Keep the server up to date on our viewport and cursor position
this.cursorSyncer = new CursorSyncer(this.rippleLink, this.cursorUpdateFrequency) this.cursorSyncer = new CursorSyncer(this, this.cursorUpdateFrequency)
// RippleLink message bindings // RippleLink message bindings

View File

@ -1,5 +1,7 @@
"use strict"; "use strict";
import { point_line_distance_multi } from 'line-distance-calculator';
/** /**
* Represents a single chunk on a plane. * Represents a single chunk on a plane.
* Note that this is the client's representation of the chunk, so it's likely * Note that this is the client's representation of the chunk, so it's likely
@ -14,8 +16,11 @@ class Chunk
*/ */
constructor(inChunkRef, inSize) constructor(inChunkRef, inSize)
{ {
/** @type {ChunkReference} */
this.chunkRef = inChunkRef; this.chunkRef = inChunkRef;
/** @type {number} */
this.size = inSize; this.size = inSize;
/** @type {[ { Points: [Vector], Width: number, Color: string }] */
this.lines = []; this.lines = [];
} }
@ -62,6 +67,23 @@ class Chunk
return area.overlaps(area); return area.overlaps(area);
} }
/**
* Fetches the last line segment that lies underneath the specified point.
* Prefers lines drawn later to lines drawn earlier.
* @param {Vector} point The point to find the line underneath.
* @return {object|null} The first line (segment) that lies underneath the specified point, or null if one couldn't be found.
*/
getLineUnderPoint(point)
{
// Prefer lines that have been drawn later (i.e. on top)
for (let i = this.lines.length - 1; i > 0; i--) {
// If our distance to the line is less than half the width (i.e.
// the radius), then we must be inside it
if(point_line_distance_multi(point, this.lines[i].Points) <= this.lines[i].Width / 2)
return this.lines[i];
}
}
update(dt) update(dt)
{ {

View File

@ -1,11 +1,14 @@
"use strict"; "use strict";
import Vector from './Utilities/Vector.js';
class CursorSyncer class CursorSyncer
{ {
constructor(inRippleLink, syncFrequency) constructor(inBoardWindow, syncFrequency)
{ {
this.boardWindow = inBoardWindow
// The ripple link we should send the cursor updates down // The ripple link we should send the cursor updates down
this.rippleLink = inRippleLink; this.rippleLink = this.boardWindow.rippleLink;
// The target frequency in fps at we should send cursor updates. // The target frequency in fps at we should send cursor updates.
this.cursorUpdateFrequency = syncFrequency; this.cursorUpdateFrequency = syncFrequency;
@ -13,7 +16,10 @@ class CursorSyncer
// link connects // link connects
this.rippleLink.on("connect", this.setup.bind(this)); this.rippleLink.on("connect", this.setup.bind(this));
this.cursorPosition = { X: 0, Y: 0 }; /** The current cursor position in screen-space. @type {Vector} */
this.cursorPosition = new Vector(0, 0);
/** The current cursor position in plane-space. @type {Vector} */
this.absCursorPosition = new Vector(0, 0);
} }
setup() setup()
@ -22,10 +28,11 @@ class CursorSyncer
this.lastCursorUpdate = 0; this.lastCursorUpdate = 0;
document.addEventListener("mousemove", (function(event) { document.addEventListener("mousemove", (function(event) {
this.cursorPosition = { this.cursorPosition.x = event.clientX;
X: event.clientX, this.cursorPosition.y = event.clientY;
Y: event.clientY
}; this.absCursorPosition.x = this.boardWindow.viewport.x + this.cursorPosition.x;
this.absCursorPosition.y = this.boardWindow.viewport.y + this.cursorPosition.y;
setTimeout((function() { setTimeout((function() {
// Throttle the cursor updates we send to the server - a high // Throttle the cursor updates we send to the server - a high
@ -50,7 +57,10 @@ class CursorSyncer
// Update the server on the mouse's position // Update the server on the mouse's position
this.rippleLink.send({ this.rippleLink.send({
"Event": "CursorPosition", "Event": "CursorPosition",
"AbsCursorPosition": this.cursorPosition "AbsCursorPosition": {
X: Math.floor(this.absCursorPosition.x),
Y: Math.floor(this.absCursorPosition.y)
}
}); });
} }
} }

View File

@ -3,6 +3,7 @@
import cuid from "cuid"; import cuid from "cuid";
import { simplify_line } from "visvalingam-simplifier"; import { simplify_line } from "visvalingam-simplifier";
import ChunkReference from './ChunkReference.js';
import Vector from './Utilities/Vector'; import Vector from './Utilities/Vector';
import Mouse from './Utilities/Mouse'; import Mouse from './Utilities/Mouse';
@ -129,6 +130,21 @@ class Pencil
this.sendUnsent(); this.sendUnsent();
break; break;
case "eraser":
let locRef = this.boardWin.cursorSyncer.absCursorPosition;
let hoverChunkRef = new ChunkReference(
this.boardWindow.currentPlaneName,
Math.floor((this.boardWindow.viewport.x + this.mouse.position.x) / this.boardWindow.gridSize),
Math.floor((this.boardWindow.viewport.y + this.mouse.position.y) / this.boardWindow.gridSize)
);
let hoverChunk = this.boardWindow.chunkCache.fetchChunk(hoverChunk);
if(hoverChunk == null)
break; // If it's null, then we haven't received it yet from the server
let lineToErase = hoverChunk.getLineUnderPoint()
break;
case "pan": case "pan":
// handled by BoardWindow.handleCanvasMovement(event) // handled by BoardWindow.handleCanvasMovement(event)
break; break;

Binary file not shown.

After

Width:  |  Height:  |  Size: 489 B

View File

@ -21,6 +21,7 @@
<section class="tools"> <section class="tools">
<span class="tool-selector" data-tool-name="brush" title="Draw lines with a brush." data-selected><img src="images/icons/brush.png" aria-hidden="true" /></span> <span class="tool-selector" data-tool-name="brush" title="Draw lines with a brush." data-selected><img src="images/icons/brush.png" aria-hidden="true" /></span>
<span class="tool-selector" data-tool-name="eraser" title="Erase lines. Remember that you can't undo/redo yet!"><img src="images/icons/eraser.png" aria-hidden="true" /></span>
<span class="tool-selector" data-tool-name="pan" title="Pan around the plane."><img src="images/icons/pan.png" aria-hidden="true" /></span> <span class="tool-selector" data-tool-name="pan" title="Pan around the plane."><img src="images/icons/pan.png" aria-hidden="true" /></span>
<span class="tool-selector" data-tool-name="pointer" title="Point at things, but don't change them."><img src="images/icons/point.png" aria-hidden="true" /></span> <span class="tool-selector" data-tool-name="pointer" title="Point at things, but don't change them."><img src="images/icons/point.png" aria-hidden="true" /></span>
</section> </section>

View File

@ -47,7 +47,7 @@ Note that if you're intending to use Nibriboard over the internet or an untruste
- Images: - Images:
- [Transparent Square Tiles](https://www.toptal.com/designers/subtlepatterns/transparent-square-tiles/) from [subtlepatterns.com](https://subtlepatterns.com/) - [Transparent Square Tiles](https://www.toptal.com/designers/subtlepatterns/transparent-square-tiles/) from [subtlepatterns.com](https://subtlepatterns.com/)
- Icons: - Icons:
- [OpenIconic](https://useiconic.com/open) - brush, move -> pan, sun -> point - [OpenIconic](https://useiconic.com/open) - brush, move -> pan, sun -> point, eraser -> delete
- Future reference: Libraries I am considering - Future reference: Libraries I am considering
- [Paper.js](http://paperjs.org/) - Client-side rendering - [Paper.js](http://paperjs.org/) - Client-side rendering
- [IotWeb](http://sensaura.org/pages/tools/iotweb/) - Underlying HTTP / WebSocket server - [IotWeb](http://sensaura.org/pages/tools/iotweb/) - Underlying HTTP / WebSocket server