aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/InkStrokeProperties.ts
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2020-08-31 14:36:46 -0400
committerbobzel <zzzman@gmail.com>2020-08-31 14:36:46 -0400
commit28b904a0a1d8a5d90f128b4487aba047b69bfd70 (patch)
tree1f81d2d05d6691e1beec35d3e12a4cbe8d7dd665 /src/client/views/InkStrokeProperties.ts
parentb0bbd000f608170ae791689b41053d62bf9163d1 (diff)
moved the non-rendering contents of FormatShapePane into InkStrokeProperties.
Diffstat (limited to 'src/client/views/InkStrokeProperties.ts')
-rw-r--r--src/client/views/InkStrokeProperties.ts268
1 files changed, 268 insertions, 0 deletions
diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts
new file mode 100644
index 000000000..ad5c70fb1
--- /dev/null
+++ b/src/client/views/InkStrokeProperties.ts
@@ -0,0 +1,268 @@
+import { action, computed, observable } from "mobx";
+import { ColorState } from 'react-color';
+import { Doc, Field, Opt } from "../../fields/Doc";
+import { Document } from "../../fields/documentSchemas";
+import { InkField } from "../../fields/InkField";
+import { Cast, NumCast } from "../../fields/Types";
+import { DocumentType } from "../documents/DocumentTypes";
+import { SelectionManager } from "../util/SelectionManager";
+import { undoBatch } from "../util/UndoManager";
+
+export class InkStrokeProperties {
+ static Instance: InkStrokeProperties | undefined;
+
+ private _lastFill = "#D0021B";
+ private _lastLine = "#D0021B";
+ private _lastDash = "2";
+
+ @observable _lock = false;
+ @observable _controlBtn = false;
+ @observable _currPoint = -1;
+
+ getField(key: string) {
+ return this.selectedInk?.reduce((p, i) =>
+ (p === undefined || (p && p === i.rootDoc[key])) && i.rootDoc[key] !== "0" ? Field.toString(i.rootDoc[key] as Field) : "", undefined as Opt<string>);
+ }
+
+ @computed get selectedInk() {
+ const inks = SelectionManager.SelectedDocuments().filter(i => Document(i.rootDoc).type === DocumentType.INK);
+ return inks.length ? inks : undefined;
+ }
+ @computed get unFilled() { return this.selectedInk?.reduce((p, i) => p && !i.rootDoc.fillColor ? true : false, true) || false; }
+ @computed get unStrokd() { return this.selectedInk?.reduce((p, i) => p && !i.rootDoc.color ? true : false, true) || false; }
+ @computed get solidFil() { return this.selectedInk?.reduce((p, i) => p && i.rootDoc.fillColor ? true : false, true) || false; }
+ @computed get solidStk() { return this.selectedInk?.reduce((p, i) => p && i.rootDoc.color && (!i.rootDoc.strokeDash || i.rootDoc.strokeDash === "0") ? true : false, true) || false; }
+ @computed get dashdStk() { return !this.unStrokd && this.getField("strokeDash") || ""; }
+ @computed get colorFil() { const ccol = this.getField("fillColor") || ""; ccol && (this._lastFill = ccol); return ccol; }
+ @computed get colorStk() { const ccol = this.getField("color") || ""; ccol && (this._lastLine = ccol); return ccol; }
+ @computed get widthStk() { return this.getField("strokeWidth") || "1"; }
+ @computed get markHead() { return this.getField("strokeStartMarker") || ""; }
+ @computed get markTail() { return this.getField("strokeEndMarker") || ""; }
+ @computed get shapeHgt() { return this.getField("_height"); }
+ @computed get shapeWid() { return this.getField("_width"); }
+ @computed get shapeXps() { return this.getField("x"); }
+ @computed get shapeYps() { return this.getField("y"); }
+ @computed get shapeRot() { return this.getField("rotation"); }
+ set unFilled(value) { this.colorFil = value ? "" : this._lastFill; }
+ set solidFil(value) { this.unFilled = !value; }
+ set colorFil(value) { value && (this._lastFill = value); this.selectedInk?.forEach(i => i.rootDoc.fillColor = value ? value : undefined); }
+ set colorStk(value) { value && (this._lastLine = value); this.selectedInk?.forEach(i => i.rootDoc.color = value ? value : undefined); }
+ set markHead(value) { this.selectedInk?.forEach(i => i.rootDoc.strokeStartMarker = value); }
+ set markTail(value) { this.selectedInk?.forEach(i => i.rootDoc.strokeEndMarker = value); }
+ set unStrokd(value) { this.colorStk = value ? "" : this._lastLine; }
+ set solidStk(value) { this.dashdStk = ""; this.unStrokd = !value; }
+ set dashdStk(value) {
+ value && (this._lastDash = value) && (this.unStrokd = false);
+ this.selectedInk?.forEach(i => i.rootDoc.strokeDash = value ? this._lastDash : undefined);
+ }
+ set shapeXps(value) { this.selectedInk?.forEach(i => i.rootDoc.x = Number(value)); }
+ set shapeYps(value) { this.selectedInk?.forEach(i => i.rootDoc.y = Number(value)); }
+ set shapeRot(value) { this.selectedInk?.forEach(i => i.rootDoc.rotation = Number(value)); }
+ set widthStk(value) { this.selectedInk?.forEach(i => i.rootDoc.strokeWidth = Number(value)); }
+ set shapeWid(value) {
+ this.selectedInk?.filter(i => i.rootDoc._width && i.rootDoc._height).forEach(i => {
+ const oldWidth = NumCast(i.rootDoc._width);
+ i.rootDoc._width = Number(value);
+ this._lock && (i.rootDoc._height = (i.rootDoc._width * NumCast(i.rootDoc._height)) / oldWidth);
+ });
+ }
+ set shapeHgt(value) {
+ this.selectedInk?.filter(i => i.rootDoc._width && i.rootDoc._height).forEach(i => {
+ const oldHeight = NumCast(i.rootDoc._height);
+ i.rootDoc._height = Number(value);
+ this._lock && (i.rootDoc._width = (i.rootDoc._height * NumCast(i.rootDoc._width)) / oldHeight);
+ });
+ }
+
+ constructor() {
+ InkStrokeProperties.Instance = this;
+ }
+
+ @undoBatch
+ @action
+ addPoints = (x: number, y: number, pts: { X: number, Y: number }[], index: number, control: { X: number, Y: number }[]) => {
+ this.selectedInk?.forEach(action(inkView => {
+ if (this.selectedInk?.length === 1) {
+ const doc = Document(inkView.rootDoc);
+ if (doc.type === DocumentType.INK) {
+ const ink = Cast(doc.data, InkField)?.inkData;
+ if (ink) {
+ const newPoints: { X: number, Y: number }[] = [];
+ var counter = 0;
+ for (var k = 0; k < index; k++) {
+ control.forEach(pt => (pts[k].X === pt.X && pts[k].Y === pt.Y) && counter++);
+ }
+ //decide where to put the new coordinate
+ const spNum = Math.floor(counter / 2) * 4 + 2;
+
+ for (var i = 0; i < spNum; i++) {
+ ink[i] && newPoints.push({ X: ink[i].X, Y: ink[i].Y });
+ }
+ for (var j = 0; j < 4; j++) {
+ newPoints.push({ X: x, Y: y });
+
+ }
+ for (var i = spNum; i < ink.length; i++) {
+ newPoints.push({ X: ink[i].X, Y: ink[i].Y });
+ }
+ this._currPoint = -1;
+ Doc.GetProto(doc).data = new InkField(newPoints);
+ }
+ }
+ }
+ }));
+ }
+
+ @undoBatch
+ @action
+ deletePoints = () => {
+ this.selectedInk?.forEach(action(inkView => {
+ if (this.selectedInk?.length === 1 && this._currPoint !== -1) {
+ const doc = Document(inkView.rootDoc);
+ if (doc.type === DocumentType.INK) {
+ const ink = Cast(doc.data, InkField)?.inkData;
+ if (ink && ink.length > 4) {
+ const newPoints: { X: number, Y: number }[] = [];
+ const toRemove = Math.floor(((this._currPoint + 2) / 4));
+ for (var i = 0; i < ink.length; i++) {
+ if (Math.floor((i + 2) / 4) !== toRemove) {
+ newPoints.push({ X: ink[i].X, Y: ink[i].Y });
+ }
+ }
+ this._currPoint = -1;
+ Doc.GetProto(doc).data = new InkField(newPoints);
+ if (newPoints.length === 4) {
+ const newerPoints: { X: number, Y: number }[] = [];
+ newerPoints.push({ X: newPoints[0].X, Y: newPoints[0].Y });
+ newerPoints.push({ X: newPoints[0].X, Y: newPoints[0].Y });
+ newerPoints.push({ X: newPoints[3].X, Y: newPoints[3].Y });
+ newerPoints.push({ X: newPoints[3].X, Y: newPoints[3].Y });
+ Doc.GetProto(doc).data = new InkField(newerPoints);
+
+ }
+ }
+ }
+ }
+ }));
+ }
+
+ @undoBatch
+ @action
+ rotate = (angle: number) => {
+ const _centerPoints: { X: number, Y: number }[] = [];
+ SelectionManager.SelectedDocuments().forEach(action(inkView => {
+ const doc = Document(inkView.rootDoc);
+ if (doc.type === DocumentType.INK && doc.x && doc.y && doc._width && doc._height && doc.data) {
+ const ink = Cast(doc.data, InkField)?.inkData;
+ if (ink) {
+ const xs = ink.map(p => p.X);
+ const ys = ink.map(p => p.Y);
+ const left = Math.min(...xs);
+ const top = Math.min(...ys);
+ const right = Math.max(...xs);
+ const bottom = Math.max(...ys);
+ _centerPoints.push({ X: left, Y: top });
+ }
+ }
+ }));
+
+ var index = 0;
+ SelectionManager.SelectedDocuments().forEach(action(inkView => {
+ const doc = Document(inkView.rootDoc);
+ if (doc.type === DocumentType.INK && doc.x && doc.y && doc._width && doc._height && doc.data) {
+ doc.rotation = Number(doc.rotation) + Number(angle);
+ const ink = Cast(doc.data, InkField)?.inkData;
+ if (ink) {
+
+ const newPoints: { X: number, Y: number }[] = [];
+ ink.forEach(i => {
+ const newX = Math.cos(angle) * (i.X - _centerPoints[index].X) - Math.sin(angle) * (i.Y - _centerPoints[index].Y) + _centerPoints[index].X;
+ const newY = Math.sin(angle) * (i.X - _centerPoints[index].X) + Math.cos(angle) * (i.Y - _centerPoints[index].Y) + _centerPoints[index].Y;
+ newPoints.push({ X: newX, Y: newY });
+ });
+ Doc.GetProto(doc).data = new InkField(newPoints);
+ const xs = newPoints.map(p => p.X);
+ const ys = newPoints.map(p => p.Y);
+ const left = Math.min(...xs);
+ const top = Math.min(...ys);
+ const right = Math.max(...xs);
+ const bottom = Math.max(...ys);
+
+ doc._height = (bottom - top);
+ doc._width = (right - left);
+ }
+ index++;
+ }
+ }));
+ }
+
+ @undoBatch
+ @action
+ control = (xDiff: number, yDiff: number, controlNum: number) => {
+ this.selectedInk?.forEach(action(inkView => {
+ if (this.selectedInk?.length === 1) {
+ const doc = Document(inkView.rootDoc);
+ if (doc.type === DocumentType.INK && doc.x && doc.y && doc._width && doc._height && doc.data) {
+ const ink = Cast(doc.data, InkField)?.inkData;
+ if (ink) {
+
+ const newPoints: { X: number, Y: number }[] = [];
+ const order = controlNum % 4;
+ for (var i = 0; i < ink.length; i++) {
+ if (controlNum === i ||
+ (order === 0 && i === controlNum + 1) ||
+ (order === 0 && controlNum !== 0 && i === controlNum - 2) ||
+ (order === 0 && controlNum !== 0 && i === controlNum - 1) ||
+ (order === 3 && i === controlNum - 1) ||
+ (order === 3 && controlNum !== ink.length - 1 && i === controlNum + 1) ||
+ (order === 3 && controlNum !== ink.length - 1 && i === controlNum + 2)
+ || ((ink[0].X === ink[ink.length - 1].X) && (ink[0].Y === ink[ink.length - 1].Y) && (i === 0 || i === ink.length - 1) && (controlNum === 0 || controlNum === ink.length - 1))
+ ) {
+ newPoints.push({ X: ink[i].X - (xDiff * inkView.props.ScreenToLocalTransform().Scale), Y: ink[i].Y - (yDiff * inkView.props.ScreenToLocalTransform().Scale) });
+ }
+ else {
+ newPoints.push({ X: ink[i].X, Y: ink[i].Y });
+ }
+ }
+ const oldx = doc.x;
+ const oldy = doc.y;
+ const xs = ink.map(p => p.X);
+ const ys = ink.map(p => p.Y);
+ const left = Math.min(...xs);
+ const top = Math.min(...ys);
+ Doc.GetProto(doc).data = new InkField(newPoints);
+ const xs2 = newPoints.map(p => p.X);
+ const ys2 = newPoints.map(p => p.Y);
+ const left2 = Math.min(...xs2);
+ const top2 = Math.min(...ys2);
+ const right2 = Math.max(...xs2);
+ const bottom2 = Math.max(...ys2);
+ doc._height = (bottom2 - top2);
+ doc._width = (right2 - left2);
+ //if points move out of bounds
+
+ doc.x = oldx - (left - left2);
+ doc.y = oldy - (top - top2);
+
+ }
+ }
+ }
+ }));
+ }
+
+ @undoBatch
+ @action
+ switchStk = (color: ColorState) => {
+ const val = String(color.hex);
+ this.colorStk = val;
+ return true;
+ }
+
+ @undoBatch
+ @action
+ switchFil = (color: ColorState) => {
+ const val = String(color.hex);
+ this.colorFil = val;
+ return true;
+ }
+} \ No newline at end of file