More events for layers, align, colors and swap name <=> category (#2442)
This commit is contained in:
parent
0ef60dce2d
commit
668150a667
86
analytics.md
86
analytics.md
@ -1,36 +1,50 @@
|
|||||||
| Excalidraw | Name | Category | Label | Value |
|
| Excalidraw | Category | Name | Label | Value |
|
||||||
| -------------------- | ------ | ---------------------------------- | ------------------------ | --------- |
|
| ----------------------- | -------- | ---------------------------------- | ------------------------------- | --------- |
|
||||||
| Shape / Selection | shape | selection, rectangle, diamond, etc | `toolbar` or `shortcut` |
|
| Shape / Selection | shape | selection, rectangle, diamond, etc | `toolbar` or `shortcut` |
|
||||||
| Text on double click | shape | text | `double-click` |
|
| Text on double click | shape | text | `double-click` |
|
||||||
| Lock selection | shape | lock | `on` or `off` |
|
| Lock selection | shape | lock | `on` or `off` |
|
||||||
| Load file | action | load | `MIME type` |
|
| Load file | action | load | `MIME type` |
|
||||||
| Import from URL | action | import |
|
| Import from URL | action | import |
|
||||||
| Save | action | save |
|
| Save | action | save |
|
||||||
| Save as | action | save as |
|
| Save as | action | save as |
|
||||||
| Clear canvas | action | clear canvas |
|
| Clear canvas | action | clear canvas |
|
||||||
| Zoom in | action | zoom | in | `zoom` |
|
| Zoom in | action | zoom | in | `zoom` |
|
||||||
| Zoom out | action | zoom | out | `zoom` |
|
| Zoom out | action | zoom | out | `zoom` |
|
||||||
| Zoom fit | action | zoom | fit | `zoom` |
|
| Zoom fit | action | zoom | fit | `zoom` |
|
||||||
| Zoom reset | action | zoom | reset | `zoom` |
|
| Zoom reset | action | zoom | reset | `zoom` |
|
||||||
| Export dialog | action | export | dialog |
|
| Export dialog | action | export | dialog |
|
||||||
| Export to backend | action | export | backend |
|
| Export to backend | action | export | backend |
|
||||||
| Export as SVG | action | export | `svg` or `clipboard-svg` |
|
| Export as SVG | action | export | `svg` or `clipboard-svg` |
|
||||||
| Export to PNG | action | export | `png` or `clipboard-png` |
|
| Export to PNG | action | export | `png` or `clipboard-png` |
|
||||||
| Open shortcut menu | action | keyboard shortcuts |
|
| Scroll back to content | action | scroll to content |
|
||||||
| Canvas color | change | canvas color | `color` |
|
| Open shortcut menu | action | keyboard shortcuts |
|
||||||
| Background color | change | background color | `color` |
|
| Canvas color | change | canvas color | `color` |
|
||||||
| Stroke color | change | stroke color | `color` |
|
| Background color | change | background color | `color` |
|
||||||
| Stroke width | change | stroke | width | `width` |
|
| Stroke color | change | stroke color | `color` |
|
||||||
| Stroke sloppiness | change | stroke | sloppiness | `value` |
|
| Stroke width | change | stroke | width | `width` |
|
||||||
| Fill | change | fill | `value` |
|
| Stroke style | change | style | `solid` or `dashed` or `dotted` |
|
||||||
| Edge | change | edge | `value` |
|
| Stroke sloppiness | change | stroke | sloppiness | `value` |
|
||||||
| Opacity | change | opacity | value | `opacity` |
|
| Fill | change | fill | `value` |
|
||||||
| Project name | change | title |
|
| Edge | change | edge | `value` |
|
||||||
| Theme | change | theme | `light` or `dark` |
|
| Opacity | change | opacity | value | `opacity` |
|
||||||
| Change language | change | language | `language` |
|
| Project name | change | title |
|
||||||
| Language on load | change | language on load | `language` |
|
| Theme | change | theme | `light` or `dark` |
|
||||||
| E2EE shield | exit | e2ee shield |
|
| Change language | change | language | `language` |
|
||||||
| GitHub corner | exit | github |
|
| Language on load | change | language on load | `language` |
|
||||||
| Excalidraw blog | exit | blog |
|
| Send to back | layer | move | `back` |
|
||||||
| Excalidraw guides | exit | guides |
|
| Send backward | layer | move | `down` |
|
||||||
| File issues | exit | issues |
|
| Bring to front | layer | move | `front` |
|
||||||
|
| Bring forward | layer | move | `up` |
|
||||||
|
| Align left | align | align | `left` |
|
||||||
|
| Align right | align | align | `right` |
|
||||||
|
| Align top | align | align | `top` |
|
||||||
|
| Align bottom | align | align | `bottom` |
|
||||||
|
| Center horizontally | align | horizontally | `center` |
|
||||||
|
| Center vertically | align | vertically | `center` |
|
||||||
|
| Distribute horizontally | align | distribute | `horizontally` |
|
||||||
|
| Distribute vertically | align | distribute | `vertically` |
|
||||||
|
| E2EE shield | exit | e2ee shield |
|
||||||
|
| GitHub corner | exit | github |
|
||||||
|
| Excalidraw blog | exit | blog |
|
||||||
|
| Excalidraw guides | exit | guides |
|
||||||
|
| File issues | exit | issues |
|
||||||
|
@ -17,6 +17,7 @@ import { ExcalidrawElement } from "../element/types";
|
|||||||
import { AppState } from "../types";
|
import { AppState } from "../types";
|
||||||
import { alignElements, Alignment } from "../align";
|
import { alignElements, Alignment } from "../align";
|
||||||
import { getShortcutKey } from "../utils";
|
import { getShortcutKey } from "../utils";
|
||||||
|
import { trackEvent, EVENT_ALIGN } from "../analytics";
|
||||||
|
|
||||||
const enableActionGroup = (
|
const enableActionGroup = (
|
||||||
elements: readonly ExcalidrawElement[],
|
elements: readonly ExcalidrawElement[],
|
||||||
@ -43,6 +44,7 @@ const alignSelectedElements = (
|
|||||||
export const actionAlignTop = register({
|
export const actionAlignTop = register({
|
||||||
name: "alignTop",
|
name: "alignTop",
|
||||||
perform: (elements, appState) => {
|
perform: (elements, appState) => {
|
||||||
|
trackEvent(EVENT_ALIGN, "align", "top");
|
||||||
return {
|
return {
|
||||||
appState,
|
appState,
|
||||||
elements: alignSelectedElements(elements, appState, {
|
elements: alignSelectedElements(elements, appState, {
|
||||||
@ -72,6 +74,7 @@ export const actionAlignTop = register({
|
|||||||
export const actionAlignBottom = register({
|
export const actionAlignBottom = register({
|
||||||
name: "alignBottom",
|
name: "alignBottom",
|
||||||
perform: (elements, appState) => {
|
perform: (elements, appState) => {
|
||||||
|
trackEvent(EVENT_ALIGN, "align", "bottom");
|
||||||
return {
|
return {
|
||||||
appState,
|
appState,
|
||||||
elements: alignSelectedElements(elements, appState, {
|
elements: alignSelectedElements(elements, appState, {
|
||||||
@ -101,6 +104,7 @@ export const actionAlignBottom = register({
|
|||||||
export const actionAlignLeft = register({
|
export const actionAlignLeft = register({
|
||||||
name: "alignLeft",
|
name: "alignLeft",
|
||||||
perform: (elements, appState) => {
|
perform: (elements, appState) => {
|
||||||
|
trackEvent(EVENT_ALIGN, "align", "left");
|
||||||
return {
|
return {
|
||||||
appState,
|
appState,
|
||||||
elements: alignSelectedElements(elements, appState, {
|
elements: alignSelectedElements(elements, appState, {
|
||||||
@ -130,6 +134,7 @@ export const actionAlignLeft = register({
|
|||||||
export const actionAlignRight = register({
|
export const actionAlignRight = register({
|
||||||
name: "alignRight",
|
name: "alignRight",
|
||||||
perform: (elements, appState) => {
|
perform: (elements, appState) => {
|
||||||
|
trackEvent(EVENT_ALIGN, "align", "right");
|
||||||
return {
|
return {
|
||||||
appState,
|
appState,
|
||||||
elements: alignSelectedElements(elements, appState, {
|
elements: alignSelectedElements(elements, appState, {
|
||||||
@ -159,6 +164,7 @@ export const actionAlignRight = register({
|
|||||||
export const actionAlignVerticallyCentered = register({
|
export const actionAlignVerticallyCentered = register({
|
||||||
name: "alignVerticallyCentered",
|
name: "alignVerticallyCentered",
|
||||||
perform: (elements, appState) => {
|
perform: (elements, appState) => {
|
||||||
|
trackEvent(EVENT_ALIGN, "vertically", "center");
|
||||||
return {
|
return {
|
||||||
appState,
|
appState,
|
||||||
elements: alignSelectedElements(elements, appState, {
|
elements: alignSelectedElements(elements, appState, {
|
||||||
@ -184,6 +190,7 @@ export const actionAlignVerticallyCentered = register({
|
|||||||
export const actionAlignHorizontallyCentered = register({
|
export const actionAlignHorizontallyCentered = register({
|
||||||
name: "alignHorizontallyCentered",
|
name: "alignHorizontallyCentered",
|
||||||
perform: (elements, appState) => {
|
perform: (elements, appState) => {
|
||||||
|
trackEvent(EVENT_ALIGN, "horizontally", "center");
|
||||||
return {
|
return {
|
||||||
appState,
|
appState,
|
||||||
elements: alignSelectedElements(elements, appState, {
|
elements: alignSelectedElements(elements, appState, {
|
||||||
|
@ -15,12 +15,19 @@ import { getCommonBounds } from "../element";
|
|||||||
import { getNewZoom } from "../scene/zoom";
|
import { getNewZoom } from "../scene/zoom";
|
||||||
import { centerScrollOn } from "../scene/scroll";
|
import { centerScrollOn } from "../scene/scroll";
|
||||||
import { EVENT_ACTION, EVENT_CHANGE, trackEvent } from "../analytics";
|
import { EVENT_ACTION, EVENT_CHANGE, trackEvent } from "../analytics";
|
||||||
|
import colors from "../colors";
|
||||||
|
|
||||||
export const actionChangeViewBackgroundColor = register({
|
export const actionChangeViewBackgroundColor = register({
|
||||||
name: "changeViewBackgroundColor",
|
name: "changeViewBackgroundColor",
|
||||||
perform: (_, appState, value) => {
|
perform: (_, appState, value) => {
|
||||||
if (value !== appState.viewBackgroundColor) {
|
if (value !== appState.viewBackgroundColor) {
|
||||||
trackEvent(EVENT_CHANGE, "canvas color", value);
|
trackEvent(
|
||||||
|
EVENT_CHANGE,
|
||||||
|
"canvas color",
|
||||||
|
colors.canvasBackground.includes(value)
|
||||||
|
? `${value} (picker ${colors.canvasBackground.indexOf(value)})`
|
||||||
|
: value,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
appState: { ...appState, viewBackgroundColor: value },
|
appState: { ...appState, viewBackgroundColor: value },
|
||||||
|
@ -13,6 +13,7 @@ import { ExcalidrawElement } from "../element/types";
|
|||||||
import { AppState } from "../types";
|
import { AppState } from "../types";
|
||||||
import { distributeElements, Distribution } from "../disitrubte";
|
import { distributeElements, Distribution } from "../disitrubte";
|
||||||
import { getShortcutKey } from "../utils";
|
import { getShortcutKey } from "../utils";
|
||||||
|
import { EVENT_ALIGN, trackEvent } from "../analytics";
|
||||||
|
|
||||||
const enableActionGroup = (
|
const enableActionGroup = (
|
||||||
elements: readonly ExcalidrawElement[],
|
elements: readonly ExcalidrawElement[],
|
||||||
@ -39,6 +40,7 @@ const distributeSelectedElements = (
|
|||||||
export const distributeHorizontally = register({
|
export const distributeHorizontally = register({
|
||||||
name: "distributeHorizontally",
|
name: "distributeHorizontally",
|
||||||
perform: (elements, appState) => {
|
perform: (elements, appState) => {
|
||||||
|
trackEvent(EVENT_ALIGN, "distribute", "horizontally");
|
||||||
return {
|
return {
|
||||||
appState,
|
appState,
|
||||||
elements: distributeSelectedElements(elements, appState, {
|
elements: distributeSelectedElements(elements, appState, {
|
||||||
@ -67,6 +69,7 @@ export const distributeHorizontally = register({
|
|||||||
export const distributeVertically = register({
|
export const distributeVertically = register({
|
||||||
name: "distributeVertically",
|
name: "distributeVertically",
|
||||||
perform: (elements, appState) => {
|
perform: (elements, appState) => {
|
||||||
|
trackEvent(EVENT_ALIGN, "distribute", "vertically");
|
||||||
return {
|
return {
|
||||||
appState,
|
appState,
|
||||||
elements: distributeSelectedElements(elements, appState, {
|
elements: distributeSelectedElements(elements, appState, {
|
||||||
|
@ -41,6 +41,7 @@ import {
|
|||||||
SloppinessCartoonistIcon,
|
SloppinessCartoonistIcon,
|
||||||
} from "../components/icons";
|
} from "../components/icons";
|
||||||
import { EVENT_CHANGE, trackEvent } from "../analytics";
|
import { EVENT_CHANGE, trackEvent } from "../analytics";
|
||||||
|
import colors from "../colors";
|
||||||
|
|
||||||
const changeProperty = (
|
const changeProperty = (
|
||||||
elements: readonly ExcalidrawElement[],
|
elements: readonly ExcalidrawElement[],
|
||||||
@ -83,7 +84,13 @@ export const actionChangeStrokeColor = register({
|
|||||||
name: "changeStrokeColor",
|
name: "changeStrokeColor",
|
||||||
perform: (elements, appState, value) => {
|
perform: (elements, appState, value) => {
|
||||||
if (value !== appState.currentItemStrokeColor) {
|
if (value !== appState.currentItemStrokeColor) {
|
||||||
trackEvent(EVENT_CHANGE, "stroke color", value);
|
trackEvent(
|
||||||
|
EVENT_CHANGE,
|
||||||
|
"stroke color",
|
||||||
|
colors.elementStroke.includes(value)
|
||||||
|
? `${value} (picker ${colors.elementStroke.indexOf(value)})`
|
||||||
|
: value,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
elements: changeProperty(elements, appState, (el) =>
|
elements: changeProperty(elements, appState, (el) =>
|
||||||
@ -117,7 +124,13 @@ export const actionChangeBackgroundColor = register({
|
|||||||
name: "changeBackgroundColor",
|
name: "changeBackgroundColor",
|
||||||
perform: (elements, appState, value) => {
|
perform: (elements, appState, value) => {
|
||||||
if (value !== appState.currentItemBackgroundColor) {
|
if (value !== appState.currentItemBackgroundColor) {
|
||||||
trackEvent(EVENT_CHANGE, "background color", value);
|
trackEvent(
|
||||||
|
EVENT_CHANGE,
|
||||||
|
"background color",
|
||||||
|
colors.elementBackground.includes(value)
|
||||||
|
? `${value} (picker ${colors.elementBackground.indexOf(value)})`
|
||||||
|
: value,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -313,6 +326,7 @@ export const actionChangeSloppiness = register({
|
|||||||
export const actionChangeStrokeStyle = register({
|
export const actionChangeStrokeStyle = register({
|
||||||
name: "changeStrokeStyle",
|
name: "changeStrokeStyle",
|
||||||
perform: (elements, appState, value) => {
|
perform: (elements, appState, value) => {
|
||||||
|
trackEvent(EVENT_CHANGE, "style", value);
|
||||||
return {
|
return {
|
||||||
elements: changeProperty(elements, appState, (el) =>
|
elements: changeProperty(elements, appState, (el) =>
|
||||||
newElementWith(el, {
|
newElementWith(el, {
|
||||||
|
@ -2,15 +2,17 @@ export const EVENT_ACTION = "action";
|
|||||||
export const EVENT_EXIT = "exit";
|
export const EVENT_EXIT = "exit";
|
||||||
export const EVENT_CHANGE = "change";
|
export const EVENT_CHANGE = "change";
|
||||||
export const EVENT_SHAPE = "shape";
|
export const EVENT_SHAPE = "shape";
|
||||||
|
export const EVENT_LAYER = "layer";
|
||||||
|
export const EVENT_ALIGN = "align";
|
||||||
|
|
||||||
export const trackEvent = window.gtag
|
export const trackEvent = window.gtag
|
||||||
? (name: string, category: string, label?: string, value?: number) => {
|
? (category: string, name: string, label?: string, value?: number) => {
|
||||||
window.gtag("event", name, {
|
window.gtag("event", name, {
|
||||||
event_category: category,
|
event_category: category,
|
||||||
event_label: label,
|
event_label: label,
|
||||||
value,
|
value,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
: (name: string, category: string, label?: string, value?: number) => {
|
: (category: string, name: string, label?: string, value?: number) => {
|
||||||
console.info("Track Event", name, category, label, value);
|
console.info("Track Event", category, name, label, value);
|
||||||
};
|
};
|
||||||
|
@ -45,7 +45,7 @@ import { muteFSAbortError } from "../utils";
|
|||||||
import { BackgroundPickerAndDarkModeToggle } from "./BackgroundPickerAndDarkModeToggle";
|
import { BackgroundPickerAndDarkModeToggle } from "./BackgroundPickerAndDarkModeToggle";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import { Library } from "../data/library";
|
import { Library } from "../data/library";
|
||||||
import { EVENT_EXIT, trackEvent } from "../analytics";
|
import { EVENT_ACTION, EVENT_EXIT, trackEvent } from "../analytics";
|
||||||
|
|
||||||
interface LayerUIProps {
|
interface LayerUIProps {
|
||||||
actionManager: ActionManager;
|
actionManager: ActionManager;
|
||||||
@ -575,6 +575,7 @@ const LayerUI = ({
|
|||||||
<button
|
<button
|
||||||
className="scroll-back-to-content"
|
className="scroll-back-to-content"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
trackEvent(EVENT_ACTION, "scroll to content");
|
||||||
setAppState({
|
setAppState({
|
||||||
...calculateScrollCenter(elements, appState, canvas),
|
...calculateScrollCenter(elements, appState, canvas),
|
||||||
});
|
});
|
||||||
|
@ -18,6 +18,7 @@ import { LockIcon } from "./LockIcon";
|
|||||||
import { LoadingMessage } from "./LoadingMessage";
|
import { LoadingMessage } from "./LoadingMessage";
|
||||||
import { UserList } from "./UserList";
|
import { UserList } from "./UserList";
|
||||||
import { BackgroundPickerAndDarkModeToggle } from "./BackgroundPickerAndDarkModeToggle";
|
import { BackgroundPickerAndDarkModeToggle } from "./BackgroundPickerAndDarkModeToggle";
|
||||||
|
import { EVENT_ACTION, trackEvent } from "../analytics";
|
||||||
|
|
||||||
type MobileMenuProps = {
|
type MobileMenuProps = {
|
||||||
appState: AppState;
|
appState: AppState;
|
||||||
@ -163,6 +164,7 @@ export const MobileMenu = ({
|
|||||||
<button
|
<button
|
||||||
className="scroll-back-to-content"
|
className="scroll-back-to-content"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
trackEvent(EVENT_ACTION, "scroll to content");
|
||||||
setAppState({
|
setAppState({
|
||||||
...calculateScrollCenter(elements, appState, canvas),
|
...calculateScrollCenter(elements, appState, canvas),
|
||||||
});
|
});
|
||||||
|
@ -2,6 +2,7 @@ import { AppState } from "./types";
|
|||||||
import { ExcalidrawElement } from "./element/types";
|
import { ExcalidrawElement } from "./element/types";
|
||||||
import { getElementsInGroup } from "./groups";
|
import { getElementsInGroup } from "./groups";
|
||||||
import { findLastIndex, findIndex } from "./utils";
|
import { findLastIndex, findIndex } from "./utils";
|
||||||
|
import { trackEvent, EVENT_LAYER } from "./analytics";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns indices of elements to move based on selected elements.
|
* Returns indices of elements to move based on selected elements.
|
||||||
@ -175,6 +176,7 @@ const shiftElements = (
|
|||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
trackEvent(EVENT_LAYER, "move", direction === "left" ? "down" : "up");
|
||||||
return elements;
|
return elements;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -232,6 +234,7 @@ const shiftElementsToEnd = (
|
|||||||
const leadingElements = elements.slice(0, leadingIndex);
|
const leadingElements = elements.slice(0, leadingIndex);
|
||||||
const trailingElements = elements.slice(trailingIndex + 1);
|
const trailingElements = elements.slice(trailingIndex + 1);
|
||||||
|
|
||||||
|
trackEvent(EVENT_LAYER, "move", direction === "left" ? "back" : "front");
|
||||||
return direction === "left"
|
return direction === "left"
|
||||||
? [
|
? [
|
||||||
...leadingElements,
|
...leadingElements,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user