From 01fc2726d439127baebc214bc1c0c7a0c1554fa2 Mon Sep 17 00:00:00 2001 From: Andy Rickert Date: Wed, 8 Jan 2020 17:11:33 -0800 Subject: setting up architecture for radial menu --- src/client/views/nodes/DocumentView.tsx | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src') diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index a14f69f71..e1b68cdf7 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -82,6 +82,7 @@ export interface DocumentViewProps { ChromeHeight?: () => number; dontRegisterView?: boolean; layoutKey?: string; + radialMenu?: String[]; } @@ -104,6 +105,14 @@ export class DocumentView extends DocComponent(Docu @computed get nativeHeight() { return this.layoutDoc.nativeHeight || 0; } @computed get onClickHandler() { return this.props.onClick ? this.props.onClick : this.Document.onClick; } + constructor(props: any) { + super(props); + } + + handle1PointerHoldStart= (e: React.TouchEvent): any =>{ + console.log("yeet") + } + @action componentDidMount() { this._mainCont.current && (this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, this.drop.bind(this))); -- cgit v1.2.3-70-g09d2 From e3466bdb86fdc3096e86f2437a0c8e2000b2252a Mon Sep 17 00:00:00 2001 From: Andy Rickert Date: Wed, 8 Jan 2020 22:32:09 -0800 Subject: menu appears on click --- src/client/views/MainView.tsx | 2 + src/client/views/Touchable.tsx | 9 ++++- src/client/views/globalCssVariables.scss | 2 + src/client/views/nodes/DocumentView.tsx | 69 +++++++++++++++++++++++++++++--- 4 files changed, 75 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index a1196ee1c..5bf5dbcc1 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -40,6 +40,7 @@ import InkSelectDecorations from './InkSelectDecorations'; 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 { @@ -514,6 +515,7 @@ export class MainView extends React.Component { {this.mainContent} + diff --git a/src/client/views/Touchable.tsx b/src/client/views/Touchable.tsx index 251cd41e5..49b2116f1 100644 --- a/src/client/views/Touchable.tsx +++ b/src/client/views/Touchable.tsx @@ -1,11 +1,13 @@ import * as React from 'react'; import { action } from 'mobx'; import { InteractionUtils } from '../util/InteractionUtils'; +import { RadialMenu } from './nodes/RadialMenu'; const HOLD_DURATION = 1000; export abstract class Touchable extends React.Component { - private holdTimer: NodeJS.Timeout | undefined; + //private holdTimer: NodeJS.Timeout | undefined; + holdTimer: NodeJS.Timeout | undefined; protected _touchDrag: boolean = false; protected prevPoints: Map = new Map(); @@ -54,6 +56,7 @@ export abstract class Touchable extends React.Component { if (!InteractionUtils.IsDragging(this.prevPoints, myTouches, 5) && !this._touchDrag) return; this._touchDrag = true; if (this.holdTimer) { + console.log("CLEAR") clearTimeout(this.holdTimer); } switch (myTouches.length) { @@ -89,6 +92,7 @@ export abstract class Touchable extends React.Component { } if (this.holdTimer) { clearTimeout(this.holdTimer); + console.log("clear"); } this._touchDrag = false; e.stopPropagation(); @@ -136,5 +140,8 @@ export abstract class Touchable extends React.Component { console.log("Hold"); e.stopPropagation(); e.preventDefault(); + document.removeEventListener("touchmove", this.onTouch); + document.removeEventListener("touchend", this.onTouchEnd); } + } \ No newline at end of file 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 e1b68cdf7..d5442bd48 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -45,6 +45,9 @@ import { InkTool } from '../../../new_fields/InkField'; import { TraceMobx } from '../../../new_fields/util'; import { List } from '../../../new_fields/List'; import { FormattedTextBoxComment } from './FormattedTextBoxComment'; +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,7 +88,6 @@ export interface DocumentViewProps { radialMenu?: String[]; } - @observer export class DocumentView extends DocComponent(Document) { private _downX: number = 0; @@ -105,12 +107,65 @@ export class DocumentView extends DocComponent(Docu @computed get nativeHeight() { return this.layoutDoc.nativeHeight || 0; } @computed get onClickHandler() { return this.props.onClick ? this.props.onClick : this.Document.onClick; } - constructor(props: any) { - super(props); - } handle1PointerHoldStart= (e: React.TouchEvent): any =>{ - console.log("yeet") + this.onRadialMenu(e); + + document.removeEventListener("touchmove", this.onTouch); + document.removeEventListener("touchend", this.onTouchEnd); + document.addEventListener("touchmove", this.handle1PointerHoldMove); + document.addEventListener("touchend", this.handle1PointerHoldEnd); + } + + handle1PointerHoldMove = (e: TouchEvent): void => { + console.log("YUH") + document.removeEventListener("touchmove", this.handle1PointerHoldMove); + document.addEventListener("touchmove", this.handle1PointerHoldMove); + document.removeEventListener("touchend", this.handle1PointerHoldEnd); + document.addEventListener("touchend", this.handle1PointerHoldEnd); + } + + handle1PointerHoldEnd = (e: TouchEvent): void => { + RadialMenu.Instance.closeMenu(); + document.removeEventListener("touchmove", this.handle1PointerHoldMove); + document.removeEventListener("touchend", this.handle1PointerHoldEnd); + } + + @action + onRadialMenu = async (event: React.TouchEvent): Promise => { + console.log("YUH") + // the touch onContextMenu is button 0, the pointer onContextMenu is button 2 + // if (e.button === 0) { + // e.preventDefault(); + // return; + // } + let e = event.touches[0]; + // if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3 || + // // event.isDefaultPrevented()) { + // // event.preventDefault(); + // return; + // } + // event.preventDefault(); + + let rm = RadialMenu.Instance; + rm.openMenu(); + + rm.addItem({ description: "Open Fields", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group" }); + runInAction(() => { + // cm.addItem({ + // description: "Share", + // event: () => SharingManager.Instance.open(this), + // icon: "external-link-alt" + // }); + + if (!this.topMost) { + // DocumentViews should stop propagation of this event + } + RadialMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15); + if (!SelectionManager.IsSelected(this, true)) { + SelectionManager.SelectDoc(this, false); + } + }); } @action @@ -371,6 +426,7 @@ export class DocumentView extends DocComponent(Docu } onPointerDown = (e: React.PointerEvent): void => { + // console.log(e.button) // console.log(e.nativeEvent) // continue if the event hasn't been canceled AND we are using a moues or this is has an onClick or onDragStart function (meaning it is a button document) @@ -388,7 +444,6 @@ export class DocumentView extends DocComponent(Docu // || InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || InteractionUtils.IsType(e, InteractionUtils.ERASERTYPE)) { // return; // } - this._downX = e.clientX; this._downY = e.clientY; this._hitTemplateDrag = false; @@ -404,11 +459,13 @@ export class DocumentView extends DocComponent(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 (e.cancelBubble && this.active) { document.removeEventListener("pointermove", this.onPointerMove); // stop listening to pointerMove if something else has stopPropagated it (e.g., the MarqueeView) -- cgit v1.2.3-70-g09d2 From f3c332c982e32d94609bf5ab9c077f602db0d206 Mon Sep 17 00:00:00 2001 From: Andy Rickert Date: Thu, 9 Jan 2020 01:13:22 -0800 Subject: circle appears for menu that can be split into smaller pie pieces --- src/client/views/nodes/DocumentView.tsx | 265 +++++++++++++++++--------------- 1 file changed, 139 insertions(+), 126 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index d5442bd48..b4ebe626f 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -107,9 +107,15 @@ export class DocumentView extends DocComponent(Docu @computed get nativeHeight() { return this.layoutDoc.nativeHeight || 0; } @computed get onClickHandler() { return this.props.onClick ? this.props.onClick : this.Document.onClick; } + private _firstX:number=0; + private _firstY:number=0; + handle1PointerHoldStart= (e: React.TouchEvent): any =>{ this.onRadialMenu(e); + let page =e.touches[0]; + this._firstX=page.pageX; + this._firstY=page.pageY; document.removeEventListener("touchmove", this.onTouch); document.removeEventListener("touchend", this.onTouchEnd); @@ -117,14 +123,21 @@ export class DocumentView extends DocComponent(Docu document.addEventListener("touchend", this.handle1PointerHoldEnd); } - handle1PointerHoldMove = (e: TouchEvent): void => { - console.log("YUH") + handle1PointerHoldMove = (event: TouchEvent): void => { + let e=event.touches[0]; + Math.abs(e.pageX-this._firstX)>175 ||Math.abs(e.pageY-this._firstY)>175? this.handleRelease():null; 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); @@ -300,130 +313,130 @@ export class DocumentView extends DocComponent(Docu } } - handle1PointerDown = (e: React.TouchEvent) => { - if (!e.nativeEvent.cancelBubble) { - const touch = InteractionUtils.GetMyTargetTouches(e, this.prevPoints)[0]; - this._downX = touch.clientX; - this._downY = touch.clientY; - this._hitTemplateDrag = false; - for (let element = (e.target as any); element && !this._hitTemplateDrag; element = element.parentElement) { - if (element.className && element.className.toString() === "collectionViewBaseChrome-collapse") { - this._hitTemplateDrag = true; - } - } - if ((this.active || this.Document.onDragStart || this.Document.onClick) && !e.ctrlKey && !this.Document.lockedPosition && !this.Document.inOverlay) e.stopPropagation(); - document.removeEventListener("touchmove", this.onTouch); - document.addEventListener("touchmove", this.onTouch); - document.removeEventListener("touchend", this.onTouchEnd); - document.addEventListener("touchend", this.onTouchEnd); - if ((e.nativeEvent as any).formattedHandled) e.stopPropagation(); - console.log("down") - } - } - - handle1PointerMove = (e: TouchEvent) => { - if ((e as any).formattedHandled) { e.stopPropagation; return; } - if (e.cancelBubble && this.active) { - document.removeEventListener("touchmove", this.onTouch); - } - else if (!e.cancelBubble && (SelectionManager.IsSelected(this, true) || this.props.parentActive(true) || this.Document.onDragStart || this.Document.onClick) && !this.Document.lockedPosition && !this.Document.inOverlay) { - const touch = InteractionUtils.GetMyTargetTouches(e, this.prevPoints)[0]; - if (Math.abs(this._downX - touch.clientX) > 3 || Math.abs(this._downY - touch.clientY) > 3) { - if (!e.altKey && (!this.topMost || this.Document.onDragStart || this.Document.onClick)) { - document.removeEventListener("touchmove", this.onTouch); - document.removeEventListener("touchend", this.onTouchEnd); - this.startDragging(this._downX, this._downY, this.Document.dropAction ? this.Document.dropAction as any : e.ctrlKey || e.altKey ? "alias" : undefined, this._hitTemplateDrag); - } - } - e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document' however it does mark the event as cancelBubble=true which we test for in the move event handlers - e.preventDefault(); - - } - } - - handle2PointersDown = (e: React.TouchEvent) => { - if (!e.nativeEvent.cancelBubble && !this.isSelected()) { - e.stopPropagation(); - e.preventDefault(); - - document.removeEventListener("touchmove", this.onTouch); - document.addEventListener("touchmove", this.onTouch); - document.removeEventListener("touchend", this.onTouchEnd); - document.addEventListener("touchend", this.onTouchEnd); - } - } - - @action - handle2PointersMove = (e: TouchEvent) => { - const myTouches = InteractionUtils.GetMyTargetTouches(e, this.prevPoints); - const pt1 = myTouches[0]; - const pt2 = myTouches[1]; - const oldPoint1 = this.prevPoints.get(pt1.identifier); - const oldPoint2 = this.prevPoints.get(pt2.identifier); - const pinching = InteractionUtils.Pinning(pt1, pt2, oldPoint1!, oldPoint2!); - if (pinching !== 0 && oldPoint1 && oldPoint2) { - // let dX = (Math.min(pt1.clientX, pt2.clientX) - Math.min(oldPoint1.clientX, oldPoint2.clientX)); - // let dY = (Math.min(pt1.clientY, pt2.clientY) - Math.min(oldPoint1.clientY, oldPoint2.clientY)); - // let dX = Math.sign(Math.abs(pt1.clientX - oldPoint1.clientX) - Math.abs(pt2.clientX - oldPoint2.clientX)); - // let dY = Math.sign(Math.abs(pt1.clientY - oldPoint1.clientY) - Math.abs(pt2.clientY - oldPoint2.clientY)); - // let dW = -dX; - // let dH = -dY; - const dW = (Math.abs(pt1.clientX - pt2.clientX) - Math.abs(oldPoint1.clientX - oldPoint2.clientX)); - const dH = (Math.abs(pt1.clientY - pt2.clientY) - Math.abs(oldPoint1.clientY - oldPoint2.clientY)); - const dX = -1 * Math.sign(dW); - const dY = -1 * Math.sign(dH); - - if (dX !== 0 || dY !== 0 || dW !== 0 || dH !== 0) { - const doc = PositionDocument(this.props.Document); - const layoutDoc = PositionDocument(Doc.Layout(this.props.Document)); - let nwidth = layoutDoc.nativeWidth || 0; - let nheight = layoutDoc.nativeHeight || 0; - const width = (layoutDoc.width || 0); - const height = (layoutDoc.height || (nheight / nwidth * width)); - const scale = this.props.ScreenToLocalTransform().Scale * this.props.ContentScaling(); - const actualdW = Math.max(width + (dW * scale), 20); - const actualdH = Math.max(height + (dH * scale), 20); - doc.x = (doc.x || 0) + dX * (actualdW - width); - doc.y = (doc.y || 0) + dY * (actualdH - height); - const fixedAspect = e.ctrlKey || (!layoutDoc.ignoreAspect && nwidth && nheight); - if (fixedAspect && e.ctrlKey && layoutDoc.ignoreAspect) { - layoutDoc.ignoreAspect = false; - layoutDoc.nativeWidth = nwidth = layoutDoc.width || 0; - layoutDoc.nativeHeight = nheight = layoutDoc.height || 0; - } - if (fixedAspect && (!nwidth || !nheight)) { - layoutDoc.nativeWidth = nwidth = layoutDoc.width || 0; - layoutDoc.nativeHeight = nheight = layoutDoc.height || 0; - } - if (nwidth > 0 && nheight > 0 && !layoutDoc.ignoreAspect) { - if (Math.abs(dW) > Math.abs(dH)) { - if (!fixedAspect) { - layoutDoc.nativeWidth = actualdW / (layoutDoc.width || 1) * (layoutDoc.nativeWidth || 0); - } - layoutDoc.width = actualdW; - if (fixedAspect && !layoutDoc.fitWidth) layoutDoc.height = nheight / nwidth * layoutDoc.width; - else layoutDoc.height = actualdH; - } - else { - if (!fixedAspect) { - layoutDoc.nativeHeight = actualdH / (layoutDoc.height || 1) * (doc.nativeHeight || 0); - } - layoutDoc.height = actualdH; - if (fixedAspect && !layoutDoc.fitWidth) layoutDoc.width = nwidth / nheight * layoutDoc.height; - else layoutDoc.width = actualdW; - } - } else { - dW && (layoutDoc.width = actualdW); - dH && (layoutDoc.height = actualdH); - dH && layoutDoc.autoHeight && (layoutDoc.autoHeight = false); - } - } - // let newWidth = Math.max(Math.abs(oldPoint1!.clientX - oldPoint2!.clientX), Math.abs(pt1.clientX - pt2.clientX)) - // this.props.Document.width = newWidth; - e.stopPropagation(); - e.preventDefault(); - } - } + // handle1PointerDown = (e: React.TouchEvent) => { + // if (!e.nativeEvent.cancelBubble) { + // const touch = InteractionUtils.GetMyTargetTouches(e, this.prevPoints)[0]; + // this._downX = touch.clientX; + // this._downY = touch.clientY; + // this._hitTemplateDrag = false; + // for (let element = (e.target as any); element && !this._hitTemplateDrag; element = element.parentElement) { + // if (element.className && element.className.toString() === "collectionViewBaseChrome-collapse") { + // this._hitTemplateDrag = true; + // } + // } + // if ((this.active || this.Document.onDragStart || this.Document.onClick) && !e.ctrlKey && !this.Document.lockedPosition && !this.Document.inOverlay) e.stopPropagation(); + // document.removeEventListener("touchmove", this.onTouch); + // document.addEventListener("touchmove", this.onTouch); + // document.removeEventListener("touchend", this.onTouchEnd); + // document.addEventListener("touchend", this.onTouchEnd); + // if ((e.nativeEvent as any).formattedHandled) e.stopPropagation(); + // console.log("down") + // } + // } + + // handle1PointerMove = (e: TouchEvent) => { + // if ((e as any).formattedHandled) { e.stopPropagation; return; } + // if (e.cancelBubble && this.active) { + // document.removeEventListener("touchmove", this.onTouch); + // } + // else if (!e.cancelBubble && (SelectionManager.IsSelected(this, true) || this.props.parentActive(true) || this.Document.onDragStart || this.Document.onClick) && !this.Document.lockedPosition && !this.Document.inOverlay) { + // const touch = InteractionUtils.GetMyTargetTouches(e, this.prevPoints)[0]; + // if (Math.abs(this._downX - touch.clientX) > 3 || Math.abs(this._downY - touch.clientY) > 3) { + // if (!e.altKey && (!this.topMost || this.Document.onDragStart || this.Document.onClick)) { + // document.removeEventListener("touchmove", this.onTouch); + // document.removeEventListener("touchend", this.onTouchEnd); + // this.startDragging(this._downX, this._downY, this.Document.dropAction ? this.Document.dropAction as any : e.ctrlKey || e.altKey ? "alias" : undefined, this._hitTemplateDrag); + // } + // } + // e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document' however it does mark the event as cancelBubble=true which we test for in the move event handlers + // e.preventDefault(); + + // } + // } + + // handle2PointersDown = (e: React.TouchEvent) => { + // if (!e.nativeEvent.cancelBubble && !this.isSelected()) { + // e.stopPropagation(); + // e.preventDefault(); + + // document.removeEventListener("touchmove", this.onTouch); + // document.addEventListener("touchmove", this.onTouch); + // document.removeEventListener("touchend", this.onTouchEnd); + // document.addEventListener("touchend", this.onTouchEnd); + // } + // } + + // @action + // handle2PointersMove = (e: TouchEvent) => { + // const myTouches = InteractionUtils.GetMyTargetTouches(e, this.prevPoints); + // const pt1 = myTouches[0]; + // const pt2 = myTouches[1]; + // const oldPoint1 = this.prevPoints.get(pt1.identifier); + // const oldPoint2 = this.prevPoints.get(pt2.identifier); + // const pinching = InteractionUtils.Pinning(pt1, pt2, oldPoint1!, oldPoint2!); + // if (pinching !== 0 && oldPoint1 && oldPoint2) { + // // let dX = (Math.min(pt1.clientX, pt2.clientX) - Math.min(oldPoint1.clientX, oldPoint2.clientX)); + // // let dY = (Math.min(pt1.clientY, pt2.clientY) - Math.min(oldPoint1.clientY, oldPoint2.clientY)); + // // let dX = Math.sign(Math.abs(pt1.clientX - oldPoint1.clientX) - Math.abs(pt2.clientX - oldPoint2.clientX)); + // // let dY = Math.sign(Math.abs(pt1.clientY - oldPoint1.clientY) - Math.abs(pt2.clientY - oldPoint2.clientY)); + // // let dW = -dX; + // // let dH = -dY; + // const dW = (Math.abs(pt1.clientX - pt2.clientX) - Math.abs(oldPoint1.clientX - oldPoint2.clientX)); + // const dH = (Math.abs(pt1.clientY - pt2.clientY) - Math.abs(oldPoint1.clientY - oldPoint2.clientY)); + // const dX = -1 * Math.sign(dW); + // const dY = -1 * Math.sign(dH); + + // if (dX !== 0 || dY !== 0 || dW !== 0 || dH !== 0) { + // const doc = PositionDocument(this.props.Document); + // const layoutDoc = PositionDocument(Doc.Layout(this.props.Document)); + // let nwidth = layoutDoc.nativeWidth || 0; + // let nheight = layoutDoc.nativeHeight || 0; + // const width = (layoutDoc.width || 0); + // const height = (layoutDoc.height || (nheight / nwidth * width)); + // const scale = this.props.ScreenToLocalTransform().Scale * this.props.ContentScaling(); + // const actualdW = Math.max(width + (dW * scale), 20); + // const actualdH = Math.max(height + (dH * scale), 20); + // doc.x = (doc.x || 0) + dX * (actualdW - width); + // doc.y = (doc.y || 0) + dY * (actualdH - height); + // const fixedAspect = e.ctrlKey || (!layoutDoc.ignoreAspect && nwidth && nheight); + // if (fixedAspect && e.ctrlKey && layoutDoc.ignoreAspect) { + // layoutDoc.ignoreAspect = false; + // layoutDoc.nativeWidth = nwidth = layoutDoc.width || 0; + // layoutDoc.nativeHeight = nheight = layoutDoc.height || 0; + // } + // if (fixedAspect && (!nwidth || !nheight)) { + // layoutDoc.nativeWidth = nwidth = layoutDoc.width || 0; + // layoutDoc.nativeHeight = nheight = layoutDoc.height || 0; + // } + // if (nwidth > 0 && nheight > 0 && !layoutDoc.ignoreAspect) { + // if (Math.abs(dW) > Math.abs(dH)) { + // if (!fixedAspect) { + // layoutDoc.nativeWidth = actualdW / (layoutDoc.width || 1) * (layoutDoc.nativeWidth || 0); + // } + // layoutDoc.width = actualdW; + // if (fixedAspect && !layoutDoc.fitWidth) layoutDoc.height = nheight / nwidth * layoutDoc.width; + // else layoutDoc.height = actualdH; + // } + // else { + // if (!fixedAspect) { + // layoutDoc.nativeHeight = actualdH / (layoutDoc.height || 1) * (doc.nativeHeight || 0); + // } + // layoutDoc.height = actualdH; + // if (fixedAspect && !layoutDoc.fitWidth) layoutDoc.width = nwidth / nheight * layoutDoc.height; + // else layoutDoc.width = actualdW; + // } + // } else { + // dW && (layoutDoc.width = actualdW); + // dH && (layoutDoc.height = actualdH); + // dH && layoutDoc.autoHeight && (layoutDoc.autoHeight = false); + // } + // } + // // let newWidth = Math.max(Math.abs(oldPoint1!.clientX - oldPoint2!.clientX), Math.abs(pt1.clientX - pt2.clientX)) + // // this.props.Document.width = newWidth; + // e.stopPropagation(); + // e.preventDefault(); + // } + // } onPointerDown = (e: React.PointerEvent): void => { -- cgit v1.2.3-70-g09d2 From 145c6ae63cf6682032df1336c41589f4993cd79e Mon Sep 17 00:00:00 2001 From: Andy Rickert Date: Thu, 9 Jan 2020 15:07:28 -0800 Subject: menu handles any number of items and adjusts scale accordingly --- src/client/views/nodes/DocumentView.tsx | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index b4ebe626f..19f058b1a 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -125,7 +125,7 @@ export class DocumentView extends DocComponent(Docu handle1PointerHoldMove = (event: TouchEvent): void => { let e=event.touches[0]; - Math.abs(e.pageX-this._firstX)>175 ||Math.abs(e.pageY-this._firstY)>175? this.handleRelease():null; + Math.abs(e.pageX-this._firstX)>150 ||Math.abs(e.pageY-this._firstY)>150? this.handleRelease():null; document.removeEventListener("touchmove", this.handle1PointerHoldMove); document.addEventListener("touchmove", this.handle1PointerHoldMove); document.removeEventListener("touchend", this.handle1PointerHoldEnd); @@ -162,8 +162,23 @@ export class DocumentView extends DocComponent(Docu let rm = RadialMenu.Instance; rm.openMenu(); + const one = RadialMenu.Instance.findByDescription("one..."); + const two = RadialMenu.Instance.findByDescription("two..."); + const three = RadialMenu.Instance.findByDescription("three..."); + const four= RadialMenu.Instance.findByDescription("four..."); + const five= RadialMenu.Instance.findByDescription("five..."); + const six= RadialMenu.Instance.findByDescription("six..."); + const seven= RadialMenu.Instance.findByDescription("seven..."); + + + !one?rm.addItem({ description: "one", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group" }):null; + !two?rm.addItem({ description: "two", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group" }):null; + !three?rm.addItem({ description: "three", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group" }):null; + !four?rm.addItem({ description: "four", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group" }):null; + !five?rm.addItem({ description: "five", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group" }):null; + !six?rm.addItem({ description: "six", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group" }):null; + !seven?rm.addItem({ description: "seven", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group" }):null; - rm.addItem({ description: "Open Fields", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group" }); runInAction(() => { // cm.addItem({ // description: "Share", -- cgit v1.2.3-70-g09d2 From e2a2db0dfe05e0d17521d3f5bfae6fbf9b03bc3c Mon Sep 17 00:00:00 2001 From: Andy Rickert Date: Thu, 9 Jan 2020 20:54:36 -0800 Subject: now fully functional, just needs bugfixing for implementation in different classes --- src/client/views/nodes/DocumentView.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 19f058b1a..c9a56b46f 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -171,13 +171,13 @@ export class DocumentView extends DocComponent(Docu const seven= RadialMenu.Instance.findByDescription("seven..."); - !one?rm.addItem({ description: "one", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group" }):null; - !two?rm.addItem({ description: "two", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group" }):null; - !three?rm.addItem({ description: "three", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group" }):null; - !four?rm.addItem({ description: "four", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group" }):null; - !five?rm.addItem({ description: "five", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group" }):null; - !six?rm.addItem({ description: "six", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group" }):null; - !seven?rm.addItem({ description: "seven", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group" }):null; + !one?rm.addItem({ description: "one", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group",selected:-1 }):null; + !two?rm.addItem({ description: "two", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group",selected:-1 }):null; + !three?rm.addItem({ description: "three", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group",selected:-1 }):null; + !four?rm.addItem({ description: "four", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group",selected:-1 }):null; + !five?rm.addItem({ description: "five", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group",selected:-1 }):null; + !six?rm.addItem({ description: "six", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group" ,selected:-1}):null; + !seven?rm.addItem({ description: "seven", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group" ,selected:-1}):null; runInAction(() => { // cm.addItem({ -- cgit v1.2.3-70-g09d2 From 11abadccd0d12ce39b059c9df87b771ddec21936 Mon Sep 17 00:00:00 2001 From: Andy Rickert Date: Thu, 9 Jan 2020 20:58:54 -0800 Subject: Adding missing files --- src/client/views/nodes/RadialMenu.scss | 83 ++++++++++++ src/client/views/nodes/RadialMenu.tsx | 218 ++++++++++++++++++++++++++++++ src/client/views/nodes/RadialMenuItem.tsx | 96 +++++++++++++ 3 files changed, 397 insertions(+) create mode 100644 src/client/views/nodes/RadialMenu.scss create mode 100644 src/client/views/nodes/RadialMenu.tsx create mode 100644 src/client/views/nodes/RadialMenuItem.tsx (limited to 'src') 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..4fbb40c5f --- /dev/null +++ b/src/client/views/nodes/RadialMenu.tsx @@ -0,0 +1,218 @@ +import React = require("react"); +import { observer } from "mobx-react"; +import { action, observable, computed, IReactionDisposer, reaction, runInAction } from "mobx"; +import { RadialMenuItem, RadialMenuProps, OriginalMenuProps } 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; x0){ + 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._reactionDisposer = reaction( + () => this._shouldDisplay, + () => this._shouldDisplay && !this._mouseDown && runInAction(() => this._display = true) + ); + } + + @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; + } + + findByDescription = (target: string, toLowerCase = false) => { + return this._items.find(menuItem => { + let reference = menuItem.description; + toLowerCase && (reference = reference.toLowerCase()); + return reference === target; + }); + } + + + @action + addItem(item: RadialMenuProps) { + if (this._items.indexOf(item) === -1) { + this._items.push(item); + } + } + + @observable + private _items: Array = []; + + @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) => ); + } + + @action + closeMenu = () => { + this.clearItems(); + this._display = false; + this._shouldDisplay = false; + } + + @action + openMenu = () => { + this._shouldDisplay; + this._display = true; + } + + @action + clearItems() { + this._items = []; + } + + render() { + if (!this._display) { + return null; + } + const style = this._yRelativeToTop ? { left: this._mouseX-150, top: this._mouseY-150 } : + { left: this._mouseX-150, bottom: this._mouseY+150 }; + + const contents = ( + <> + {this.menuItems} + + ); + // return ( + // { this._width = r.offset.width; this._height = r.offset.height; })}> + // {({ measureRef }) => ( + //
+ // {contents} + //
+ // ) + // } + //
+ // ); + return ( + +
+ {contents} +
+ + ); + } + + +} \ 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..727d1c3be --- /dev/null +++ b/src/client/views/nodes/RadialMenuItem.tsx @@ -0,0 +1,96 @@ +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 OriginalMenuProps { + description: string; + event: (stuff?: any) => void; + undoable?: boolean; + icon: IconProp; //maybe should be optional (icon?) + closeMenu?: () => void; + min?: number; + max?:number; + selected:number; +} + + +export type RadialMenuProps = OriginalMenuProps; + +@observer +export class RadialMenuItem extends React.Component { + + componentDidMount = () =>{ + this.setcircle(); + } + + componentDidUpdate = () =>{ + this.setcircle(); + } + + handleEvent = async (e: React.MouseEvent) => { + if ("event" in this.props) { + 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 = "white"; + break; + case 2: + color = "lightgray"; + break; + } + if (circlemax%3===1 && circlemin===circlemax-1){ + color="#c2c2c5"; + } + console.log(this.props.selected,this.props.min) + + if (this.props.selected === this.props.min){ + console.log(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() + } + } + } + + render() { + return ( +
+ Your browser does not support the HTML5 canvas tag. +
+ ); + } +} \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 2379bdba987e524806eecd62cf439cd2bdad3db8 Mon Sep 17 00:00:00 2001 From: Andy Rickert Date: Thu, 9 Jan 2020 23:54:49 -0800 Subject: added icons --- src/client/views/nodes/DocumentView.tsx | 13 ++++++------- src/client/views/nodes/RadialMenu.tsx | 2 +- src/client/views/nodes/RadialMenuItem.tsx | 31 ++++++++++++++++++++++++++++--- 3 files changed, 35 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index c9a56b46f..9bc0244ba 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -146,7 +146,6 @@ export class DocumentView extends DocComponent(Docu @action onRadialMenu = async (event: React.TouchEvent): Promise => { - console.log("YUH") // the touch onContextMenu is button 0, the pointer onContextMenu is button 2 // if (e.button === 0) { // e.preventDefault(); @@ -166,18 +165,18 @@ export class DocumentView extends DocComponent(Docu const two = RadialMenu.Instance.findByDescription("two..."); const three = RadialMenu.Instance.findByDescription("three..."); const four= RadialMenu.Instance.findByDescription("four..."); - const five= RadialMenu.Instance.findByDescription("five..."); - const six= RadialMenu.Instance.findByDescription("six..."); - const seven= RadialMenu.Instance.findByDescription("seven..."); + // const five= RadialMenu.Instance.findByDescription("five..."); + // const six= RadialMenu.Instance.findByDescription("six..."); + // const seven= RadialMenu.Instance.findByDescription("seven..."); !one?rm.addItem({ description: "one", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group",selected:-1 }):null; !two?rm.addItem({ description: "two", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group",selected:-1 }):null; !three?rm.addItem({ description: "three", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group",selected:-1 }):null; !four?rm.addItem({ description: "four", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group",selected:-1 }):null; - !five?rm.addItem({ description: "five", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group",selected:-1 }):null; - !six?rm.addItem({ description: "six", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group" ,selected:-1}):null; - !seven?rm.addItem({ description: "seven", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group" ,selected:-1}):null; + // !five?rm.addItem({ description: "five", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group",selected:-1 }):null; + // !six?rm.addItem({ description: "six", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group" ,selected:-1}):null; + // !seven?rm.addItem({ description: "seven", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group" ,selected:-1}):null; runInAction(() => { // cm.addItem({ diff --git a/src/client/views/nodes/RadialMenu.tsx b/src/client/views/nodes/RadialMenu.tsx index 4fbb40c5f..b0cf3bb98 100644 --- a/src/client/views/nodes/RadialMenu.tsx +++ b/src/client/views/nodes/RadialMenu.tsx @@ -188,7 +188,7 @@ export class RadialMenu extends React.Component { return null; } const style = this._yRelativeToTop ? { left: this._mouseX-150, top: this._mouseY-150 } : - { left: this._mouseX-150, bottom: this._mouseY+150 }; + { left: this._mouseX-150, top: this._mouseY-150 }; const contents = ( <> diff --git a/src/client/views/nodes/RadialMenuItem.tsx b/src/client/views/nodes/RadialMenuItem.tsx index 727d1c3be..f077dd447 100644 --- a/src/client/views/nodes/RadialMenuItem.tsx +++ b/src/client/views/nodes/RadialMenuItem.tsx @@ -12,7 +12,7 @@ export interface OriginalMenuProps { description: string; event: (stuff?: any) => void; undoable?: boolean; - icon: IconProp; //maybe should be optional (icon?) + icon: IconProp; closeMenu?: () => void; min?: number; max?:number; @@ -68,10 +68,8 @@ export class RadialMenuItem extends React.Component Your browser does not support the HTML5 canvas tag. + ); } -- cgit v1.2.3-70-g09d2 From 32ff2b6e39dfd943c784c3cb6afa8806ad3d11b9 Mon Sep 17 00:00:00 2001 From: Andy Rickert Date: Fri, 10 Jan 2020 19:03:08 -0800 Subject: added text in the middle of the menu for description --- src/client/views/nodes/DocumentView.tsx | 2 +- src/client/views/nodes/RadialMenu.tsx | 34 ++++++++++++++++++++++++++++++- src/client/views/nodes/RadialMenuItem.tsx | 2 +- 3 files changed, 35 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 9bc0244ba..49d35637e 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -170,7 +170,7 @@ export class DocumentView extends DocComponent(Docu // const seven= RadialMenu.Instance.findByDescription("seven..."); - !one?rm.addItem({ description: "one", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group",selected:-1 }):null; + !one?rm.addItem({ description: "one one one one one one one one one", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group",selected:-1 }):null; !two?rm.addItem({ description: "two", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group",selected:-1 }):null; !three?rm.addItem({ description: "three", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group",selected:-1 }):null; !four?rm.addItem({ description: "four", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group",selected:-1 }):null; diff --git a/src/client/views/nodes/RadialMenu.tsx b/src/client/views/nodes/RadialMenu.tsx index b0cf3bb98..d8750a192 100644 --- a/src/client/views/nodes/RadialMenu.tsx +++ b/src/client/views/nodes/RadialMenu.tsx @@ -87,13 +87,17 @@ export class RadialMenu extends React.Component { 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; @@ -183,6 +187,33 @@ export class RadialMenu extends React.Component { this._items = []; } + + previewcircle(){ + if (document.getElementById("newCanvas")!==null){ + var c : any= document.getElementById("newCanvas"); + if (c.getContext){ + var 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; @@ -208,6 +239,7 @@ export class RadialMenu extends React.Component { return (
+ Your browser does not support the HTML5 canvas tag. {contents}
diff --git a/src/client/views/nodes/RadialMenuItem.tsx b/src/client/views/nodes/RadialMenuItem.tsx index f077dd447..4ca257df5 100644 --- a/src/client/views/nodes/RadialMenuItem.tsx +++ b/src/client/views/nodes/RadialMenuItem.tsx @@ -59,7 +59,7 @@ export class RadialMenuItem extends React.Component Date: Mon, 13 Jan 2020 17:14:50 -0500 Subject: some fixes --- src/client/views/Touchable.tsx | 2 - src/client/views/nodes/DocumentView.tsx | 91 +++++++------------ src/client/views/nodes/RadialMenu.tsx | 132 +++++++++++---------------- src/client/views/nodes/RadialMenuItem.tsx | 146 +++++++++++++++--------------- 4 files changed, 156 insertions(+), 215 deletions(-) (limited to 'src') diff --git a/src/client/views/Touchable.tsx b/src/client/views/Touchable.tsx index 49b2116f1..7d9184bea 100644 --- a/src/client/views/Touchable.tsx +++ b/src/client/views/Touchable.tsx @@ -137,11 +137,9 @@ export abstract class Touchable extends React.Component { } handle1PointerHoldStart = (e: React.TouchEvent): any => { - console.log("Hold"); e.stopPropagation(); e.preventDefault(); document.removeEventListener("touchmove", this.onTouch); - document.removeEventListener("touchend", this.onTouchEnd); } } \ No newline at end of file diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 49d35637e..e6c6aaa08 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -107,33 +107,38 @@ export class DocumentView extends DocComponent(Docu @computed get nativeHeight() { return this.layoutDoc.nativeHeight || 0; } @computed get onClickHandler() { return this.props.onClick ? this.props.onClick : this.Document.onClick; } - private _firstX:number=0; - private _firstY:number=0; + private _firstX: number = 0; + private _firstY: number = 0; - - handle1PointerHoldStart= (e: React.TouchEvent): any =>{ + + handle1PointerHoldStart = (e: React.TouchEvent): any => { this.onRadialMenu(e); - let page =e.touches[0]; - this._firstX=page.pageX; - this._firstY=page.pageY; + const pt = InteractionUtils.GetMyTargetTouches(e, this.prevPoints)[0]; + this._firstX = pt.pageX; + this._firstY = pt.pageY; + e.stopPropagation(); + e.preventDefault(); document.removeEventListener("touchmove", this.onTouch); - document.removeEventListener("touchend", this.onTouchEnd); + document.removeEventListener("touchmove", this.handle1PointerHoldMove); document.addEventListener("touchmove", this.handle1PointerHoldMove); + document.removeEventListener("touchend", this.handle1PointerHoldEnd); document.addEventListener("touchend", this.handle1PointerHoldEnd); } - handle1PointerHoldMove = (event: TouchEvent): void => { - let e=event.touches[0]; - Math.abs(e.pageX-this._firstX)>150 ||Math.abs(e.pageY-this._firstY)>150? this.handleRelease():null; + handle1PointerHoldMove = (e: TouchEvent): void => { + const pt = InteractionUtils.GetMyTargetTouches(e, this.prevPoints)[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() + handleRelease() { + RadialMenu.Instance.closeMenu(); document.removeEventListener("touchmove", this.handle1PointerHoldMove); document.removeEventListener("touchend", this.handle1PointerHoldEnd); } @@ -145,56 +150,24 @@ export class DocumentView extends DocComponent(Docu } @action - onRadialMenu = async (event: React.TouchEvent): Promise => { - // the touch onContextMenu is button 0, the pointer onContextMenu is button 2 - // if (e.button === 0) { - // e.preventDefault(); - // return; - // } - let e = event.touches[0]; - // if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3 || - // // event.isDefaultPrevented()) { - // // event.preventDefault(); - // return; - // } - // event.preventDefault(); - - let rm = RadialMenu.Instance; - rm.openMenu(); - const one = RadialMenu.Instance.findByDescription("one..."); - const two = RadialMenu.Instance.findByDescription("two..."); - const three = RadialMenu.Instance.findByDescription("three..."); - const four= RadialMenu.Instance.findByDescription("four..."); - // const five= RadialMenu.Instance.findByDescription("five..."); - // const six= RadialMenu.Instance.findByDescription("six..."); - // const seven= RadialMenu.Instance.findByDescription("seven..."); - - - !one?rm.addItem({ description: "one one one one one one one one one", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group",selected:-1 }):null; - !two?rm.addItem({ description: "two", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group",selected:-1 }):null; - !three?rm.addItem({ description: "three", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group",selected:-1 }):null; - !four?rm.addItem({ description: "four", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group",selected:-1 }):null; - // !five?rm.addItem({ description: "five", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group",selected:-1 }):null; + onRadialMenu = (e: React.TouchEvent): void => { + const pt = InteractionUtils.GetMyTargetTouches(e, this.prevPoints)[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: "tab", selected: -1 }); + RadialMenu.Instance.addItem({ description: "four", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group", selected: -1 }); // !six?rm.addItem({ description: "six", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group" ,selected:-1}):null; // !seven?rm.addItem({ description: "seven", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group" ,selected:-1}):null; - runInAction(() => { - // cm.addItem({ - // description: "Share", - // event: () => SharingManager.Instance.open(this), - // icon: "external-link-alt" - // }); - - if (!this.topMost) { - // DocumentViews should stop propagation of this event - } - RadialMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15); - if (!SelectionManager.IsSelected(this, true)) { - SelectionManager.SelectDoc(this, false); - } - }); + RadialMenu.Instance.displayMenu(pt.pageX - 15, pt.pageY - 15); + if (!SelectionManager.IsSelected(this, true)) { + SelectionManager.SelectDoc(this, false); + } } - + @action componentDidMount() { this._mainCont.current && (this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, this.drop.bind(this))); diff --git a/src/client/views/nodes/RadialMenu.tsx b/src/client/views/nodes/RadialMenu.tsx index d8750a192..74c5f53bd 100644 --- a/src/client/views/nodes/RadialMenu.tsx +++ b/src/client/views/nodes/RadialMenu.tsx @@ -1,13 +1,11 @@ import React = require("react"); import { observer } from "mobx-react"; import { action, observable, computed, IReactionDisposer, reaction, runInAction } from "mobx"; -import { RadialMenuItem, RadialMenuProps, OriginalMenuProps } from "./RadialMenuItem"; +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; @@ -30,36 +28,36 @@ export class RadialMenu extends React.Component { onPointerDown = (e: PointerEvent) => { this._mouseDown = true; this._mouseX = e.clientX; - this._mouseY = e.clientY; + this._mouseY = e.clientY; document.addEventListener("pointermove", this.onPointerMove); } - @observable - private _closest:number=-1; + @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) + 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; + if (scale < 150 && scale > 50) { + const rad = Math.atan2(deltY, deltX) + Math.PI; + let closest = 0; let closestval = 999999999; - for (let x =0; x0){ - closestval=rad-curmin - closest=x; + 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; + this._closest = closest; } - else{ - this._closest=-1; + else { + this._closest = -1; } } @action @@ -72,8 +70,8 @@ export class RadialMenu extends React.Component { } this._shouldDisplay && (this._display = true); document.removeEventListener("pointermove", this.onPointerMove); - if (this._closest!==-1){ - this._items[this._closest].event(); + if (this._closest !== -1) { + this._items[this._closest]?.event(); } } componentWillUnmount() { @@ -94,7 +92,7 @@ export class RadialMenu extends React.Component { ); } - componentDidUpdate = () =>{ + componentDidUpdate = () => { this.previewcircle(); } @@ -112,23 +110,14 @@ export class RadialMenu extends React.Component { return this._items; } - findByDescription = (target: string, toLowerCase = false) => { - return this._items.find(menuItem => { - let reference = menuItem.description; - toLowerCase && (reference = reference.toLowerCase()); - return reference === target; - }); - } - - @action addItem(item: RadialMenuProps) { if (this._items.indexOf(item) === -1) { this._items.push(item); } } - - @observable + + @observable private _items: Array = []; @action @@ -166,7 +155,7 @@ export class RadialMenu extends React.Component { } @computed get menuItems() { - return this._items.map((item,index) => ); + return this._items.map((item, index) => ); } @action @@ -188,60 +177,45 @@ export class RadialMenu extends React.Component { } - previewcircle(){ - if (document.getElementById("newCanvas")!==null){ - var c : any= document.getElementById("newCanvas"); - if (c.getContext){ - var 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); + 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 }; + const style = this._yRelativeToTop ? { left: this._mouseX - 150, top: this._mouseY - 150 } : + { left: this._mouseX - 150, top: this._mouseY - 150 }; - const contents = ( - <> - {this.menuItems} - - ); - // return ( - // { this._width = r.offset.width; this._height = r.offset.height; })}> - // {({ measureRef }) => ( - //
- // {contents} - //
- // ) - // } - //
- // ); return ( -
- Your browser does not support the HTML5 canvas tag. - {contents} -
+
+ Your browser does not support the HTML5 canvas tag. + {this.menuItems} +
); } diff --git a/src/client/views/nodes/RadialMenuItem.tsx b/src/client/views/nodes/RadialMenuItem.tsx index 4ca257df5..fdc732d3f 100644 --- a/src/client/views/nodes/RadialMenuItem.tsx +++ b/src/client/views/nodes/RadialMenuItem.tsx @@ -8,114 +8,110 @@ import { UndoManager } from "../../util/UndoManager"; library.add(faAngleRight); -export interface OriginalMenuProps { +export interface RadialMenuProps { description: string; event: (stuff?: any) => void; undoable?: boolean; icon: IconProp; closeMenu?: () => void; min?: number; - max?:number; - selected:number; + max?: number; + selected: number; } -export type RadialMenuProps = OriginalMenuProps; - @observer -export class RadialMenuItem extends React.Component { +export class RadialMenuItem extends React.Component { - componentDidMount = () =>{ + componentDidMount = () => { this.setcircle(); } - componentDidUpdate = () =>{ + componentDidUpdate = () => { this.setcircle(); } - handleEvent = async (e: React.MouseEvent) => { - if ("event" in this.props) { - 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(); + 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: + 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"; - 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() + 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); + 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); + 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 ( -
- Your browser does not support the HTML5 canvas tag. - -
- ); + return ( +
+ Your browser does not support the HTML5 canvas tag. + +
+ ); } } \ No newline at end of file -- cgit v1.2.3-70-g09d2