diff --git a/client/modules/IDE/reducers/preferences.js b/client/modules/IDE/reducers/preferences.js
index 630fa465ef..f91697b5ee 100644
--- a/client/modules/IDE/reducers/preferences.js
+++ b/client/modules/IDE/reducers/preferences.js
@@ -13,7 +13,8 @@ export const initialState = {
autorefresh: false,
language: 'en-US',
autocloseBracketsQuotes: true,
- autocompleteHinter: false
+ autocompleteHinter: false,
+ coordinates: false
};
const preferences = (state = initialState, action) => {
@@ -52,6 +53,10 @@ const preferences = (state = initialState, action) => {
return Object.assign({}, state, {
autocompleteHinter: action.value
});
+ case ActionTypes.SET_COORDINATES:
+ return Object.assign({}, state, {
+ coordinates: action.value
+ });
default:
return state;
}
diff --git a/client/modules/Preview/CoordinateTracker.jsx b/client/modules/Preview/CoordinateTracker.jsx
new file mode 100644
index 0000000000..a7148f81ea
--- /dev/null
+++ b/client/modules/Preview/CoordinateTracker.jsx
@@ -0,0 +1,79 @@
+import React, { useEffect, useState } from 'react';
+import PropTypes from 'prop-types';
+import styled from 'styled-components';
+import { remSize } from '../../theme';
+
+const CoordContainer = styled.div`
+ z-index: 1000;
+ padding: ${remSize(0.1)};
+ // border-bottom: ${remSize(1)} dashed #a6a6a6;
+ margin-bottom: ${remSize(4)};
+
+ p {
+ font-size: ${remSize(9.5)};
+ padding: 0 0 ${remSize(3.5)} ${remSize(3.5)};
+ margin: 0;
+ font-family: Inconsolata, monospace;
+ font-weight: light;
+ color: ${(props) => props.theme.Button.primary.default.foreground};
+ }
+
+ @media (max-width: 550px) {
+ // border-bottom: none;
+ margin-top: ${remSize(10)};
+ }
+`;
+
+const CoordinateTracker = ({ isPlaying, sketchReloaded }) => {
+ const [coordinates, setCoordinates] = useState({ x: 0, y: 0 });
+
+ useEffect(() => {
+ let canvas;
+ let mouseMoveHandler;
+
+ const timeout = setTimeout(() => {
+ const iFrame = document.getElementById('previewIframe0');
+ canvas = iFrame?.contentWindow?.document?.getElementById(
+ 'defaultCanvas0'
+ );
+
+ if (!canvas) {
+ console.warn('Canvas not found.');
+ return;
+ }
+
+ mouseMoveHandler = (event) => {
+ const rect = canvas.getBoundingClientRect();
+ const x = event.clientX - rect.left;
+ const y = event.clientY - rect.top;
+ setCoordinates({ x, y });
+ };
+
+ canvas.addEventListener('mousemove', mouseMoveHandler);
+ }, 500);
+
+ return () => {
+ clearTimeout(timeout);
+
+ if (canvas && mouseMoveHandler) {
+ canvas.removeEventListener('mousemove', mouseMoveHandler);
+ }
+ };
+ }, [isPlaying, sketchReloaded]);
+
+ return (
+
+
+ Mouse X: {isPlaying ? coordinates.x : 0} Mouse Y:{' '}
+ {isPlaying ? coordinates.y : 0}
+
+
+ );
+};
+
+CoordinateTracker.propTypes = {
+ isPlaying: PropTypes.bool.isRequired,
+ sketchReloaded: PropTypes.bool.isRequired
+};
+
+export default CoordinateTracker;
diff --git a/client/modules/Preview/EmbedFrame.jsx b/client/modules/Preview/EmbedFrame.jsx
index fa01604ab7..ca4f811629 100644
--- a/client/modules/Preview/EmbedFrame.jsx
+++ b/client/modules/Preview/EmbedFrame.jsx
@@ -302,6 +302,7 @@ function EmbedFrame({ files, isPlaying, basePath, gridOutput, textOutput }) {
useEffect(renderSketch, [files, isPlaying]);
return (
{
const [basePath, setBasePath] = useState('');
const [textOutput, setTextOutput] = useState(false);
const [gridOutput, setGridOutput] = useState(false);
+ const [userTheme, setUserTheme] = useState('light');
+ const [coordinatesVisible, setCoordinatesVisible] = useState(false);
+ const [sketchReloaded, setSketchReloaded] = useState(0);
+
registerFrame(window.parent, getConfig('EDITOR_URL'));
function handleMessageEvent(message) {
@@ -34,12 +40,16 @@ const App = () => {
setBasePath(payload.basePath);
setTextOutput(payload.textOutput);
setGridOutput(payload.gridOutput);
+ setUserTheme(payload.userTheme);
+ setCoordinatesVisible(payload.coordinates);
+ setSketchReloaded((prev) => prev + 1);
break;
case MessageTypes.START:
setIsPlaying(true);
break;
case MessageTypes.STOP:
setIsPlaying(false);
+ setCoordinatesVisible(false);
break;
case MessageTypes.REGISTER:
dispatchMessage({ type: MessageTypes.REGISTER });
@@ -47,6 +57,9 @@ const App = () => {
case MessageTypes.EXECUTE:
dispatchMessage(payload);
break;
+ case MessageTypes.COORDINATES_VISIBILITY:
+ if (isPlaying) setCoordinatesVisible(payload);
+ break;
default:
break;
}
@@ -65,23 +78,35 @@ const App = () => {
});
}
+ const memoizedFiles = useMemo(() => addCacheBustingToAssets(state), [
+ state,
+ addCacheBustingToAssets
+ ]);
+
useEffect(() => {
const unsubscribe = listen(handleMessageEvent);
return function cleanup() {
unsubscribe();
};
- });
+ }, []);
+
return (
-
+
+ {coordinatesVisible && (
+
+ )}
-
+
);
};
diff --git a/client/testData/testServerResponses.js b/client/testData/testServerResponses.js
index 9675b005b6..d8b240719e 100644
--- a/client/testData/testServerResponses.js
+++ b/client/testData/testServerResponses.js
@@ -19,7 +19,8 @@ export const userResponse = {
autorefresh: false,
language: 'en-US',
autocloseBracketsQuotes: true,
- autocompleteHinter: false
+ autocompleteHinter: false,
+ coordinates: false
},
apiKeys: [],
verified: 'verified',
diff --git a/client/utils/dispatcher.js b/client/utils/dispatcher.js
index 49393121ac..0eb83ebef7 100644
--- a/client/utils/dispatcher.js
+++ b/client/utils/dispatcher.js
@@ -11,7 +11,9 @@ export const MessageTypes = {
FILES: 'FILES',
SKETCH: 'SKETCH',
REGISTER: 'REGISTER',
- EXECUTE: 'EXECUTE'
+ EXECUTE: 'EXECUTE',
+ COORDINATES: 'COORDINATES',
+ COORDINATES_VISIBILITY: 'COORDINATES_VISIBILITY'
};
export function registerFrame(newFrame, newOrigin) {
diff --git a/server/models/user.js b/server/models/user.js
index b825971747..ccee359764 100644
--- a/server/models/user.js
+++ b/server/models/user.js
@@ -74,7 +74,8 @@ const userSchema = new Schema(
autorefresh: { type: Boolean, default: false },
language: { type: String, default: 'en-US' },
autocloseBracketsQuotes: { type: Boolean, default: true },
- autocompleteHinter: { type: Boolean, default: false }
+ autocompleteHinter: { type: Boolean, default: false },
+ coordinates: { type: Boolean, default: false }
},
totalSize: { type: Number, default: 0 },
cookieConsent: {
diff --git a/translations/locales/en-US/translations.json b/translations/locales/en-US/translations.json
index 59e6bcbaad..129ceefaa5 100644
--- a/translations/locales/en-US/translations.json
+++ b/translations/locales/en-US/translations.json
@@ -203,6 +203,9 @@
"WordWrap": "Word Wrap",
"LineWrapOnARIA": "linewrap on",
"LineWrapOffARIA": "linewrap off",
+ "Coordinates": "Coordinates",
+ "CoordinatesOnARIA": "coordinates on",
+ "CoordinatesOffARIA": "coordinates off",
"LineNumbers": "Line numbers",
"LineNumbersOnARIA": "line numbers on",
"LineNumbersOffARIA": "line numbers off",