Browse Source

chore: Remove tracking (#2722)

* chore: Remove tracking

* process

* rename

* remove

* prod

* Update public/index.html

Co-authored-by: David Luzar <luzar.david@gmail.com>

* Update public/index.html

* eol

* more

* stats

Co-authored-by: David Luzar <luzar.david@gmail.com>
vanilla_orig
Lipis 4 years ago
parent
commit
3aa01ad272
No account linked to committer's email address

+ 1
- 1
.env.production View File

@@ -1 +1 @@
1
-REACT_APP_INCLUDE_GTAG=true
1
+REACT_APP_GOOGLE_ANALYTICS_ID=UA-387204-13

+ 0
- 1
Dockerfile View File

@@ -5,7 +5,6 @@ WORKDIR /opt/node_app
5 5
 COPY package.json package-lock.json ./
6 6
 RUN npm i --no-optional
7 7
 
8
-ARG REACT_APP_INCLUDE_GTAG=false
9 8
 ARG NODE_ENV=production
10 9
 
11 10
 COPY . .

+ 0
- 64
analytics.md View File

@@ -1,64 +0,0 @@
1
-| Excalidraw              | Category | Name                               | Label                           | Value     |
2
-| ----------------------- | -------- | ---------------------------------- | ------------------------------- | --------- |
3
-| Shape / Selection       | shape    | selection, rectangle, diamond, etc | `toolbar` or `shortcut`         |
4
-| Text on double click    | shape    | text                               | `double-click`                  |
5
-| Lock selection          | shape    | lock                               | `on` or `off`                   |
6
-| Clear canvas            | action   | clear canvas                       |
7
-| Zoom in                 | action   | zoom                               | in                              | `zoom`    |
8
-| Zoom out                | action   | zoom                               | out                             | `zoom`    |
9
-| Zoom fit                | action   | zoom                               | fit                             | `zoom`    |
10
-| Zoom reset              | action   | zoom                               | reset                           | `zoom`    |
11
-| Scroll back to content  | action   | scroll to content                  |
12
-| Load file               | io       | load                               | `MIME type`                     |
13
-| Import from URL         | io       | import                             |
14
-| Save                    | io       | save                               |
15
-| Save as                 | io       | save as                            |
16
-| Export to backend       | io       | export                             | backend                         |
17
-| Export as SVG           | io       | export                             | `svg` or `clipboard-svg`        |
18
-| Export to PNG           | io       | export                             | `png` or `clipboard-png`        |
19
-| Canvas color            | change   | canvas color                       | `color`                         |
20
-| Background color        | change   | background color                   | `color`                         |
21
-| Stroke color            | change   | stroke color                       | `color`                         |
22
-| Stroke width            | change   | stroke                             | width                           | `width`   |
23
-| Stroke style            | change   | style                              | `solid` or `dashed` or `dotted` |
24
-| Stroke sloppiness       | change   | stroke                             | sloppiness                      | `value`   |
25
-| Fill                    | change   | fill                               | `value`                         |
26
-| Edge                    | change   | edge                               | `value`                         |
27
-| Opacity                 | change   | opacity                            | value                           | `opacity` |
28
-| Project name            | change   | title                              |
29
-| Theme                   | change   | theme                              | `light` or `dark`               |
30
-| Change language         | change   | language                           | `language`                      |
31
-| Send to back            | layer    | move                               | `back`                          |
32
-| Send backward           | layer    | move                               | `down`                          |
33
-| Bring to front          | layer    | move                               | `front`                         |
34
-| Bring forward           | layer    | move                               | `up`                            |
35
-| Align left              | align    | align                              | `left`                          |
36
-| Align right             | align    | align                              | `right`                         |
37
-| Align top               | align    | align                              | `top`                           |
38
-| Align bottom            | align    | align                              | `bottom`                        |
39
-| Center horizontally     | align    | horizontally                       | `center`                        |
40
-| Center vertically       | align    | vertically                         | `center`                        |
41
-| Distribute horizontally | align    | distribute                         | `horizontally`                  |
42
-| Distribute vertically   | align    | distribute                         | `vertically`                    |
43
-| Start session           | share    | session start                      |
44
-| Join session            | share    | session join                       |
45
-| Start end               | share    | session end                        |
46
-| Copy room link          | share    | copy link                          |
47
-| Go to collaborator      | share    | go to collaborator                 |
48
-| Change name             | share    | name                               |
49
-| Add to library          | library  | add                                |
50
-| Remove from library     | library  | remove                             |
51
-| Load library            | library  | load                               |
52
-| Save library            | library  | save                               |
53
-| Import library          | library  | import                             |
54
-| Shortcuts dialog        | dialog   | shortcuts                          |
55
-| Collaboration dialog    | dialog   | collaboration                      |
56
-| Export dialog           | dialog   | export                             |
57
-| Library dialog          | dialog   | library                            |
58
-| E2EE shield             | exit     | e2ee shield                        |
59
-| GitHub corner           | exit     | github                             |
60
-| Excalidraw blog         | exit     | blog                               |
61
-| Excalidraw guides       | exit     | guides                             |
62
-| File issues             | exit     | issues                             |
63
-| First load              | load     | first load                         |
64
-| Load from stroage       | load     | storage                            | size                            | `bytes`   |

+ 2
- 2
package.json View File

@@ -81,8 +81,8 @@
81 81
   "private": true,
82 82
   "scripts": {
83 83
     "build-node": "node ./scripts/build-node.js",
84
-    "build:app:docker": "REACT_APP_INCLUDE_GTAG=false REACT_APP_DISABLE_SENTRY=true react-scripts build",
85
-    "build:app": "REACT_APP_INCLUDE_GTAG=true REACT_APP_GIT_SHA=$NOW_GITHUB_COMMIT_SHA react-scripts build",
84
+    "build:app:docker": "REACT_APP_DISABLE_SENTRY=true react-scripts build",
85
+    "build:app": "REACT_APP_GIT_SHA=$NOW_GITHUB_COMMIT_SHA react-scripts build",
86 86
     "build:version": "node ./scripts/build-version.js",
87 87
     "build": "npm run build:app && npm run build:version",
88 88
     "eject": "react-scripts eject",

+ 3
- 3
public/index.html View File

@@ -86,10 +86,10 @@
86 86
 
87 87
     <link rel="stylesheet" href="fonts.css" type="text/css" />
88 88
 
89
-    <% if (process.env.REACT_APP_INCLUDE_GTAG === 'true') { %>
89
+    <% if (process.env.REACT_APP_GOOGLE_ANALYTICS_ID) { %>
90 90
     <script
91 91
       async
92
-      src="https://www.googletagmanager.com/gtag/js?id=UA-387204-13"
92
+      src="https://www.googletagmanager.com/gtag/js?id=%REACT_APP_GOOGLE_ANALYTICS_ID%"
93 93
     ></script>
94 94
     <script>
95 95
       window.dataLayer = window.dataLayer || [];
@@ -97,7 +97,7 @@
97 97
         dataLayer.push(arguments);
98 98
       }
99 99
       gtag("js", new Date());
100
-      gtag("config", "UA-387204-13");
100
+      gtag("config", "%REACT_APP_GOOGLE_ANALYTICS_ID%");
101 101
     </script>
102 102
     <% } %>
103 103
 

+ 0
- 2
src/actions/actionAddToLibrary.ts View File

@@ -3,7 +3,6 @@ import { getSelectedElements } from "../scene";
3 3
 import { getNonDeletedElements } from "../element";
4 4
 import { deepCopyElement } from "../element/newElement";
5 5
 import { Library } from "../data/library";
6
-import { EVENT_LIBRARY, trackEvent } from "../analytics";
7 6
 
8 7
 export const actionAddToLibrary = register({
9 8
   name: "addToLibrary",
@@ -16,7 +15,6 @@ export const actionAddToLibrary = register({
16 15
     Library.loadLibrary().then((items) => {
17 16
       Library.saveLibrary([...items, selectedElements.map(deepCopyElement)]);
18 17
     });
19
-    trackEvent(EVENT_LIBRARY, "add");
20 18
     return false;
21 19
   },
22 20
   contextMenuOrder: 6,

+ 6
- 13
src/actions/actionAlign.tsx View File

@@ -1,7 +1,5 @@
1 1
 import React from "react";
2
-import { KEYS } from "../keys";
3
-import { t } from "../i18n";
4
-import { register } from "./register";
2
+import { alignElements, Alignment } from "../align";
5 3
 import {
6 4
   AlignBottomIcon,
7 5
   AlignLeftIcon,
@@ -10,14 +8,15 @@ import {
10 8
   CenterHorizontallyIcon,
11 9
   CenterVerticallyIcon,
12 10
 } from "../components/icons";
13
-import { getSelectedElements, isSomeElementSelected } from "../scene";
14
-import { getElementMap, getNonDeletedElements } from "../element";
15 11
 import { ToolButton } from "../components/ToolButton";
12
+import { getElementMap, getNonDeletedElements } from "../element";
16 13
 import { ExcalidrawElement } from "../element/types";
14
+import { t } from "../i18n";
15
+import { KEYS } from "../keys";
16
+import { getSelectedElements, isSomeElementSelected } from "../scene";
17 17
 import { AppState } from "../types";
18
-import { alignElements, Alignment } from "../align";
19 18
 import { getShortcutKey } from "../utils";
20
-import { trackEvent, EVENT_ALIGN } from "../analytics";
19
+import { register } from "./register";
21 20
 
22 21
 const enableActionGroup = (
23 22
   elements: readonly ExcalidrawElement[],
@@ -44,7 +43,6 @@ const alignSelectedElements = (
44 43
 export const actionAlignTop = register({
45 44
   name: "alignTop",
46 45
   perform: (elements, appState) => {
47
-    trackEvent(EVENT_ALIGN, "align", "top");
48 46
     return {
49 47
       appState,
50 48
       elements: alignSelectedElements(elements, appState, {
@@ -74,7 +72,6 @@ export const actionAlignTop = register({
74 72
 export const actionAlignBottom = register({
75 73
   name: "alignBottom",
76 74
   perform: (elements, appState) => {
77
-    trackEvent(EVENT_ALIGN, "align", "bottom");
78 75
     return {
79 76
       appState,
80 77
       elements: alignSelectedElements(elements, appState, {
@@ -104,7 +101,6 @@ export const actionAlignBottom = register({
104 101
 export const actionAlignLeft = register({
105 102
   name: "alignLeft",
106 103
   perform: (elements, appState) => {
107
-    trackEvent(EVENT_ALIGN, "align", "left");
108 104
     return {
109 105
       appState,
110 106
       elements: alignSelectedElements(elements, appState, {
@@ -134,7 +130,6 @@ export const actionAlignLeft = register({
134 130
 export const actionAlignRight = register({
135 131
   name: "alignRight",
136 132
   perform: (elements, appState) => {
137
-    trackEvent(EVENT_ALIGN, "align", "right");
138 133
     return {
139 134
       appState,
140 135
       elements: alignSelectedElements(elements, appState, {
@@ -164,7 +159,6 @@ export const actionAlignRight = register({
164 159
 export const actionAlignVerticallyCentered = register({
165 160
   name: "alignVerticallyCentered",
166 161
   perform: (elements, appState) => {
167
-    trackEvent(EVENT_ALIGN, "vertically", "center");
168 162
     return {
169 163
       appState,
170 164
       elements: alignSelectedElements(elements, appState, {
@@ -190,7 +184,6 @@ export const actionAlignVerticallyCentered = register({
190 184
 export const actionAlignHorizontallyCentered = register({
191 185
   name: "alignHorizontallyCentered",
192 186
   perform: (elements, appState) => {
193
-    trackEvent(EVENT_ALIGN, "horizontally", "center");
194 187
     return {
195 188
       appState,
196 189
       elements: alignSelectedElements(elements, appState, {

+ 0
- 17
src/actions/actionCanvas.tsx View File

@@ -1,7 +1,5 @@
1 1
 import React from "react";
2
-import { EVENT_ACTION, EVENT_CHANGE, trackEvent } from "../analytics";
3 2
 import { getDefaultAppState } from "../appState";
4
-import colors from "../colors";
5 3
 import { ColorPicker } from "../components/ColorPicker";
6 4
 import { resetZoom, trash, zoomIn, zoomOut } from "../components/icons";
7 5
 import { ToolButton } from "../components/ToolButton";
@@ -21,15 +19,6 @@ import { register } from "./register";
21 19
 export const actionChangeViewBackgroundColor = register({
22 20
   name: "changeViewBackgroundColor",
23 21
   perform: (_, appState, value) => {
24
-    if (value !== appState.viewBackgroundColor) {
25
-      trackEvent(
26
-        EVENT_CHANGE,
27
-        "canvas color",
28
-        colors.canvasBackground.includes(value)
29
-          ? `${value} (picker ${colors.canvasBackground.indexOf(value)})`
30
-          : value,
31
-      );
32
-    }
33 22
     return {
34 23
       appState: { ...appState, viewBackgroundColor: value },
35 24
       commitToHistory: true,
@@ -52,7 +41,6 @@ export const actionChangeViewBackgroundColor = register({
52 41
 export const actionClearCanvas = register({
53 42
   name: "clearCanvas",
54 43
   perform: (elements, appState: AppState) => {
55
-    trackEvent(EVENT_ACTION, "clear canvas");
56 44
     return {
57 45
       elements: elements.map((element) =>
58 46
         newElementWith(element, { isDeleted: true }),
@@ -98,7 +86,6 @@ export const actionZoomIn = register({
98 86
       { left: appState.offsetLeft, top: appState.offsetTop },
99 87
       { x: appState.width / 2, y: appState.height / 2 },
100 88
     );
101
-    trackEvent(EVENT_ACTION, "zoom", "in", zoom.value * 100);
102 89
     return {
103 90
       appState: {
104 91
         ...appState,
@@ -133,7 +120,6 @@ export const actionZoomOut = register({
133 120
       { x: appState.width / 2, y: appState.height / 2 },
134 121
     );
135 122
 
136
-    trackEvent(EVENT_ACTION, "zoom", "out", zoom.value * 100);
137 123
     return {
138 124
       appState: {
139 125
         ...appState,
@@ -161,7 +147,6 @@ export const actionZoomOut = register({
161 147
 export const actionResetZoom = register({
162 148
   name: "resetZoom",
163 149
   perform: (_elements, appState) => {
164
-    trackEvent(EVENT_ACTION, "zoom", "reset", 100);
165 150
     return {
166 151
       appState: {
167 152
         ...appState,
@@ -234,12 +219,10 @@ const zoomToFitElements = (
234 219
     left: appState.offsetLeft,
235 220
     top: appState.offsetTop,
236 221
   });
237
-  const action = zoomToSelection ? "selection" : "fit";
238 222
 
239 223
   const [x1, y1, x2, y2] = commonBounds;
240 224
   const centerX = (x1 + x2) / 2;
241 225
   const centerY = (y1 + y2) / 2;
242
-  trackEvent(EVENT_ACTION, "zoom", action, newZoom.value * 100);
243 226
   return {
244 227
     appState: {
245 228
       ...appState,

+ 6
- 9
src/actions/actionDistribute.tsx View File

@@ -1,19 +1,18 @@
1 1
 import React from "react";
2
-import { CODES } from "../keys";
3
-import { t } from "../i18n";
4
-import { register } from "./register";
5 2
 import {
6 3
   DistributeHorizontallyIcon,
7 4
   DistributeVerticallyIcon,
8 5
 } from "../components/icons";
9
-import { getSelectedElements, isSomeElementSelected } from "../scene";
10
-import { getElementMap, getNonDeletedElements } from "../element";
11 6
 import { ToolButton } from "../components/ToolButton";
7
+import { distributeElements, Distribution } from "../disitrubte";
8
+import { getElementMap, getNonDeletedElements } from "../element";
12 9
 import { ExcalidrawElement } from "../element/types";
10
+import { t } from "../i18n";
11
+import { CODES } from "../keys";
12
+import { getSelectedElements, isSomeElementSelected } from "../scene";
13 13
 import { AppState } from "../types";
14
-import { distributeElements, Distribution } from "../disitrubte";
15 14
 import { getShortcutKey } from "../utils";
16
-import { EVENT_ALIGN, trackEvent } from "../analytics";
15
+import { register } from "./register";
17 16
 
18 17
 const enableActionGroup = (
19 18
   elements: readonly ExcalidrawElement[],
@@ -40,7 +39,6 @@ const distributeSelectedElements = (
40 39
 export const distributeHorizontally = register({
41 40
   name: "distributeHorizontally",
42 41
   perform: (elements, appState) => {
43
-    trackEvent(EVENT_ALIGN, "distribute", "horizontally");
44 42
     return {
45 43
       appState,
46 44
       elements: distributeSelectedElements(elements, appState, {
@@ -69,7 +67,6 @@ export const distributeHorizontally = register({
69 67
 export const distributeVertically = register({
70 68
   name: "distributeVertically",
71 69
   perform: (elements, appState) => {
72
-    trackEvent(EVENT_ALIGN, "distribute", "vertically");
73 70
     return {
74 71
       appState,
75 72
       elements: distributeSelectedElements(elements, appState, {

+ 4
- 7
src/actions/actionExport.tsx View File

@@ -1,22 +1,21 @@
1 1
 import React from "react";
2
-import { EVENT_CHANGE, EVENT_IO, trackEvent } from "../analytics";
3
-import { load, save, saveAs } from "../components/icons";
2
+import { trackEvent } from "../analytics";
3
+import { load, questionCircle, save, saveAs } from "../components/icons";
4 4
 import { ProjectName } from "../components/ProjectName";
5 5
 import { ToolButton } from "../components/ToolButton";
6
+import "../components/ToolIcon.scss";
6 7
 import { Tooltip } from "../components/Tooltip";
7
-import { questionCircle } from "../components/icons";
8 8
 import { loadFromJSON, saveAsJSON } from "../data";
9 9
 import { t } from "../i18n";
10 10
 import useIsMobile from "../is-mobile";
11 11
 import { KEYS } from "../keys";
12 12
 import { muteFSAbortError } from "../utils";
13 13
 import { register } from "./register";
14
-import "../components/ToolIcon.scss";
15 14
 
16 15
 export const actionChangeProjectName = register({
17 16
   name: "changeProjectName",
18 17
   perform: (_elements, appState, value) => {
19
-    trackEvent(EVENT_CHANGE, "title");
18
+    trackEvent("change", "title");
20 19
     return { appState: { ...appState, name: value }, commitToHistory: false };
21 20
   },
22 21
   PanelComponent: ({ appState, updateData }) => (
@@ -100,7 +99,6 @@ export const actionSaveScene = register({
100 99
   perform: async (elements, appState, value) => {
101 100
     try {
102 101
       const { fileHandle } = await saveAsJSON(elements, appState);
103
-      trackEvent(EVENT_IO, "save");
104 102
       return { commitToHistory: false, appState: { ...appState, fileHandle } };
105 103
     } catch (error) {
106 104
       if (error?.name !== "AbortError") {
@@ -131,7 +129,6 @@ export const actionSaveAsScene = register({
131 129
         ...appState,
132 130
         fileHandle: null,
133 131
       });
134
-      trackEvent(EVENT_IO, "save as");
135 132
       return { commitToHistory: false, appState: { ...appState, fileHandle } };
136 133
     } catch (error) {
137 134
       if (error?.name !== "AbortError") {

+ 0
- 2
src/actions/actionMenu.tsx View File

@@ -7,7 +7,6 @@ import { register } from "./register";
7 7
 import { allowFullScreen, exitFullScreen, isFullScreen } from "../utils";
8 8
 import { CODES, KEYS } from "../keys";
9 9
 import { HelpIcon } from "../components/HelpIcon";
10
-import { EVENT_DIALOG, trackEvent } from "../analytics";
11 10
 
12 11
 export const actionToggleCanvasMenu = register({
13 12
   name: "toggleCanvasMenu",
@@ -72,7 +71,6 @@ export const actionFullScreen = register({
72 71
 export const actionShortcuts = register({
73 72
   name: "toggleShortcuts",
74 73
   perform: (_elements, appState) => {
75
-    trackEvent(EVENT_DIALOG, "shortcuts");
76 74
     return {
77 75
       appState: {
78 76
         ...appState,

+ 3
- 5
src/actions/actionNavigate.tsx View File

@@ -1,16 +1,14 @@
1 1
 import React from "react";
2
-import { Avatar } from "../components/Avatar";
3
-import { register } from "./register";
4 2
 import { getClientColors, getClientInitials } from "../clients";
5
-import { Collaborator } from "../types";
3
+import { Avatar } from "../components/Avatar";
6 4
 import { centerScrollOn } from "../scene/scroll";
7
-import { EVENT_SHARE, trackEvent } from "../analytics";
5
+import { Collaborator } from "../types";
6
+import { register } from "./register";
8 7
 
9 8
 export const actionGoToCollaborator = register({
10 9
   name: "goToCollaborator",
11 10
   perform: (_elements, appState, value) => {
12 11
     const point = value as Collaborator["pointer"];
13
-    trackEvent(EVENT_SHARE, "go to collaborator");
14 12
     if (!point) {
15 13
       return { appState, commitToHistory: false };
16 14
     }

+ 39
- 73
src/actions/actionProperties.tsx View File

@@ -1,56 +1,53 @@
1 1
 import React from "react";
2
-import { getLanguage } from "../i18n";
2
+import { AppState } from "../../src/types";
3
+import { ButtonIconSelect } from "../components/ButtonIconSelect";
4
+import { ButtonSelect } from "../components/ButtonSelect";
5
+import { ColorPicker } from "../components/ColorPicker";
6
+import { IconPicker } from "../components/IconPicker";
3 7
 import {
8
+  ArrowheadArrowIcon,
9
+  ArrowheadBarIcon,
10
+  ArrowheadDotIcon,
11
+  ArrowheadNoneIcon,
12
+  EdgeRoundIcon,
13
+  EdgeSharpIcon,
14
+  FillCrossHatchIcon,
15
+  FillHachureIcon,
16
+  FillSolidIcon,
17
+  SloppinessArchitectIcon,
18
+  SloppinessArtistIcon,
19
+  SloppinessCartoonistIcon,
20
+  StrokeStyleDashedIcon,
21
+  StrokeStyleDottedIcon,
22
+  StrokeStyleSolidIcon,
23
+  StrokeWidthIcon,
24
+} from "../components/icons";
25
+import { DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE } from "../constants";
26
+import {
27
+  getNonDeletedElements,
28
+  isTextElement,
29
+  redrawTextBoundingBox,
30
+} from "../element";
31
+import { newElementWith } from "../element/mutateElement";
32
+import { isLinearElement, isLinearElementType } from "../element/typeChecks";
33
+import {
34
+  Arrowhead,
4 35
   ExcalidrawElement,
36
+  ExcalidrawLinearElement,
5 37
   ExcalidrawTextElement,
6
-  TextAlign,
7 38
   FontFamily,
8
-  ExcalidrawLinearElement,
9
-  Arrowhead,
39
+  TextAlign,
10 40
 } from "../element/types";
41
+import { getLanguage, t } from "../i18n";
42
+import { randomInteger } from "../random";
11 43
 import {
12
-  getCommonAttributeOfSelectedElements,
13
-  isSomeElementSelected,
14
-  getTargetElements,
15 44
   canChangeSharpness,
16 45
   canHaveArrowheads,
46
+  getCommonAttributeOfSelectedElements,
47
+  getTargetElements,
48
+  isSomeElementSelected,
17 49
 } from "../scene";
18
-import { ButtonSelect } from "../components/ButtonSelect";
19
-import { ButtonIconSelect } from "../components/ButtonIconSelect";
20
-import { IconPicker } from "../components/IconPicker";
21
-import {
22
-  isTextElement,
23
-  redrawTextBoundingBox,
24
-  getNonDeletedElements,
25
-} from "../element";
26
-import { isLinearElement, isLinearElementType } from "../element/typeChecks";
27
-import { ColorPicker } from "../components/ColorPicker";
28
-import { AppState } from "../../src/types";
29
-import { t } from "../i18n";
30 50
 import { register } from "./register";
31
-import { newElementWith } from "../element/mutateElement";
32
-import { DEFAULT_FONT_SIZE, DEFAULT_FONT_FAMILY } from "../constants";
33
-import { randomInteger } from "../random";
34
-import {
35
-  FillHachureIcon,
36
-  FillCrossHatchIcon,
37
-  FillSolidIcon,
38
-  StrokeWidthIcon,
39
-  StrokeStyleSolidIcon,
40
-  StrokeStyleDashedIcon,
41
-  StrokeStyleDottedIcon,
42
-  EdgeSharpIcon,
43
-  EdgeRoundIcon,
44
-  SloppinessArchitectIcon,
45
-  SloppinessArtistIcon,
46
-  SloppinessCartoonistIcon,
47
-  ArrowheadArrowIcon,
48
-  ArrowheadBarIcon,
49
-  ArrowheadDotIcon,
50
-  ArrowheadNoneIcon,
51
-} from "../components/icons";
52
-import { EVENT_CHANGE, trackEvent } from "../analytics";
53
-import colors from "../colors";
54 51
 
55 52
 const changeProperty = (
56 53
   elements: readonly ExcalidrawElement[],
@@ -92,15 +89,6 @@ const getFormValue = function <T>(
92 89
 export const actionChangeStrokeColor = register({
93 90
   name: "changeStrokeColor",
94 91
   perform: (elements, appState, value) => {
95
-    if (value !== appState.currentItemStrokeColor) {
96
-      trackEvent(
97
-        EVENT_CHANGE,
98
-        "stroke color",
99
-        colors.elementStroke.includes(value)
100
-          ? `${value} (picker ${colors.elementStroke.indexOf(value)})`
101
-          : value,
102
-      );
103
-    }
104 92
     return {
105 93
       elements: changeProperty(elements, appState, (el) =>
106 94
         newElementWith(el, {
@@ -132,16 +120,6 @@ export const actionChangeStrokeColor = register({
132 120
 export const actionChangeBackgroundColor = register({
133 121
   name: "changeBackgroundColor",
134 122
   perform: (elements, appState, value) => {
135
-    if (value !== appState.currentItemBackgroundColor) {
136
-      trackEvent(
137
-        EVENT_CHANGE,
138
-        "background color",
139
-        colors.elementBackground.includes(value)
140
-          ? `${value} (picker ${colors.elementBackground.indexOf(value)})`
141
-          : value,
142
-      );
143
-    }
144
-
145 123
     return {
146 124
       elements: changeProperty(elements, appState, (el) =>
147 125
         newElementWith(el, {
@@ -173,7 +151,6 @@ export const actionChangeBackgroundColor = register({
173 151
 export const actionChangeFillStyle = register({
174 152
   name: "changeFillStyle",
175 153
   perform: (elements, appState, value) => {
176
-    trackEvent(EVENT_CHANGE, "fill", value);
177 154
     return {
178 155
       elements: changeProperty(elements, appState, (el) =>
179 156
         newElementWith(el, {
@@ -223,7 +200,6 @@ export const actionChangeFillStyle = register({
223 200
 export const actionChangeStrokeWidth = register({
224 201
   name: "changeStrokeWidth",
225 202
   perform: (elements, appState, value) => {
226
-    trackEvent(EVENT_CHANGE, "stroke", "width", value);
227 203
     return {
228 204
       elements: changeProperty(elements, appState, (el) =>
229 205
         newElementWith(el, {
@@ -286,7 +262,6 @@ export const actionChangeStrokeWidth = register({
286 262
 export const actionChangeSloppiness = register({
287 263
   name: "changeSloppiness",
288 264
   perform: (elements, appState, value) => {
289
-    trackEvent(EVENT_CHANGE, "stroke", "sloppiness", value);
290 265
     return {
291 266
       elements: changeProperty(elements, appState, (el) =>
292 267
         newElementWith(el, {
@@ -335,7 +310,6 @@ export const actionChangeSloppiness = register({
335 310
 export const actionChangeStrokeStyle = register({
336 311
   name: "changeStrokeStyle",
337 312
   perform: (elements, appState, value) => {
338
-    trackEvent(EVENT_CHANGE, "style", value);
339 313
     return {
340 314
       elements: changeProperty(elements, appState, (el) =>
341 315
         newElementWith(el, {
@@ -383,7 +357,6 @@ export const actionChangeStrokeStyle = register({
383 357
 export const actionChangeOpacity = register({
384 358
   name: "changeOpacity",
385 359
   perform: (elements, appState, value) => {
386
-    trackEvent(EVENT_CHANGE, "opacity", "value", value);
387 360
     return {
388 361
       elements: changeProperty(elements, appState, (el) =>
389 362
         newElementWith(el, {
@@ -580,7 +553,6 @@ export const actionChangeSharpness = register({
580 553
     const shouldUpdateForLinearElements = targetElements.length
581 554
       ? targetElements.every(isLinearElement)
582 555
       : isLinearElementType(appState.elementType);
583
-    trackEvent(EVENT_CHANGE, "edge", value);
584 556
     return {
585 557
       elements: changeProperty(elements, appState, (el) =>
586 558
         newElementWith(el, {
@@ -642,12 +614,6 @@ export const actionChangeArrowhead = register({
642 614
     return {
643 615
       elements: changeProperty(elements, appState, (el) => {
644 616
         if (isLinearElement(el)) {
645
-          trackEvent(
646
-            EVENT_CHANGE,
647
-            `arrowhead ${value.position}`,
648
-            value.type || "none",
649
-          );
650
-
651 617
           const { position, type } = value;
652 618
 
653 619
           if (position === "start") {

+ 5
- 15
src/analytics.ts View File

@@ -1,18 +1,7 @@
1
-export const EVENT_ACTION = "action";
2
-export const EVENT_ALIGN = "align";
3
-export const EVENT_CHANGE = "change";
4
-export const EVENT_DIALOG = "dialog";
5
-export const EVENT_EXIT = "exit";
6
-export const EVENT_IO = "io";
7
-export const EVENT_LAYER = "layer";
8
-export const EVENT_LIBRARY = "library";
9
-export const EVENT_LOAD = "load";
10
-export const EVENT_SHAPE = "shape";
11
-export const EVENT_SHARE = "share";
12
-export const EVENT_MAGIC = "magic";
13
-
14 1
 export const trackEvent =
15
-  typeof window !== "undefined" && window.gtag
2
+  process.env.REACT_APP_GOOGLE_ANALYTICS_ID &&
3
+  typeof window !== "undefined" &&
4
+  window.gtag
16 5
     ? (category: string, name: string, label?: string, value?: number) => {
17 6
         window.gtag("event", name, {
18 7
           event_category: category,
@@ -23,5 +12,6 @@ export const trackEvent =
23 12
     : typeof process !== "undefined" && process?.env?.JEST_WORKER_ID
24 13
     ? (category: string, name: string, label?: string, value?: number) => {}
25 14
     : (category: string, name: string, label?: string, value?: number) => {
26
-        console.info("Track Event", category, name, label, value);
15
+        // Uncomment the next line to track locally
16
+        // console.info("Track Event", category, name, label, value);
27 17
       };

+ 2
- 2
src/charts.ts View File

@@ -1,4 +1,4 @@
1
-import { EVENT_MAGIC, trackEvent } from "./analytics";
1
+import { trackEvent } from "./analytics";
2 2
 import colors from "./colors";
3 3
 import { DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE, ENV } from "./constants";
4 4
 import { newElement, newLinearElement, newTextElement } from "./element";
@@ -473,7 +473,7 @@ export const renderSpreadsheet = (
473 473
   x: number,
474 474
   y: number,
475 475
 ): ChartElements => {
476
-  trackEvent(EVENT_MAGIC, "chart", chartType, spreadsheet.values.length);
476
+  trackEvent("magic", "chart", chartType, spreadsheet.values.length);
477 477
   if (chartType === "line") {
478 478
     return chartTypeLine(spreadsheet, x, y);
479 479
   }

+ 9
- 14
src/components/Actions.tsx View File

@@ -1,23 +1,22 @@
1 1
 import React from "react";
2
-import { AppState, Zoom } from "../types";
3
-import { ExcalidrawElement } from "../element/types";
4 2
 import { ActionManager } from "../actions/manager";
3
+import { getNonDeletedElements } from "../element";
4
+import { ExcalidrawElement } from "../element/types";
5
+import { t } from "../i18n";
6
+import useIsMobile from "../is-mobile";
5 7
 import {
6
-  hasBackground,
7
-  hasStroke,
8 8
   canChangeSharpness,
9
-  hasText,
10 9
   canHaveArrowheads,
11 10
   getTargetElements,
11
+  hasBackground,
12
+  hasStroke,
13
+  hasText,
12 14
 } from "../scene";
13
-import { t } from "../i18n";
14 15
 import { SHAPES } from "../shapes";
15
-import { ToolButton } from "./ToolButton";
16
+import { AppState, Zoom } from "../types";
16 17
 import { capitalizeString, isTransparent, setCursorForShape } from "../utils";
17 18
 import Stack from "./Stack";
18
-import useIsMobile from "../is-mobile";
19
-import { getNonDeletedElements } from "../element";
20
-import { trackEvent, EVENT_SHAPE, EVENT_DIALOG } from "../analytics";
19
+import { ToolButton } from "./ToolButton";
21 20
 
22 21
 export const SelectedShapeActions = ({
23 22
   appState,
@@ -181,7 +180,6 @@ export const ShapesSwitcher = ({
181 180
           aria-keyshortcuts={shortcut}
182 181
           data-testid={value}
183 182
           onChange={() => {
184
-            trackEvent(EVENT_SHAPE, value, "toolbar");
185 183
             setAppState({
186 184
               elementType: value,
187 185
               multiElement: null,
@@ -203,9 +201,6 @@ export const ShapesSwitcher = ({
203 201
       title={`${capitalizeString(t("toolBar.library"))} — 9`}
204 202
       aria-label={capitalizeString(t("toolBar.library"))}
205 203
       onClick={() => {
206
-        if (!isLibraryOpen) {
207
-          trackEvent(EVENT_DIALOG, "library");
208
-        }
209 204
         setAppState({ isLibraryOpen: !isLibraryOpen });
210 205
       }}
211 206
     />

+ 3
- 15
src/components/App.tsx View File

@@ -8,12 +8,7 @@ import { createRedoAction, createUndoAction } from "../actions/actionHistory";
8 8
 import { ActionManager } from "../actions/manager";
9 9
 import { actions } from "../actions/register";
10 10
 import { ActionResult } from "../actions/types";
11
-import {
12
-  EVENT_DIALOG,
13
-  EVENT_LIBRARY,
14
-  EVENT_SHAPE,
15
-  trackEvent,
16
-} from "../analytics";
11
+import { trackEvent } from "../analytics";
17 12
 import { getDefaultAppState } from "../appState";
18 13
 import {
19 14
   copyToClipboard,
@@ -111,7 +106,7 @@ import {
111 106
   selectGroupsForSelectedElements,
112 107
 } from "../groups";
113 108
 import { createHistory, SceneHistory } from "../history";
114
-import { t, getLanguage, setLanguage, languages, defaultLang } from "../i18n";
109
+import { defaultLang, getLanguage, languages, setLanguage, t } from "../i18n";
115 110
 import {
116 111
   CODES,
117 112
   getResizeCenterPointKey,
@@ -504,7 +499,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
504 499
         )
505 500
       ) {
506 501
         await Library.importLibrary(blob);
507
-        trackEvent(EVENT_LIBRARY, "import");
508 502
         this.setState({
509 503
           isLibraryOpen: true,
510 504
         });
@@ -1134,7 +1128,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
1134 1128
 
1135 1129
   toggleLock = () => {
1136 1130
     this.setState((prevState) => {
1137
-      trackEvent(EVENT_SHAPE, "lock", !prevState.elementLocked ? "on" : "off");
1138 1131
       return {
1139 1132
         elementLocked: !prevState.elementLocked,
1140 1133
         elementType: prevState.elementLocked
@@ -1158,7 +1151,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
1158 1151
 
1159 1152
   toggleStats = () => {
1160 1153
     if (!this.state.showStats) {
1161
-      trackEvent(EVENT_DIALOG, "stats");
1154
+      trackEvent("dialog", "stats");
1162 1155
     }
1163 1156
     this.setState({
1164 1157
       showStats: !this.state.showStats,
@@ -1270,9 +1263,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
1270 1263
     }
1271 1264
 
1272 1265
     if (event.code === CODES.NINE) {
1273
-      if (!this.state.isLibraryOpen) {
1274
-        trackEvent(EVENT_DIALOG, "library");
1275
-      }
1276 1266
       this.setState({ isLibraryOpen: !this.state.isLibraryOpen });
1277 1267
     }
1278 1268
 
@@ -1357,7 +1347,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
1357 1347
     ) {
1358 1348
       const shape = findShapeByKey(event.key);
1359 1349
       if (shape) {
1360
-        trackEvent(EVENT_SHAPE, shape, "shortcut");
1361 1350
         this.selectShapeTool(shape);
1362 1351
       } else if (event.key === KEYS.Q) {
1363 1352
         this.toggleLock();
@@ -1741,7 +1730,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
1741 1730
     resetCursor();
1742 1731
 
1743 1732
     if (!event[KEYS.CTRL_OR_CMD]) {
1744
-      trackEvent(EVENT_SHAPE, "text", "double-click");
1745 1733
       this.startTextEditing({
1746 1734
         sceneX,
1747 1735
         sceneY,

+ 0
- 3
src/components/BackgroundPickerAndDarkModeToggle.tsx View File

@@ -1,6 +1,5 @@
1 1
 import React from "react";
2 2
 import { ActionManager } from "../actions/manager";
3
-import { EVENT_CHANGE, trackEvent } from "../analytics";
4 3
 import { AppState } from "../types";
5 4
 import { DarkModeToggle } from "./DarkModeToggle";
6 5
 
@@ -19,8 +18,6 @@ export const BackgroundPickerAndDarkModeToggle = ({
19 18
       <DarkModeToggle
20 19
         value={appState.appearance}
21 20
         onChange={(appearance) => {
22
-          // TODO: track the theme on the first load too
23
-          trackEvent(EVENT_CHANGE, "theme", appearance);
24 21
           setAppState({ appearance });
25 22
         }}
26 23
       />

+ 1
- 5
src/components/CollabButton.tsx View File

@@ -6,7 +6,6 @@ import useIsMobile from "../is-mobile";
6 6
 import { users } from "./icons";
7 7
 
8 8
 import "./CollabButton.scss";
9
-import { EVENT_DIALOG, trackEvent } from "../analytics";
10 9
 
11 10
 const CollabButton = ({
12 11
   isCollaborating,
@@ -23,10 +22,7 @@ const CollabButton = ({
23 22
         className={clsx("CollabButton", {
24 23
           "is-collaborating": isCollaborating,
25 24
         })}
26
-        onClick={() => {
27
-          trackEvent(EVENT_DIALOG, "collaboration");
28
-          onClick();
29
-        }}
25
+        onClick={onClick}
30 26
         icon={users}
31 27
         type="button"
32 28
         title={t("buttons.roomDialog")}

+ 0
- 2
src/components/ExportDialog.tsx View File

@@ -1,7 +1,6 @@
1 1
 import React, { useEffect, useRef, useState } from "react";
2 2
 import { render, unmountComponentAtNode } from "react-dom";
3 3
 import { ActionsManagerInterface } from "../actions/types";
4
-import { EVENT_DIALOG, trackEvent } from "../analytics";
5 4
 import { probablySupportsClipboardBlob } from "../clipboard";
6 5
 import { canvasToBlob } from "../data/blob";
7 6
 import { NonDeletedExcalidrawElement } from "../element/types";
@@ -251,7 +250,6 @@ export const ExportDialog = ({
251 250
     <>
252 251
       <ToolButton
253 252
         onClick={() => {
254
-          trackEvent(EVENT_DIALOG, "export");
255 253
           setModalIsShown(true);
256 254
         }}
257 255
         icon={exportFile}

+ 1
- 5
src/components/GitHubCorner.tsx View File

@@ -1,6 +1,5 @@
1
-import React from "react";
2 1
 import oc from "open-color";
3
-import { EVENT_EXIT, trackEvent } from "../analytics";
2
+import React from "react";
4 3
 
5 4
 // https://github.com/tholman/github-corners
6 5
 export const GitHubCorner = React.memo(
@@ -17,9 +16,6 @@ export const GitHubCorner = React.memo(
17 16
         target="_blank"
18 17
         rel="noopener noreferrer"
19 18
         aria-label="GitHub repository"
20
-        onClick={() => {
21
-          trackEvent(EVENT_EXIT, "github");
22
-        }}
23 19
       >
24 20
         <path
25 21
           d="M0 0l115 115h15l12 27 108 108V0z"

+ 29
- 51
src/components/LayerUI.tsx View File

@@ -1,56 +1,46 @@
1
+import clsx from "clsx";
1 2
 import React, {
2
-  useRef,
3
-  useState,
4 3
   RefObject,
5
-  useEffect,
6 4
   useCallback,
5
+  useEffect,
6
+  useRef,
7
+  useState,
7 8
 } from "react";
8
-import { showSelectedShapeActions } from "../element";
9
-import { calculateScrollCenter, getSelectedElements } from "../scene";
9
+import { ActionManager } from "../actions/manager";
10
+import { CLASSES } from "../constants";
10 11
 import { exportCanvas } from "../data";
11
-
12
-import { AppState, LibraryItems, LibraryItem } from "../types";
12
+import { importLibraryFromJSON, saveLibraryAsJSON } from "../data/json";
13
+import { Library } from "../data/library";
14
+import { showSelectedShapeActions } from "../element";
13 15
 import { NonDeletedExcalidrawElement } from "../element/types";
14
-
15
-import { ActionManager } from "../actions/manager";
16
-import { Island } from "./Island";
17
-import Stack from "./Stack";
18
-import { FixedSideContainer } from "./FixedSideContainer";
19
-import { UserList } from "./UserList";
20
-import { LockIcon } from "./LockIcon";
21
-import { ExportDialog, ExportCB } from "./ExportDialog";
22 16
 import { Language, t } from "../i18n";
23
-import { HintViewer } from "./HintViewer";
24 17
 import useIsMobile from "../is-mobile";
25
-
18
+import { calculateScrollCenter, getSelectedElements } from "../scene";
26 19
 import { ExportType } from "../scene/types";
27
-import { MobileMenu } from "./MobileMenu";
28
-import { ZoomActions, SelectedShapeActions, ShapesSwitcher } from "./Actions";
29
-import { Section } from "./Section";
20
+import { AppState, LibraryItem, LibraryItems } from "../types";
21
+import { muteFSAbortError } from "../utils";
22
+import { SelectedShapeActions, ShapesSwitcher, ZoomActions } from "./Actions";
23
+import { BackgroundPickerAndDarkModeToggle } from "./BackgroundPickerAndDarkModeToggle";
30 24
 import CollabButton from "./CollabButton";
31 25
 import { ErrorDialog } from "./ErrorDialog";
32
-import { ShortcutsDialog } from "./ShortcutsDialog";
33
-import { LoadingMessage } from "./LoadingMessage";
34
-import { CLASSES } from "../constants";
35
-import { shield, exportFile, load } from "./icons";
26
+import { ExportCB, ExportDialog } from "./ExportDialog";
27
+import { FixedSideContainer } from "./FixedSideContainer";
36 28
 import { GitHubCorner } from "./GitHubCorner";
37
-import { Tooltip } from "./Tooltip";
38
-
29
+import { HintViewer } from "./HintViewer";
30
+import { exportFile, load, shield } from "./icons";
31
+import { Island } from "./Island";
39 32
 import "./LayerUI.scss";
40 33
 import { LibraryUnit } from "./LibraryUnit";
41
-import { ToolButton } from "./ToolButton";
42
-import { saveLibraryAsJSON, importLibraryFromJSON } from "../data/json";
43
-import { muteFSAbortError } from "../utils";
44
-import { BackgroundPickerAndDarkModeToggle } from "./BackgroundPickerAndDarkModeToggle";
45
-import clsx from "clsx";
46
-import { Library } from "../data/library";
47
-import {
48
-  EVENT_ACTION,
49
-  EVENT_EXIT,
50
-  EVENT_LIBRARY,
51
-  trackEvent,
52
-} from "../analytics";
34
+import { LoadingMessage } from "./LoadingMessage";
35
+import { LockIcon } from "./LockIcon";
36
+import { MobileMenu } from "./MobileMenu";
53 37
 import { PasteChartDialog } from "./PasteChartDialog";
38
+import { Section } from "./Section";
39
+import { ShortcutsDialog } from "./ShortcutsDialog";
40
+import Stack from "./Stack";
41
+import { ToolButton } from "./ToolButton";
42
+import { Tooltip } from "./Tooltip";
43
+import { UserList } from "./UserList";
54 44
 
55 45
 interface LayerUIProps {
56 46
   actionManager: ActionManager;
@@ -159,13 +149,7 @@ const LibraryMenuItems = ({
159 149
         }}
160 150
       />
161 151
 
162
-      <a
163
-        href="https://libraries.excalidraw.com"
164
-        target="_excalidraw_libraries"
165
-        onClick={() => {
166
-          trackEvent(EVENT_EXIT, "libraries");
167
-        }}
168
-      >
152
+      <a href="https://libraries.excalidraw.com" target="_excalidraw_libraries">
169 153
         {t("labels.libraries")}
170 154
       </a>
171 155
     </div>,
@@ -267,7 +251,6 @@ const LibraryMenu = ({
267 251
     const items = await Library.loadLibrary();
268 252
     const nextItems = items.filter((_, index) => index !== indexToRemove);
269 253
     Library.saveLibrary(nextItems);
270
-    trackEvent(EVENT_LIBRARY, "remove");
271 254
     setLibraryItems(nextItems);
272 255
   }, []);
273 256
 
@@ -276,7 +259,6 @@ const LibraryMenu = ({
276 259
       const items = await Library.loadLibrary();
277 260
       const nextItems = [...items, elements];
278 261
       onAddToLibrary();
279
-      trackEvent(EVENT_LIBRARY, "add");
280 262
       Library.saveLibrary(nextItems);
281 263
       setLibraryItems(nextItems);
282 264
     },
@@ -328,9 +310,6 @@ const LayerUI = ({
328 310
       href="https://blog.excalidraw.com/end-to-end-encryption/"
329 311
       target="_blank"
330 312
       rel="noopener noreferrer"
331
-      onClick={() => {
332
-        trackEvent(EVENT_EXIT, "e2ee shield");
333
-      }}
334 313
     >
335 314
       <Tooltip label={t("encrypted.tooltip")} position="above" long={true}>
336 315
         {shield}
@@ -567,7 +546,6 @@ const LayerUI = ({
567 546
         <button
568 547
           className="scroll-back-to-content"
569 548
           onClick={() => {
570
-            trackEvent(EVENT_ACTION, "scroll to content");
571 549
             setAppState({
572 550
               ...calculateScrollCenter(elements, appState, canvas),
573 551
             });

+ 0
- 2
src/components/MobileMenu.tsx View File

@@ -16,7 +16,6 @@ import { SCROLLBAR_WIDTH, SCROLLBAR_MARGIN } from "../scene/scrollbars";
16 16
 import { LockIcon } from "./LockIcon";
17 17
 import { UserList } from "./UserList";
18 18
 import { BackgroundPickerAndDarkModeToggle } from "./BackgroundPickerAndDarkModeToggle";
19
-import { EVENT_ACTION, trackEvent } from "../analytics";
20 19
 
21 20
 type MobileMenuProps = {
22 21
   appState: AppState;
@@ -149,7 +148,6 @@ export const MobileMenu = ({
149 148
             <button
150 149
               className="scroll-back-to-content"
151 150
               onClick={() => {
152
-                trackEvent(EVENT_ACTION, "scroll to content");
153 151
                 setAppState({
154 152
                   ...calculateScrollCenter(elements, appState, canvas),
155 153
                 });

+ 0
- 10
src/components/ShortcutsDialog.tsx View File

@@ -4,7 +4,6 @@ import { isDarwin } from "../keys";
4 4
 import { Dialog } from "./Dialog";
5 5
 import { getShortcutKey } from "../utils";
6 6
 import "./ShortcutsDialog.scss";
7
-import { EVENT_EXIT, trackEvent } from "../analytics";
8 7
 
9 8
 const Columns = (props: { children: React.ReactNode }) => (
10 9
   <div
@@ -92,9 +91,6 @@ const Footer = () => (
92 91
       href="https://blog.excalidraw.com"
93 92
       target="_blank"
94 93
       rel="noopener noreferrer"
95
-      onClick={() => {
96
-        trackEvent(EVENT_EXIT, "blog");
97
-      }}
98 94
     >
99 95
       {t("shortcutsDialog.blog")}
100 96
     </a>
@@ -102,9 +98,6 @@ const Footer = () => (
102 98
       href="https://howto.excalidraw.com"
103 99
       target="_blank"
104 100
       rel="noopener noreferrer"
105
-      onClick={() => {
106
-        trackEvent(EVENT_EXIT, "guides");
107
-      }}
108 101
     >
109 102
       {t("shortcutsDialog.howto")}
110 103
     </a>
@@ -112,9 +105,6 @@ const Footer = () => (
112 105
       href="https://github.com/excalidraw/excalidraw/issues"
113 106
       target="_blank"
114 107
       rel="noopener noreferrer"
115
-      onClick={() => {
116
-        trackEvent(EVENT_EXIT, "issues");
117
-      }}
118 108
     >
119 109
       {t("shortcutsDialog.github")}
120 110
     </a>

+ 0
- 2
src/data/blob.ts View File

@@ -1,4 +1,3 @@
1
-import { EVENT_IO, trackEvent } from "../analytics";
2 1
 import { cleanAppStateForExport } from "../appState";
3 2
 import { MIME_TYPES } from "../constants";
4 3
 import { clearElementsForExport } from "../element";
@@ -111,7 +110,6 @@ export const loadFromBlob = async (
111 110
       localAppState,
112 111
     );
113 112
 
114
-    trackEvent(EVENT_IO, "load", getMimeType(blob));
115 113
     return result;
116 114
   } catch (error) {
117 115
     console.error(error.message);

+ 1
- 6
src/data/index.ts View File

@@ -1,5 +1,4 @@
1 1
 import { fileSave } from "browser-nativefs";
2
-import { EVENT_IO, trackEvent } from "../analytics";
3 2
 import {
4 3
   copyCanvasToClipboardAsPng,
5 4
   copyTextToSystemClipboard,
@@ -8,8 +7,8 @@ import { NonDeletedExcalidrawElement } from "../element/types";
8 7
 import { t } from "../i18n";
9 8
 import { exportToCanvas, exportToSvg } from "../scene/export";
10 9
 import { ExportType } from "../scene/types";
11
-import { canvasToBlob } from "./blob";
12 10
 import { AppState } from "../types";
11
+import { canvasToBlob } from "./blob";
13 12
 import { serializeAsJSON } from "./json";
14 13
 
15 14
 export { loadFromBlob } from "./blob";
@@ -60,10 +59,8 @@ export const exportCanvas = async (
60 59
         fileName: `${name}.svg`,
61 60
         extensions: [".svg"],
62 61
       });
63
-      trackEvent(EVENT_IO, "export", "svg");
64 62
       return;
65 63
     } else if (type === "clipboard-svg") {
66
-      trackEvent(EVENT_IO, "export", "clipboard-svg");
67 64
       copyTextToSystemClipboard(tempSvg.outerHTML);
68 65
       return;
69 66
     }
@@ -95,11 +92,9 @@ export const exportCanvas = async (
95 92
       fileName,
96 93
       extensions: [".png"],
97 94
     });
98
-    trackEvent(EVENT_IO, "export", "png");
99 95
   } else if (type === "clipboard") {
100 96
     try {
101 97
       await copyCanvasToClipboardAsPng(tempCanvas);
102
-      trackEvent(EVENT_IO, "export", "clipboard-png");
103 98
     } catch (error) {
104 99
       if (error.name === "CANVAS_POSSIBLY_TOO_BIG") {
105 100
         throw error;

+ 4
- 8
src/data/json.ts View File

@@ -1,13 +1,11 @@
1
+import { fileOpen, fileSave } from "browser-nativefs";
2
+import { cleanAppStateForExport } from "../appState";
3
+import { MIME_TYPES } from "../constants";
4
+import { clearElementsForExport } from "../element";
1 5
 import { ExcalidrawElement } from "../element/types";
2 6
 import { AppState } from "../types";
3
-import { cleanAppStateForExport } from "../appState";
4
-
5
-import { fileOpen, fileSave } from "browser-nativefs";
6 7
 import { loadFromBlob } from "./blob";
7 8
 import { Library } from "./library";
8
-import { MIME_TYPES } from "../constants";
9
-import { clearElementsForExport } from "../element";
10
-import { EVENT_LIBRARY, trackEvent } from "../analytics";
11 9
 
12 10
 export const serializeAsJSON = (
13 11
   elements: readonly ExcalidrawElement[],
@@ -84,7 +82,6 @@ export const saveLibraryAsJSON = async () => {
84 82
     description: "Excalidraw library file",
85 83
     extensions: [".excalidrawlib"],
86 84
   });
87
-  trackEvent(EVENT_LIBRARY, "save");
88 85
 };
89 86
 
90 87
 export const importLibraryFromJSON = async () => {
@@ -93,6 +90,5 @@ export const importLibraryFromJSON = async () => {
93 90
     extensions: [".json", ".excalidrawlib"],
94 91
     mimeTypes: ["application/json"],
95 92
   });
96
-  trackEvent(EVENT_LIBRARY, "load");
97 93
   Library.importLibrary(blob);
98 94
 };

+ 19
- 25
src/excalidraw-app/collab/CollabWrapper.tsx View File

@@ -1,40 +1,36 @@
1
-import React, { PureComponent } from "react";
2 1
 import throttle from "lodash.throttle";
3
-
2
+import React, { PureComponent } from "react";
3
+import { ExcalidrawImperativeAPI } from "../../components/App";
4
+import { ErrorDialog } from "../../components/ErrorDialog";
4 5
 import { APP_NAME, ENV, EVENT } from "../../constants";
5
-
6
+import { ImportedDataState } from "../../data/types";
7
+import { ExcalidrawElement } from "../../element/types";
8
+import {
9
+  getSceneVersion,
10
+  getSyncableElements,
11
+} from "../../packages/excalidraw/index";
12
+import { AppState, Collaborator, Gesture } from "../../types";
13
+import { resolvablePromise, withBatchedUpdates } from "../../utils";
14
+import {
15
+  INITIAL_SCENE_UPDATE_TIMEOUT,
16
+  SCENE,
17
+  SYNC_FULL_SCENE_INTERVAL_MS,
18
+} from "../app_constants";
6 19
 import {
7 20
   decryptAESGEM,
8
-  SocketUpdateDataSource,
9
-  getCollaborationLinkData,
10 21
   generateCollaborationLink,
22
+  getCollaborationLinkData,
23
+  SocketUpdateDataSource,
11 24
   SOCKET_SERVER,
12 25
 } from "../data";
13 26
 import { isSavedToFirebase, saveToFirebase } from "../data/firebase";
14
-
15
-import Portal from "./Portal";
16
-import { AppState, Collaborator, Gesture } from "../../types";
17
-import { ExcalidrawElement } from "../../element/types";
18 27
 import {
19 28
   importUsernameFromLocalStorage,
20 29
   saveUsernameToLocalStorage,
21 30
   STORAGE_KEYS,
22 31
 } from "../data/localStorage";
23
-import { resolvablePromise, withBatchedUpdates } from "../../utils";
24
-import {
25
-  getSceneVersion,
26
-  getSyncableElements,
27
-} from "../../packages/excalidraw/index";
32
+import Portal from "./Portal";
28 33
 import RoomDialog from "./RoomDialog";
29
-import { ErrorDialog } from "../../components/ErrorDialog";
30
-import { ImportedDataState } from "../../data/types";
31
-import { ExcalidrawImperativeAPI } from "../../components/App";
32
-import {
33
-  INITIAL_SCENE_UPDATE_TIMEOUT,
34
-  SCENE,
35
-  SYNC_FULL_SCENE_INTERVAL_MS,
36
-} from "../app_constants";
37
-import { EVENT_SHARE, trackEvent } from "../../analytics";
38 34
 
39 35
 interface CollabState {
40 36
   isCollaborating: boolean;
@@ -168,7 +164,6 @@ class CollabWrapper extends PureComponent<Props, CollabState> {
168 164
       elements,
169 165
       commitToHistory: true,
170 166
     });
171
-    trackEvent(EVENT_SHARE, "session start");
172 167
     return this.initializeSocketClient();
173 168
   };
174 169
 
@@ -176,7 +171,6 @@ class CollabWrapper extends PureComponent<Props, CollabState> {
176 171
     this.saveCollabRoomToFirebase();
177 172
     window.history.pushState({}, APP_NAME, window.location.origin);
178 173
     this.destroySocketClient();
179
-    trackEvent(EVENT_SHARE, "session end");
180 174
   };
181 175
 
182 176
   private destroySocketClient = () => {

+ 3
- 7
src/excalidraw-app/collab/RoomDialog.tsx View File

@@ -1,12 +1,10 @@
1 1
 import React, { useRef } from "react";
2
-import { t } from "../../i18n";
3
-import { Dialog } from "../../components/Dialog";
4 2
 import { copyTextToSystemClipboard } from "../../clipboard";
5
-import { ToolButton } from "../../components/ToolButton";
3
+import { Dialog } from "../../components/Dialog";
6 4
 import { clipboard, start, stop } from "../../components/icons";
7
-
5
+import { ToolButton } from "../../components/ToolButton";
6
+import { t } from "../../i18n";
8 7
 import "./RoomDialog.scss";
9
-import { EVENT_SHARE, trackEvent } from "../../analytics";
10 8
 
11 9
 const RoomDialog = ({
12 10
   handleClose,
@@ -30,7 +28,6 @@ const RoomDialog = ({
30 28
   const copyRoomLink = async () => {
31 29
     try {
32 30
       await copyTextToSystemClipboard(activeRoomLink);
33
-      trackEvent(EVENT_SHARE, "copy link");
34 31
     } catch (error) {
35 32
       setErrorMessage(error.message);
36 33
     }
@@ -95,7 +92,6 @@ const RoomDialog = ({
95 92
                 value={username || ""}
96 93
                 className="RoomDialog-username TextInput"
97 94
                 onChange={(event) => onUsernameChange(event.target.value)}
98
-                onBlur={() => trackEvent(EVENT_SHARE, "name")}
99 95
                 onKeyPress={(event) => event.key === "Enter" && handleClose()}
100 96
               />
101 97
             </div>

+ 4
- 7
src/excalidraw-app/data/index.ts View File

@@ -1,10 +1,9 @@
1
-import { t } from "../../i18n";
1
+import { serializeAsJSON } from "../../data/json";
2
+import { restore } from "../../data/restore";
3
+import { ImportedDataState } from "../../data/types";
2 4
 import { ExcalidrawElement } from "../../element/types";
5
+import { t } from "../../i18n";
3 6
 import { AppState } from "../../types";
4
-import { ImportedDataState } from "../../data/types";
5
-import { restore } from "../../data/restore";
6
-import { EVENT_ACTION, EVENT_IO, trackEvent } from "../../analytics";
7
-import { serializeAsJSON } from "../../data/json";
8 7
 
9 8
 const byteToHex = (byte: number): string => `0${byte.toString(16)}`.slice(-2);
10 9
 
@@ -192,7 +191,6 @@ const importFromBackend = async (
192 191
       data = await response.json();
193 192
     }
194 193
 
195
-    trackEvent(EVENT_ACTION, "import");
196 194
     return {
197 195
       elements: data.elements || null,
198 196
       appState: data.appState || null,
@@ -276,7 +274,6 @@ export const exportToBackend = async (
276 274
       url.hash = `json=${json.id},${exportedKey.k!}`;
277 275
       const urlString = url.toString();
278 276
       window.prompt(`🔒${t("alerts.uploadedSecurly")}`, urlString);
279
-      trackEvent(EVENT_IO, "export", "backend");
280 277
     } else if (json.error_class === "RequestTooLargeError") {
281 278
       window.alert(t("alerts.couldNotCreateShareableLinkTooBig"));
282 279
     } else {

+ 23
- 37
src/excalidraw-app/index.tsx View File

@@ -1,46 +1,39 @@
1
+import LanguageDetector from "i18next-browser-languagedetector";
1 2
 import React, {
2
-  useState,
3
-  useLayoutEffect,
3
+  useCallback,
4 4
   useEffect,
5
+  useLayoutEffect,
5 6
   useRef,
6
-  useCallback,
7
+  useState,
7 8
 } from "react";
8
-import LanguageDetector from "i18next-browser-languagedetector";
9
-
9
+import { getDefaultAppState } from "../appState";
10
+import { ExcalidrawImperativeAPI } from "../components/App";
11
+import { ErrorDialog } from "../components/ErrorDialog";
12
+import { TopErrorBoundary } from "../components/TopErrorBoundary";
13
+import { APP_NAME, EVENT, TITLE_TIMEOUT } from "../constants";
14
+import { ImportedDataState } from "../data/types";
15
+import {
16
+  ExcalidrawElement,
17
+  NonDeletedExcalidrawElement,
18
+} from "../element/types";
19
+import { Language, t } from "../i18n";
10 20
 import Excalidraw, {
11
-  languages,
12 21
   defaultLang,
22
+  languages,
13 23
 } from "../packages/excalidraw/index";
14
-
24
+import { AppState, ExcalidrawAPIRefValue } from "../types";
25
+import { debounce, ResolvablePromise, resolvablePromise } from "../utils";
26
+import { SAVE_TO_LOCAL_STORAGE_TIMEOUT } from "./app_constants";
27
+import CollabWrapper, { CollabAPI } from "./collab/CollabWrapper";
28
+import { LanguageList } from "./components/LanguageList";
29
+import { exportToBackend, getCollaborationLinkData, loadScene } from "./data";
30
+import { loadFromFirebase } from "./data/firebase";
15 31
 import {
16
-  getTotalStorageSize,
17 32
   importFromLocalStorage,
18 33
   saveToLocalStorage,
19 34
   STORAGE_KEYS,
20 35
 } from "./data/localStorage";
21 36
 
22
-import { ImportedDataState } from "../data/types";
23
-import CollabWrapper, { CollabAPI } from "./collab/CollabWrapper";
24
-import { TopErrorBoundary } from "../components/TopErrorBoundary";
25
-import { Language, t } from "../i18n";
26
-import { exportToBackend, loadScene } from "./data";
27
-import { getCollaborationLinkData } from "./data";
28
-import { EVENT } from "../constants";
29
-import { loadFromFirebase } from "./data/firebase";
30
-import { ExcalidrawImperativeAPI } from "../components/App";
31
-import { debounce, ResolvablePromise, resolvablePromise } from "../utils";
32
-import { AppState, ExcalidrawAPIRefValue } from "../types";
33
-import {
34
-  ExcalidrawElement,
35
-  NonDeletedExcalidrawElement,
36
-} from "../element/types";
37
-import { SAVE_TO_LOCAL_STORAGE_TIMEOUT } from "./app_constants";
38
-import { EVENT_LOAD, EVENT_SHARE, trackEvent } from "../analytics";
39
-import { ErrorDialog } from "../components/ErrorDialog";
40
-import { getDefaultAppState } from "../appState";
41
-import { APP_NAME, TITLE_TIMEOUT } from "../constants";
42
-import { LanguageList } from "./components/LanguageList";
43
-
44 37
 const languageDetector = new LanguageDetector();
45 38
 languageDetector.init({
46 39
   languageUtils: {
@@ -163,7 +156,6 @@ const initializeScene = async (opts: {
163 156
     // into the remote scene
164 157
     opts.resetScene();
165 158
     const scenePromise = opts.initializeSocketClient();
166
-    trackEvent(EVENT_SHARE, "session join");
167 159
 
168 160
     try {
169 161
       const [, roomId, roomKey] = getCollaborationLinkData(
@@ -231,12 +223,6 @@ function ExcalidrawWrapper(props: { collab: CollabAPI }) {
231 223
   const { collab } = props;
232 224
 
233 225
   useEffect(() => {
234
-    const storageSize = getTotalStorageSize();
235
-    if (storageSize) {
236
-      trackEvent(EVENT_LOAD, "storage", "size", storageSize);
237
-    } else {
238
-      trackEvent(EVENT_LOAD, "first time");
239
-    }
240 226
     excalidrawRef.current!.readyPromise.then((excalidrawApi) => {
241 227
       initializeScene({
242 228
         resetScene: excalidrawApi.resetScene,

+ 0
- 3
src/i18n.ts View File

@@ -1,5 +1,3 @@
1
-import { EVENT_CHANGE, trackEvent } from "./analytics";
2
-
3 1
 import fallbackLangData from "./locales/en.json";
4 2
 import percentages from "./locales/percentages.json";
5 3
 
@@ -67,7 +65,6 @@ export const setLanguage = async (lang: Language) => {
67 65
   currentLangData = await import(
68 66
     /* webpackChunkName: "i18n-[request]" */ `./locales/${currentLang.code}.json`
69 67
   );
70
-  trackEvent(EVENT_CHANGE, "language", currentLang.code);
71 68
 };
72 69
 
73 70
 export const setLanguageFirstTime = async (lang: Language) => {

+ 2
- 5
src/zindex.ts View File

@@ -1,8 +1,7 @@
1
-import { AppState } from "./types";
2 1
 import { ExcalidrawElement } from "./element/types";
3 2
 import { getElementsInGroup } from "./groups";
4
-import { findLastIndex, findIndex } from "./utils";
5
-import { trackEvent, EVENT_LAYER } from "./analytics";
3
+import { AppState } from "./types";
4
+import { findIndex, findLastIndex } from "./utils";
6 5
 
7 6
 /**
8 7
  * Returns indices of elements to move based on selected elements.
@@ -176,7 +175,6 @@ const shiftElements = (
176 175
           ];
177 176
   });
178 177
 
179
-  trackEvent(EVENT_LAYER, "move", direction === "left" ? "down" : "up");
180 178
   return elements;
181 179
 };
182 180
 
@@ -234,7 +232,6 @@ const shiftElementsToEnd = (
234 232
   const leadingElements = elements.slice(0, leadingIndex);
235 233
   const trailingElements = elements.slice(trailingIndex + 1);
236 234
 
237
-  trackEvent(EVENT_LAYER, "move", direction === "left" ? "back" : "front");
238 235
   return direction === "left"
239 236
     ? [
240 237
         ...leadingElements,

Loading…
Cancel
Save