diff options
-rw-r--r-- | package-lock.json | 31 | ||||
-rw-r--r-- | package.json | 1 | ||||
-rw-r--r-- | src/client/views/MainView.tsx | 2 | ||||
-rw-r--r-- | src/client/views/Touchable.tsx | 21 | ||||
-rw-r--r-- | src/client/views/globalCssVariables.scss | 2 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 67 | ||||
-rw-r--r-- | src/client/views/nodes/RadialMenu.scss | 83 | ||||
-rw-r--r-- | src/client/views/nodes/RadialMenu.tsx | 224 | ||||
-rw-r--r-- | src/client/views/nodes/RadialMenuItem.tsx | 117 |
9 files changed, 530 insertions, 18 deletions
diff --git a/package-lock.json b/package-lock.json index 244b2e7e0..da2648d9a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4329,14 +4329,6 @@ "minimalistic-crypto-utils": "^1.0.0" } }, - "emit-logger": { - "version": "github:chocolateboy/emit-logger#b9d25a2d939e42f29c940861e9648bd0fb810070", - "from": "github:chocolateboy/emit-logger#better-emitter-name", - "requires": { - "chalk": "^1.1.1", - "moment": "^2.10.6" - } - }, "emoji-regex": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", @@ -7090,6 +7082,16 @@ "lodash": "^4.17.4", "semver": "^5.0.3", "source-map-support": "^0.5.9" + }, + "dependencies": { + "emit-logger": { + "version": "github:chocolateboy/emit-logger#b9d25a2d939e42f29c940861e9648bd0fb810070", + "from": "github:chocolateboy/emit-logger#better-emitter-name", + "requires": { + "chalk": "^1.1.1", + "moment": "^2.10.6" + } + } } }, "is-accessor-descriptor": { @@ -8572,6 +8574,14 @@ "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" }, + "mongod": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mongod/-/mongod-2.0.0.tgz", + "integrity": "sha1-zuxLcjBRkOhdb4+smS8VpH6xjHQ=", + "requires": { + "promise-queue": "^2.2.3" + } + }, "mongodb": { "version": "3.2.7", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.2.7.tgz", @@ -13297,6 +13307,11 @@ "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", "dev": true }, + "promise-queue": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/promise-queue/-/promise-queue-2.2.5.tgz", + "integrity": "sha1-L29ffA9tCBCelnZZx5uIqe1ek7Q=" + }, "prop-types": { "version": "15.7.2", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", diff --git a/package.json b/package.json index 2a72fac80..f2ff96592 100644 --- a/package.json +++ b/package.json @@ -171,6 +171,7 @@ "mobx-react": "^5.3.5", "mobx-react-devtools": "^6.1.1", "mobx-utils": "^5.5.2", + "mongod": "^2.0.0", "mongodb": "^3.1.13", "mongoose": "^5.6.4", "node-sass": "^4.12.0", diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index f463ca306..93fb0a07c 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -40,6 +40,7 @@ import GestureOverlay from './GestureOverlay'; import { Scripting } from '../util/Scripting'; import { AudioBox } from './nodes/AudioBox'; import { TraceMobx } from '../../new_fields/util'; +import { RadialMenu } from './nodes/RadialMenu'; @observer export class MainView extends React.Component { @@ -517,6 +518,7 @@ export class MainView extends React.Component { </GestureOverlay> <PreviewCursor /> <ContextMenu /> + <RadialMenu/> <PDFMenu /> <MarqueeOptionsMenu /> <OverlayView /> diff --git a/src/client/views/Touchable.tsx b/src/client/views/Touchable.tsx index 24ea801a0..2a7599fbf 100644 --- a/src/client/views/Touchable.tsx +++ b/src/client/views/Touchable.tsx @@ -2,11 +2,13 @@ import * as React from 'react'; import { action } from 'mobx'; import { InteractionUtils } from '../util/InteractionUtils'; import { SelectionManager } from '../util/SelectionManager'; +import { RadialMenu } from './nodes/RadialMenu'; const HOLD_DURATION = 1000; export abstract class Touchable<T = {}> extends React.Component<T> { - private holdTimer: NodeJS.Timeout | undefined; + //private holdTimer: NodeJS.Timeout | undefined; + holdTimer: NodeJS.Timeout | undefined; protected _touchDrag: boolean = false; protected prevPoints: Map<number, React.Touch> = new Map<number, React.Touch>(); @@ -46,12 +48,12 @@ export abstract class Touchable<T = {}> extends React.Component<T> { case 1: this.handle1PointerDown(e); e.persist(); - if (this.holdTimer) { - clearTimeout(this.holdTimer) - this.holdTimer = undefined; - } + // if (this.holdTimer) { + // clearTimeout(this.holdTimer) + // this.holdTimer = undefined; + // } this.holdTimer = setTimeout(() => this.handle1PointerHoldStart(e), HOLD_DURATION); - console.log(this.holdTimer); + // console.log(this.holdTimer); break; case 2: this.handle2PointersDown(e); @@ -74,8 +76,9 @@ export abstract class Touchable<T = {}> extends React.Component<T> { if (!InteractionUtils.IsDragging(this.prevPoints, myTouches, 5) && !this._touchDrag) return; this._touchDrag = true; if (this.holdTimer) { + console.log("CLEAR") clearTimeout(this.holdTimer); - this.holdTimer = undefined; + // this.holdTimer = undefined; } switch (myTouches.length) { case 1: @@ -110,7 +113,7 @@ export abstract class Touchable<T = {}> extends React.Component<T> { } if (this.holdTimer) { clearTimeout(this.holdTimer); - this.holdTimer = undefined; + console.log("clear"); } this._touchDrag = false; e.stopPropagation(); @@ -155,9 +158,9 @@ export abstract class Touchable<T = {}> extends React.Component<T> { } handle1PointerHoldStart = (e: React.TouchEvent): any => { - console.log("Hold"); e.stopPropagation(); e.preventDefault(); + document.removeEventListener("touchmove", this.onTouch); } handleHandDown = (e: React.TouchEvent) => { diff --git a/src/client/views/globalCssVariables.scss b/src/client/views/globalCssVariables.scss index 6dffee586..019f931f9 100644 --- a/src/client/views/globalCssVariables.scss +++ b/src/client/views/globalCssVariables.scss @@ -25,6 +25,8 @@ $search-thumnail-size: 175; // dragged items $contextMenu-zindex: 100000; // context menu shows up over everything +$radialMenu-zindex: 100000; // context menu shows up over everything + $mainTextInput-zindex: 999; // then text input overlay so that it's context menu will appear over decorations, etc $docDecorations-zindex: 998; // then doc decorations appear over everything else $remoteCursors-zindex: 997; // ... not sure what level the remote cursors should go -- is this right? diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index bdec94eb3..2e0ae09ba 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -46,6 +46,9 @@ import { TraceMobx } from '../../../new_fields/util'; import { List } from '../../../new_fields/List'; import { FormattedTextBoxComment } from './FormattedTextBoxComment'; import { GestureUtils } from '../../../pen-gestures/GestureUtils'; +import { RadialMenu } from './RadialMenu'; +import { RadialMenuProps } from './RadialMenuItem'; + library.add(fa.faEdit, fa.faTrash, fa.faShare, fa.faDownload, fa.faExpandArrowsAlt, fa.faCompressArrowsAlt, fa.faLayerGroup, fa.faExternalLinkAlt, fa.faAlignCenter, fa.faCaretSquareRight, fa.faSquare, fa.faConciergeBell, fa.faWindowRestore, fa.faFolder, fa.faMapPin, fa.faLink, fa.faFingerprint, fa.faCrosshairs, fa.faDesktop, fa.faUnlock, fa.faLock, fa.faLaptopCode, fa.faMale, @@ -85,9 +88,9 @@ export interface DocumentViewProps { ChromeHeight?: () => number; dontRegisterView?: boolean; layoutKey?: string; + radialMenu?: String[]; } - @observer export class DocumentView extends DocComponent<DocumentViewProps, Document>(Document) { private _downX: number = 0; @@ -110,6 +113,66 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu @computed get onPointerDownHandler() { return this.props.onPointerDown ? this.props.onPointerDown : this.Document.onPointerDown; } @computed get onPointerUpHandler() { return this.props.onPointerUp ? this.props.onPointerUp : this.Document.onPointerUp; } + private _firstX: number = 0; + private _firstY: number = 0; + + + // handle1PointerHoldStart = (e: React.TouchEvent): any => { + // this.onRadialMenu(e); + // const pt = InteractionUtils.GetMyTargetTouches(e, this.prevPoints, true)[0]; + // this._firstX = pt.pageX; + // this._firstY = pt.pageY; + // e.stopPropagation(); + // e.preventDefault(); + + // document.removeEventListener("touchmove", this.onTouch); + // document.removeEventListener("touchmove", this.handle1PointerHoldMove); + // document.addEventListener("touchmove", this.handle1PointerHoldMove); + // document.removeEventListener("touchend", this.handle1PointerHoldEnd); + // document.addEventListener("touchend", this.handle1PointerHoldEnd); + // } + + handle1PointerHoldMove = (e: TouchEvent): void => { + const pt = InteractionUtils.GetMyTargetTouches(e, this.prevPoints, true)[0]; + if (Math.abs(pt.pageX - this._firstX) > 150 || Math.abs(pt.pageY - this._firstY) > 150) { + this.handleRelease(); + } + document.removeEventListener("touchmove", this.handle1PointerHoldMove); + document.addEventListener("touchmove", this.handle1PointerHoldMove); + document.removeEventListener("touchend", this.handle1PointerHoldEnd); + document.addEventListener("touchend", this.handle1PointerHoldEnd); + } + + handleRelease() { + RadialMenu.Instance.closeMenu(); + document.removeEventListener("touchmove", this.handle1PointerHoldMove); + document.removeEventListener("touchend", this.handle1PointerHoldEnd); + } + + handle1PointerHoldEnd = (e: TouchEvent): void => { + RadialMenu.Instance.closeMenu(); + document.removeEventListener("touchmove", this.handle1PointerHoldMove); + document.removeEventListener("touchend", this.handle1PointerHoldEnd); + } + + @action + onRadialMenu = (e: React.TouchEvent): void => { + const pt = InteractionUtils.GetMyTargetTouches(e, this.prevPoints, true)[0]; + + RadialMenu.Instance.openMenu(); + + RadialMenu.Instance.addItem({ description: "Open Fields", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group", selected: -1 }); + RadialMenu.Instance.addItem({ description: "Delete this document", event: () => this.props.ContainingCollectionView?.removeDocument(this.props.Document), icon: "trash", selected: -1 }); + RadialMenu.Instance.addItem({ description: "Open in a new tab", event: () => this.props.addDocTab(this.props.Document, undefined, "onRight"), icon: "folder", selected: -1 }); + RadialMenu.Instance.addItem({ description: "Pin to Presentation", event: () => this.props.pinToPres(this.props.Document), icon: "map-pin", selected: -1 }); + + RadialMenu.Instance.displayMenu(pt.pageX - 15, pt.pageY - 15); + if (!SelectionManager.IsSelected(this, true)) { + SelectionManager.SelectDoc(this, false); + } + e.stopPropagation(); + } + @action componentDidMount() { this._mainCont.current && (this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, this.drop.bind(this))); @@ -399,11 +462,13 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu document.removeEventListener("pointerup", this.onPointerUp); document.addEventListener("pointermove", this.onPointerMove); document.addEventListener("pointerup", this.onPointerUp); + if ((e.nativeEvent as any).formattedHandled) { e.stopPropagation(); } } } onPointerMove = (e: PointerEvent): void => { + if ((e as any).formattedHandled) { e.stopPropagation(); return; } if ((InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || InkingControl.Instance.selectedTool === InkTool.Highlighter || InkingControl.Instance.selectedTool === InkTool.Pen)) return; if (e.cancelBubble && this.active) { diff --git a/src/client/views/nodes/RadialMenu.scss b/src/client/views/nodes/RadialMenu.scss new file mode 100644 index 000000000..ce0c263ef --- /dev/null +++ b/src/client/views/nodes/RadialMenu.scss @@ -0,0 +1,83 @@ +@import "../globalCssVariables"; + +.radialMenu-cont { + position: absolute; + z-index: $radialMenu-zindex; + flex-direction: column; +} + +.radialMenu-subMenu-cont { + position: absolute; + display: flex; + z-index: 1000; + flex-direction: column; + border-radius: 15px; + padding-top: 10px; + padding-bottom: 10px; +} + +.radialMenu-item { + // width: 11vw; //10vw + display: flex; //comment out to allow search icon to be inline with search text + align-items: center; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + transition: all .1s; + border-style: none; + white-space: nowrap; + font-size: 13px; + letter-spacing: 2px; + text-transform: uppercase; +} + +s +.radialMenu-itemSelected { + border-style: none; +} + +.radialMenu-group { + // width: 11vw; //10vw + display: flex; //comment out to allow search icon to be inline with search text + justify-content: left; + align-items: center; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + transition: all .1s; + border-width: .11px; + border-style: none; + border-color: $intermediate-color; // rgb(187, 186, 186); + // padding: 10px 0px 10px 0px; + white-space: nowrap; + font-size: 13px; + text-transform: uppercase; + letter-spacing: 2px; + padding-left: 5px; +} + + +.radialMenu-description { + margin-left: 5px; + text-align: left; + display: inline; //need this? +} + + + +.icon-background { + pointer-events: all; + height:100%; + margin-top: 15px; + background-color: transparent; + width: 35px; + text-align: center; + font-size: 20px; + margin-left: 5px; +}
\ No newline at end of file diff --git a/src/client/views/nodes/RadialMenu.tsx b/src/client/views/nodes/RadialMenu.tsx new file mode 100644 index 000000000..74c5f53bd --- /dev/null +++ b/src/client/views/nodes/RadialMenu.tsx @@ -0,0 +1,224 @@ +import React = require("react"); +import { observer } from "mobx-react"; +import { action, observable, computed, IReactionDisposer, reaction, runInAction } from "mobx"; +import { RadialMenuItem, RadialMenuProps } from "./RadialMenuItem"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import Measure from "react-measure"; +import "./RadialMenu.scss"; + +@observer +export class RadialMenu extends React.Component { + static Instance: RadialMenu; + static readonly buffer = 20; + + constructor(props: Readonly<{}>) { + super(props); + + RadialMenu.Instance = this; + } + + @observable private _mouseX: number = -1; + @observable private _mouseY: number = -1; + @observable private _shouldDisplay: boolean = false; + @observable private _mouseDown: boolean = false; + private _reactionDisposer?: IReactionDisposer; + + + @action + onPointerDown = (e: PointerEvent) => { + this._mouseDown = true; + this._mouseX = e.clientX; + this._mouseY = e.clientY; + document.addEventListener("pointermove", this.onPointerMove); + } + + @observable + private _closest: number = -1; + + @action + onPointerMove = (e: PointerEvent) => { + const curX = e.clientX; + const curY = e.clientY; + const deltX = this._mouseX - curX; + const deltY = this._mouseY - curY; + const scale = Math.hypot(deltY, deltX); + + if (scale < 150 && scale > 50) { + const rad = Math.atan2(deltY, deltX) + Math.PI; + let closest = 0; + let closestval = 999999999; + for (let x = 0; x < this._items.length; x++) { + const curmin = (x / this._items.length) * 2 * Math.PI; + if (rad - curmin < closestval && rad - curmin > 0) { + closestval = rad - curmin; + closest = x; + } + } + this._closest = closest; + } + else { + this._closest = -1; + } + } + @action + onPointerUp = (e: PointerEvent) => { + this._mouseDown = false; + const curX = e.clientX; + const curY = e.clientY; + if (this._mouseX !== curX || this._mouseY !== curY) { + this._shouldDisplay = false; + } + this._shouldDisplay && (this._display = true); + document.removeEventListener("pointermove", this.onPointerMove); + if (this._closest !== -1) { + this._items[this._closest]?.event(); + } + } + componentWillUnmount() { + document.removeEventListener("pointerdown", this.onPointerDown); + + document.removeEventListener("pointerup", this.onPointerUp); + this._reactionDisposer && this._reactionDisposer(); + } + + @action + componentDidMount = () => { + document.addEventListener("pointerdown", this.onPointerDown); + document.addEventListener("pointerup", this.onPointerUp); + this.previewcircle(); + this._reactionDisposer = reaction( + () => this._shouldDisplay, + () => this._shouldDisplay && !this._mouseDown && runInAction(() => this._display = true) + ); + } + + componentDidUpdate = () => { + this.previewcircle(); + } + + @observable private _pageX: number = 0; + @observable private _pageY: number = 0; + @observable private _display: boolean = false; + @observable private _yRelativeToTop: boolean = true; + + + @observable private _width: number = 0; + @observable private _height: number = 0; + + + getItems() { + return this._items; + } + + @action + addItem(item: RadialMenuProps) { + if (this._items.indexOf(item) === -1) { + this._items.push(item); + } + } + + @observable + private _items: Array<RadialMenuProps> = []; + + @action + displayMenu = (x: number, y: number) => { + //maxX and maxY will change if the UI/font size changes, but will work for any amount + //of items added to the menu + + this._pageX = x; + this._pageY = y; + this._shouldDisplay = true; + } + + get pageX() { + const x = this._pageX; + if (x < 0) { + return 0; + } + const width = this._width; + if (x + width > window.innerWidth - RadialMenu.buffer) { + return window.innerWidth - RadialMenu.buffer - width; + } + return x; + } + + get pageY() { + const y = this._pageY; + if (y < 0) { + return 0; + } + const height = this._height; + if (y + height > window.innerHeight - RadialMenu.buffer) { + return window.innerHeight - RadialMenu.buffer - height; + } + return y; + } + + @computed get menuItems() { + return this._items.map((item, index) => <RadialMenuItem {...item} key={item.description} closeMenu={this.closeMenu} max={this._items.length} min={index} selected={this._closest} />); + } + + @action + closeMenu = () => { + this.clearItems(); + this._display = false; + this._shouldDisplay = false; + } + + @action + openMenu = () => { + this._shouldDisplay; + this._display = true; + } + + @action + clearItems() { + this._items = []; + } + + + previewcircle() { + if (document.getElementById("newCanvas") !== null) { + const c: any = document.getElementById("newCanvas"); + if (c.getContext) { + const ctx = c.getContext("2d"); + ctx.beginPath(); + ctx.arc(150, 150, 50, 0, 2 * Math.PI); + ctx.fillStyle = "white"; + ctx.fill(); + ctx.font = "12px Arial"; + ctx.fillStyle = "black"; + ctx.textAlign = "center"; + let description = ""; + if (this._closest !== -1) { + description = this._items[this._closest].description; + } + if (description.length > 15) { + description = description.slice(0, 12); + description += "..."; + } + ctx.fillText(description, 150, 150, 90); + } + } + } + + + render() { + if (!this._display) { + return null; + } + const style = this._yRelativeToTop ? { left: this._mouseX - 150, top: this._mouseY - 150 } : + { left: this._mouseX - 150, top: this._mouseY - 150 }; + + return ( + + <div className="radialMenu-cont" style={style}> + <canvas id="newCanvas" style={{ position: "absolute" }} height="300" width="300"> Your browser does not support the HTML5 canvas tag.</canvas> + {this.menuItems} + </div> + + ); + } + + +}
\ No newline at end of file diff --git a/src/client/views/nodes/RadialMenuItem.tsx b/src/client/views/nodes/RadialMenuItem.tsx new file mode 100644 index 000000000..fdc732d3f --- /dev/null +++ b/src/client/views/nodes/RadialMenuItem.tsx @@ -0,0 +1,117 @@ +import React = require("react"); +import { observable, action } from "mobx"; +import { observer } from "mobx-react"; +import { IconProp, library } from '@fortawesome/fontawesome-svg-core'; +import { faAngleRight } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { UndoManager } from "../../util/UndoManager"; + +library.add(faAngleRight); + +export interface RadialMenuProps { + description: string; + event: (stuff?: any) => void; + undoable?: boolean; + icon: IconProp; + closeMenu?: () => void; + min?: number; + max?: number; + selected: number; +} + + +@observer +export class RadialMenuItem extends React.Component<RadialMenuProps> { + + componentDidMount = () => { + this.setcircle(); + } + + componentDidUpdate = () => { + this.setcircle(); + } + + handleEvent = async (e: React.PointerEvent) => { + this.props.closeMenu && this.props.closeMenu(); + let batch: UndoManager.Batch | undefined; + if (this.props.undoable !== false) { + batch = UndoManager.StartBatch(`Context menu event: ${this.props.description}`); + } + await this.props.event({ x: e.clientX, y: e.clientY }); + batch && batch.end(); + } + + + setcircle() { + let circlemin = 0; + let circlemax = 1 + this.props.min ? circlemin = this.props.min : null; + this.props.max ? circlemax = this.props.max : null; + if (document.getElementById("myCanvas") !== null) { + var c: any = document.getElementById("myCanvas"); + let color = "white" + switch (circlemin % 3) { + case 1: + color = "#c2c2c5"; + break; + case 0: + color = "#f1efeb"; + break; + case 2: + color = "lightgray"; + break; + } + if (circlemax % 3 === 1 && circlemin === circlemax - 1) { + color = "#c2c2c5"; + } + + if (this.props.selected === this.props.min) { + color = "#808080"; + + } + if (c.getContext) { + var ctx = c.getContext("2d"); + ctx.beginPath(); + ctx.arc(150, 150, 150, (circlemin / circlemax) * 2 * Math.PI, ((circlemin + 1) / circlemax) * 2 * Math.PI); + ctx.arc(150, 150, 50, ((circlemin + 1) / circlemax) * 2 * Math.PI, (circlemin / circlemax) * 2 * Math.PI, true); + ctx.fillStyle = color; + ctx.fill() + } + } + } + + calculatorx() { + let circlemin = 0; + let circlemax = 1 + this.props.min ? circlemin = this.props.min : null; + this.props.max ? circlemax = this.props.max : null; + let avg = ((circlemin / circlemax) + ((circlemin + 1) / circlemax)) / 2; + let degrees = 360 * avg; + let x = 100 * Math.cos(degrees * Math.PI / 180); + let y = -125 * Math.sin(degrees * Math.PI / 180); + return x; + } + + calculatory() { + + let circlemin = 0; + let circlemax = 1 + this.props.min ? circlemin = this.props.min : null; + this.props.max ? circlemax = this.props.max : null; + let avg = ((circlemin / circlemax) + ((circlemin + 1) / circlemax)) / 2; + let degrees = 360 * avg; + let x = 125 * Math.cos(degrees * Math.PI / 180); + let y = -100 * Math.sin(degrees * Math.PI / 180); + return y; + } + + + render() { + return ( + <div className={"radialMenu-item" + (this.props.selected ? " radialMenu-itemSelected" : "")} onPointerUp={this.handleEvent}> + <canvas id="myCanvas" height="300" width="300"> Your browser does not support the HTML5 canvas tag.</canvas> + <FontAwesomeIcon icon={this.props.icon} size="3x" style={{ position: "absolute", left: this.calculatorx() + 150 - 19, top: this.calculatory() + 150 - 19 }} /> + </div> + ); + } +}
\ No newline at end of file |