diff --git a/ES6/README.md b/ES6/README.md index 7ac1f1d..78c5949 100644 --- a/ES6/README.md +++ b/ES6/README.md @@ -21,7 +21,7 @@ Table of contents: ## Prerequisites -- [Node.js 14 or later](https://nodejs.org/en/) +- [Node.js 20.19+ or 22.12+](https://nodejs.org/en/) ## Installation diff --git a/ES6/package.json b/ES6/package.json index 491efb3..ec20171 100644 --- a/ES6/package.json +++ b/ES6/package.json @@ -10,23 +10,23 @@ "preview": "vite preview" }, "dependencies": { - "@amcharts/amcharts4": "^4.10.36", - "@amcharts/amcharts5": "^5.4.1", - "highcharts": "^11.1.0", - "react": "^19.0.0", - "react-dom": "^19.0.0", + "@amcharts/amcharts4": "^4.10.40", + "@amcharts/amcharts5": "^5.13.4", + "highcharts-react-official": "^3.2.2", + "react": "^19.1.1", + "react-dom": "^19.1.1", "react-flexmonster": "latest", - "react-router-dom": "^6.14.2" + "react-router-dom": "^7.7.1" }, "devDependencies": { - "@types/react": "^19.0.0", - "@types/react-dom": "^19.0.0", - "@vitejs/plugin-react": "^4.0.3", - "eslint": "^8.45.0", - "eslint-plugin-react": "^7.32.2", - "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-react-refresh": "^0.4.3", - "express": "^4.18.2", - "vite": "^4.4.5" + "@types/react": "^19.1.9", + "@types/react-dom": "^19.1.7", + "@vitejs/plugin-react": "^4.7.0", + "eslint": "^9.32.0", + "eslint-plugin-react": "^7.37.5", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.20", + "express": "^5.1.0", + "vite": "^7.0.6" } } diff --git a/ES6/src/App.css b/ES6/src/App.css index a0f3dc6..c58cc4e 100644 --- a/ES6/src/App.css +++ b/ES6/src/App.css @@ -31,7 +31,7 @@ body { } .chart-container { - margin-top: 70px; + margin-top: 50px; } .first-description-block { @@ -78,6 +78,7 @@ body { margin: 5px 5px 5px 0; position: relative; width: auto; + appearance: none; -webkit-appearance: none; -moz-appearance: none; -webkit-box-sizing: border-box; diff --git a/ES6/src/components/ReactFlexmonsterExamples/CustomizingGrid.jsx b/ES6/src/components/ReactFlexmonsterExamples/CustomizingGrid.jsx index 0fc608a..4594490 100644 --- a/ES6/src/components/ReactFlexmonsterExamples/CustomizingGrid.jsx +++ b/ES6/src/components/ReactFlexmonsterExamples/CustomizingGrid.jsx @@ -1,86 +1,81 @@ -import React, { useRef } from "react"; +import { useRef } from "react"; import * as FlexmonsterReact from "react-flexmonster"; import ToggleButton from "../UIElements/ToggleButton"; function CustomizingGrid() { - const pivotRef = useRef(null); + const pivotRef = useRef(null); - const customizeCellFunction = (cell, data) => { - if (data.measure && data.measure.uniqueName === "Price") { - let backgroundColor = "#00A45A"; - let textShadowColor = "#095231"; - let borderColor = "#009552"; - cell.style["background-color"] = backgroundColor; - cell.style["color"] = "white"; - cell.style["font-weight"] = "bold"; - cell.style["text-shadow"] = `0px 2px 3px ${textShadowColor}`; - cell.style["border-bottom"] = `1px solid ${borderColor}`; - cell.style["border-right"] = `1px solid ${borderColor}`; - } - }; + const customizeCellFunction = (cell, data) => { + if (data.measure && data.measure.uniqueName === "Price") { + let backgroundColor = "#00A45A"; + let textShadowColor = "#095231"; + let borderColor = "#009552"; + cell.style["background-color"] = backgroundColor; + cell.style["color"] = "white"; + cell.style["font-weight"] = "bold"; + cell.style["text-shadow"] = `0px 2px 3px ${textShadowColor}`; + cell.style["border-bottom"] = `1px solid ${borderColor}`; + cell.style["border-right"] = `1px solid ${borderColor}`; + } + }; - const controllCustomization = (isCustomized) => { - isCustomized ? applyCustomization() : removeCustomization(); - }; + const toggleCustomization = (isCustomized) => { + isCustomized ? applyCustomization() : removeCustomization(); + }; - const removeCustomization = () => { - pivotRef.current.flexmonster.customizeCell(null); - }; + const removeCustomization = () => { + pivotRef.current.flexmonster.customizeCell(null); + }; - const applyCustomization = () => { - //running grid customization using "customizeCellFunction" - pivotRef.current.flexmonster.customizeCell(customizeCellFunction); - }; + const applyCustomization = () => { + pivotRef.current.flexmonster.customizeCell(customizeCellFunction); + }; - return ( - <> -

Customizing the grid

+ return ( + <> +

Customizing the grid

-
-

- Style the grid by adding links, applying custom CSS, or formatting the - cells. Check our docs for details:{" "} - - Customizing the grid - - . -

-

- In this demo, the Price measure is customized. -

-
+
+

+ Style the grid by adding links, applying custom CSS, or formatting the + cells. Check our docs for details:{" "} + Customizing the grid cells. +

+

+ In this demo, the Price measure is customized. +

+
-
- -
+
+ +
- { - toolbar.showShareReportTab = true; - }} - shareReportConnection={{ - url: "https://olap.flexmonster.com:9500", - }} - width="100%" - height={600} - report="https://cdn.flexmonster.com/github/customizing-grid-report.json" - customizeCell={customizeCellFunction} - //licenseKey="XXXX-XXXX-XXXX-XXXX-XXXX" - /> - - ); + { + toolbar.showShareReportTab = true; + }} + shareReportConnection={{ + url: "https://olap.flexmonster.com:9500", + }} + customizeCell={customizeCellFunction} + //licenseKey="XXXX-XXXX-XXXX-XXXX-XXXX" + /> + + ); } export default CustomizingGrid; diff --git a/ES6/src/components/ReactFlexmonsterExamples/CustomizingToolbar.jsx b/ES6/src/components/ReactFlexmonsterExamples/CustomizingToolbar.jsx index 846339f..afd5a50 100644 --- a/ES6/src/components/ReactFlexmonsterExamples/CustomizingToolbar.jsx +++ b/ES6/src/components/ReactFlexmonsterExamples/CustomizingToolbar.jsx @@ -1,57 +1,62 @@ -import React, { useRef } from 'react'; -import * as FlexmonsterReact from 'react-flexmonster'; +import { useRef } from "react"; +import * as FlexmonsterReact from "react-flexmonster"; function CustomizingToolbar() { - const pivotRef = useRef(null); + const pivotRef = useRef(null); - const showInfo = () => { - pivotRef.current.flexmonster.alert({ - title: "Customizing Flexmonster", - message: - "How to customize the Toolbar: https://www.flexmonster.com/doc/customizing-toolbar/
", - type: "info", - blocking: false, - }); - } + const showInfo = () => { + pivotRef.current.flexmonster.alert({ + title: "Customizing Flexmonster", + message: + "How to customize the Toolbar: https://www.flexmonster.com/doc/customizing-toolbar/
", + type: "info", + blocking: false, + }); + }; - const customizeToolbar = (toolbar) => { - let tabs = toolbar.getTabs(); - toolbar.getTabs = () => { - tabs = []; - // add new tab - tabs.push({ - id: "fm-tab-newtab", - title: "New Tab", - handler: () => showInfo(), - icon: toolbar.icons.open, - }); - return tabs; - }; - } + const customizeToolbar = (toolbar) => { + let tabs = toolbar.getTabs(); + toolbar.getTabs = () => { + tabs = []; + // Add a new tab + tabs.push({ + id: "fm-tab-newtab", + title: "New Tab", + handler: () => showInfo(), + icon: toolbar.icons.open, + }); + return tabs; + }; + }; - return ( - <> -

Customizing the Toolbar

+ return ( + <> +

Customizing the Toolbar

-
-

You can add, remove, and update the Toolbar tabs.

-

In this demo, we’ve removed all the tabs and added a custom New Tab. - See our docs to learn more about the Toolbar and its - customization: Customizing the Toolbar. -

-
+
+

You can add, remove, and update the Toolbar tabs.

+

+ In this demo, we've removed all the tabs and added a custom New Tab. + See our docs to learn more about the Toolbar and its customization:{" "} + Customizing the Toolbar. +

+
- - - ); -}; + + + ); +} -export default CustomizingToolbar; \ No newline at end of file +export default CustomizingToolbar; diff --git a/ES6/src/components/ReactFlexmonsterExamples/HandlingEvents.jsx b/ES6/src/components/ReactFlexmonsterExamples/HandlingEvents.jsx index b0de7e0..9e93318 100644 --- a/ES6/src/components/ReactFlexmonsterExamples/HandlingEvents.jsx +++ b/ES6/src/components/ReactFlexmonsterExamples/HandlingEvents.jsx @@ -1,151 +1,149 @@ -import React, { useEffect, useRef, useState } from "react"; +import { useRef, useState } from "react"; import LogsList from "../UIElements/LogsList"; import ToggleButton from "../UIElements/ToggleButton"; import * as FlexmonsterReact from "react-flexmonster"; const eventList = [ - "afterchartdraw", - "aftergriddraw", - "beforegriddraw", - "beforetoolbarcreated", - "cellclick", - "celldoubleclick", - "chartclick", - "datachanged", - "dataerror", - "datafilecancelled", - "dataloaded", - "drillthroughclose", - "drillthroughopen", - "exportcomplete", - "exportstart", - "fieldslistclose", - "fieldslistopen", - "filterclose", - "filteropen", - "loadingdata", - "loadinglocalization", - "loadingolapstructure", - "loadingreportfile", - "localizationerror", - "localizationloaded", - "olapstructureerror", - "olapstructureloaded", - "openingreportfile", - "printcomplete", - "printstart", - "querycomplete", - "queryerror", - "ready", - "reportchange", - "reportcomplete", - "reportfilecancelled", - "reportfileerror", - "runningquery", - "update", + "afterchartdraw", + "aftergriddraw", + "beforegriddraw", + "beforetoolbarcreated", + "cellclick", + "celldoubleclick", + "chartclick", + "datachanged", + "dataerror", + "datafilecancelled", + "dataloaded", + "drillthroughclose", + "drillthroughopen", + "exportcomplete", + "exportstart", + "fieldslistclose", + "fieldslistopen", + "filterclose", + "filteropen", + "loadingdata", + "loadinglocalization", + "loadingolapstructure", + "loadingreportfile", + "localizationerror", + "localizationloaded", + "olapstructureerror", + "olapstructureloaded", + "openingreportfile", + "printcomplete", + "printstart", + "querycomplete", + "queryerror", + "ready", + "reportchange", + "reportcomplete", + "reportfilecancelled", + "reportfileerror", + "runningquery", + "update", ]; -function HandlingEvents(props) { - const [logs, setLogs] = useState([]); - const logsContainer = useRef(null); +function HandlingEvents() { + const pivotRef = useRef(null); + const [logs, setLogs] = useState([]); - const printLog = (log) => { - setLogs((prevLogs) => [ - ...prevLogs, - { - date: new Date(), - event: log, - }, - ]); - }; + const printLog = (log) => { + setLogs((prevLogs) => [ + ...prevLogs, + { + date: new Date(), + event: log, + }, + ]); + requestAnimationFrame(() => { + const logsContainer = document.getElementById("logsContainer"); + if (logsContainer) { + logsContainer.scrollTop = logsContainer.scrollHeight; + } + }); + }; - const signOffAllEvents = () => { - for (const eventName of eventList) { - // remove all handlers for specified event - pivotRef.current.flexmonster.off(eventName); - } - }; + const signOffAllEvents = () => { + for (const eventName of eventList) { + // Remove all handlers for the specified event + pivotRef.current.flexmonster.off(eventName); + } + }; - const signOnAllEvents = () => { - for (const eventName of eventList) { - // add handler for specified event - pivotRef.current.flexmonster.on(eventName, () => { - printLog(eventName); - }); - } - }; + const signOnAllEvents = () => { + for (const eventName of eventList) { + // Add a handler for the specified event + pivotRef.current.flexmonster.on(eventName, () => { + printLog(eventName); + }); + } + }; - useEffect(() => { - const logsContainerElement = logsContainer.current; - if (logsContainerElement) { - logsContainerElement.scrollTop = logsContainerElement.scrollHeight; - } - }, [logs]); + const clearLogs = () => { + setLogs([]); + }; - const clearLogs = () => { - setLogs([]); - }; + return ( + <> +

Handling Flexmonster events

- const pivotRef = useRef(null); +
+

+ Perform an action (for example, click on a grid cell) to trigger a{" "} + Flexmonster event. Scroll down to the log output to see which events get triggered. +

+
- return ( - <> -

Handling Flexmonster events

+
+ (isSigned ? signOnAllEvents() : signOffAllEvents())} + labelChecked="Events are tracked" + labelUnChecked="Events are not tracked" + /> +
-
-

- Perform an action (for example, click on a grid cell) to trigger a{" "} - - Flexmonster event - - . Scroll down to the log output to see which events get triggered. -

-
+
+ { + toolbar.showShareReportTab = true; + }} + shareReportConnection={{ + url: "https://olap.flexmonster.com:9500", + }} + //licenseKey="XXXX-XXXX-XXXX-XXXX-XXXX" + /> +
-
- - isSigned ? signOnAllEvents() : signOffAllEvents() - } - labelChecked="Events are tracked" - labelUnChecked="Events are not tracked" - /> -
- -
- { - toolbar.showShareReportTab = true; - }} - shareReportConnection={{ - url: "https://olap.flexmonster.com:9500", - }} - width="100%" - height={600} - ready={signOnAllEvents} - report="https://cdn.flexmonster.com/github/demo-report.json" - //licenseKey="XXXX-XXXX-XXXX-XXXX-XXXX" - /> -
- -
- -
- -
-
- - ); -}; +
+ +
+ +
+
+ + ); +} export default HandlingEvents; diff --git a/ES6/src/components/ReactFlexmonsterExamples/PivotTableDemo.jsx b/ES6/src/components/ReactFlexmonsterExamples/PivotTableDemo.jsx index f3798a1..cedfc33 100644 --- a/ES6/src/components/ReactFlexmonsterExamples/PivotTableDemo.jsx +++ b/ES6/src/components/ReactFlexmonsterExamples/PivotTableDemo.jsx @@ -1,39 +1,43 @@ -import React, { useRef } from 'react'; -import * as FlexmonsterReact from 'react-flexmonster'; +import * as FlexmonsterReact from "react-flexmonster"; function PivotTableDemo() { + return ( + <> +

Pivot Table Demo

- return ( - <> -

Pivot Table Demo

+
+

Flexmonster is a fast and powerful JavaScript pivot grid for data visualization and reporting.

+

+ With Flexmonster, you can create reports based on many data sources, including JSON, CSV, MongoDB, + and SQL databases. Our component is easy to customize and configure, so it can be seamlessly integrated into any project. +

+

+ Visit{" "} + our documentation for step-by-step guidance on Flexmonster. +

+
-
-

Flexmonster is a fast and powerful JavaScript pivot grid for data visualization and reporting.

-

With Flexmonster, you can create reports based on many data sources, including JSON, CSV, MongoDB, and SQL - databases. - Our component is easy to customize and configure, so it can be seamlessly integrated into any project. -

-

Visit our documentation for step-by-step guidance on - Flexmonster.

-
- -
- { - toolbar.showShareReportTab = true; - }} - shareReportConnection={{ - url: "https://olap.flexmonster.com:9500" - }} - width="100%" - height={600} - report="https://cdn.flexmonster.com/github/demo-report.json" - //licenseKey="XXXX-XXXX-XXXX-XXXX-XXXX" - /> -
- - ); +
+ { + toolbar.showShareReportTab = true; + }} + shareReportConnection={{ + url: "https://olap.flexmonster.com:9500", + }} + //licenseKey="XXXX-XXXX-XXXX-XXXX-XXXX" + /> +
+ + ); } export default PivotTableDemo; diff --git a/ES6/src/components/ReactFlexmonsterExamples/UpdatingData.jsx b/ES6/src/components/ReactFlexmonsterExamples/UpdatingData.jsx index 65a9ae2..0ecb357 100644 --- a/ES6/src/components/ReactFlexmonsterExamples/UpdatingData.jsx +++ b/ES6/src/components/ReactFlexmonsterExamples/UpdatingData.jsx @@ -1,117 +1,123 @@ -import React, { useRef } from "react"; +import { useRef } from "react"; import * as FlexmonsterReact from "react-flexmonster"; function UpdatingData() { - const pivotRef = useRef(null); + const pivotRef = useRef(null); - let data = [ - { - Category: "Accessories", - Size: "262 oz", - Color: "red", - Destination: "Australia", - "Business Type": "Specialty Bike Shop", - Country: "Australia", - Price: 100, - Quantity: 225, - Discount: 23, - }, - { - Category: "Components", - Size: "235 oz", - Color: "green", - Destination: "Australia", - "Business Type": "Warehouse", - Country: "Australia", - Price: 200, - Quantity: 1950, - Discount: 51, - }, - ]; + let data = [ + { + "Category": "Accessories", + "Size": "262 oz", + "Color": "red", + "Destination": "Australia", + "Business Type": "Specialty Bike Shop", + "Country": "Australia", + "Price": 100, + "Quantity": 225, + "Discount": 23, + }, + { + "Category": "Components", + "Size": "235 oz", + "Color": "green", + "Destination": "Australia", + "Business Type": "Warehouse", + "Country": "Australia", + "Price": 200, + "Quantity": 1950, + "Discount": 51, + }, + ]; - const onReady = () => { - // Connect Flexmonster to the data - pivotRef.current.flexmonster.connectTo({ data: data }); - }; + const onReady = () => { + // Connect Flexmonster to the data + pivotRef.current.flexmonster.connectTo({ data: data }); + }; - const updateTheData = () => { - // If the data in React got updated, for example: - data = [ - { - Category: "Accessories", - Size: "262 oz", - Color: "red", - Destination: "Australia", - "Business Type": "Specialty Bike Shop", - Country: "Australia", - Price: Math.floor(Math.random() * Math.floor(1000)), - Quantity: 225, - Discount: 23, - }, - { - Category: "Components", - Size: "307 oz", - Color: "white", - Destination: "United Kingdom", - "Business Type": "Warehouse", - Country: "Canada", - Price: Math.floor(Math.random() * Math.floor(1000)), - Quantity: 8212, - Discount: 55, - }, - ]; - // then the data needs to be updated in Flexmonster as well - // this can be done via Flexmonster's updateData() API call: - pivotRef.current.flexmonster.updateData({ data: data }); - }; + const updateTheData = () => { + // If the data in React got updated, for example: + data = [ + { + "Category": "Accessories", + "Size": "262 oz", + "Color": "red", + "Destination": "Australia", + "Business Type": "Specialty Bike Shop", + "Country": "Australia", + "Price": Math.floor(Math.random() * Math.floor(1000)), + "Quantity": 225, + "Discount": 23, + }, + { + "Category": "Components", + "Size": "307 oz", + "Color": "white", + "Destination": "United Kingdom", + "Business Type": "Warehouse", + "Country": "Canada", + "Price": Math.floor(Math.random() * Math.floor(1000)), + "Quantity": 8212, + "Discount": 55, + }, + { + "Category": "Clothes", + "Size": "400 oz", + "Color": "blue", + "Destination": "Belgium", + "Business Type": "Warehouse", + "Country": "France", + "Price": Math.floor(Math.random() * Math.floor(1000)), + "Quantity": 7978, + "Discount": 30, + }, + ]; + // Then the data needs to be updated in Flexmonster as well + // This can be done via Flexmonster's updateData() API call + pivotRef.current.flexmonster.updateData({ data: data }); + }; - return ( - <> -

Updating the data in Flexmonster

+ return ( + <> +

Updating the data in Flexmonster

-
-

- This demo shows how to refresh the data at runtime and keep the slice, - options, and formatting the same. -

-

- Try it yourself: configure the component as you wish and click the{" "} - UPDATE DATA button. -

-

- Learn more about updating the data in{" "} - - our documentation - - . -

-
+
+

This demo shows how to refresh the data at runtime and keep the slice, options, and formatting the same.

+

+ Try it yourself: configure the component as you wish and click the UPDATE DATA button. +

+

+ Learn more about updating the data in{" "} + our documentation. +

+
- + - { - toolbar.showShareReportTab = true; - }} - shareReportConnection={{ - url: "https://olap.flexmonster.com:9500", - }} - width="100%" - height={400} - ready={onReady} - //licenseKey="XXXX-XXXX-XXXX-XXXX-XXXX" - /> - - ); + { + toolbar.showShareReportTab = true; + }} + shareReportConnection={{ + url: "https://olap.flexmonster.com:9500", + }} + height={400} + ready={onReady} + //licenseKey="XXXX-XXXX-XXXX-XXXX-XXXX" + /> + + ); } export default UpdatingData; diff --git a/ES6/src/components/ReactFlexmonsterExamples/UsingAPICalls.jsx b/ES6/src/components/ReactFlexmonsterExamples/UsingAPICalls.jsx index 76b235a..3fe8a4d 100644 --- a/ES6/src/components/ReactFlexmonsterExamples/UsingAPICalls.jsx +++ b/ES6/src/components/ReactFlexmonsterExamples/UsingAPICalls.jsx @@ -1,101 +1,87 @@ -import React, { useRef } from 'react'; -import ToggleSwitch from '../UIElements/ToggleSwitch'; -import * as FlexmonsterReact from 'react-flexmonster'; +import { useRef } from "react"; +import ToggleSwitch from "../UIElements/ToggleSwitch"; +import * as FlexmonsterReact from "react-flexmonster"; function UsingAPICalls() { - const pivotRef = useRef(null); + const pivotRef = useRef(null); - const showChart = () => { - pivotRef.current.flexmonster.showCharts("column"); - }; + const showChart = () => { + pivotRef.current.flexmonster.showCharts("column"); + }; - const showGrid = () => { - pivotRef.current.flexmonster.showGrid(); - }; + const showGrid = () => { + pivotRef.current.flexmonster.showGrid(); + }; - const controllGridCharts = (isGrid) => { - isGrid ? showGrid() : showChart(); - }; + const switchGridCharts = (isGrid) => { + isGrid ? showGrid() : showChart(); + }; - const controllInteractiveness = (isInteractive) => { - isInteractive ? interactive() : readOnly(); - }; + const toggleInteractiveness = (isInteractive) => { + isInteractive ? interactive() : readOnly(); + }; - const readOnly = () => { - pivotRef.current.flexmonster.setOptions({ - readOnly: true, - }); - pivotRef.current.flexmonster.refresh(); - }; + const readOnly = () => { + pivotRef.current.flexmonster.setOptions({ + readOnly: true, + }); + pivotRef.current.flexmonster.refresh(); + }; - const interactive = () => { - pivotRef.current.flexmonster.setOptions({ - readOnly: false, - }); - pivotRef.current.flexmonster.refresh(); - }; + const interactive = () => { + pivotRef.current.flexmonster.setOptions({ + readOnly: false, + }); + pivotRef.current.flexmonster.refresh(); + }; - const hideContextMenu = () => { - pivotRef.current.flexmonster.customizeContextMenu(() => { - return []; - }); - }; + return ( + <> +

Using Flexmonster API calls

- const showContextMenu = () => { - pivotRef.current.flexmonster.customizeContextMenu(null); - }; +
+

+ Flexmonster provides{" "} + API calls for interacting with the component. As an example, we've added + the toggle buttons below. Use them to switch between the views or make Flexmonster read-only. +

+
- return ( - <> -

Using Flexmonster API calls

+
+ + +
-
-

- Flexmonster provides - API calls - for interacting with the component. As an example, we've added the - toggle buttons below. Use them to switch between the views or make - Flexmonster read-only. -

-
- -
- - -
- - { - toolbar.showShareReportTab = true; - }} - shareReportConnection={{ - url: "https://olap.flexmonster.com:9500", - }} - componentFolder="https://cdn.flexmonster.com/" - width="100%" - height={600} - report="https://cdn.flexmonster.com/github/demo-report.json" - //licenseKey="XXXX-XXXX-XXXX-XXXX-XXXX" - /> - - ); -}; + { + toolbar.showShareReportTab = true; + }} + shareReportConnection={{ + url: "https://olap.flexmonster.com:9500", + }} + //licenseKey="XXXX-XXXX-XXXX-XXXX-XXXX" + /> + + ); +} export default UsingAPICalls; - diff --git a/ES6/src/components/ReactFlexmonsterExamples/WithAmcharts.jsx b/ES6/src/components/ReactFlexmonsterExamples/WithAmcharts.jsx index 4f7362b..021ec48 100644 --- a/ES6/src/components/ReactFlexmonsterExamples/WithAmcharts.jsx +++ b/ES6/src/components/ReactFlexmonsterExamples/WithAmcharts.jsx @@ -1,149 +1,141 @@ -import React, { useEffect, useRef } from 'react'; -import * as FlexmonsterReact from 'react-flexmonster'; -import 'flexmonster/lib/flexmonster.amcharts.js'; -import * as am5 from '@amcharts/amcharts5'; -import * as am5xy from '@amcharts/amcharts5/xy'; -import am5themes_Animated from '@amcharts/amcharts5/themes/Animated'; +import { useEffect, useRef } from "react"; +import * as FlexmonsterReact from "react-flexmonster"; +// Importing Flexmonster Connector for amCharts +import "flexmonster/lib/flexmonster.amcharts.js"; -function WithAmcharts() { - const pivotRef = useRef(null); - const rootRef = useRef(null); - - const reportComplete = () => { - pivotRef.current.flexmonster.off('reportcomplete', reportComplete); - drawChart(); - }; +// Importing amCharts +import * as am5 from "@amcharts/amcharts5"; +import * as am5percent from "@amcharts/amcharts5/percent"; +import am5themes_Animated from "@amcharts/amcharts5/themes/Animated"; - const drawChart = () => { - pivotRef.current.flexmonster.amcharts.getData( - {}, - (chartData, rawData) => createChart(chartData, rawData), - (chartData, rawData) => updateChart(chartData, rawData) - ); - }; +function WithAmcharts() { + const pivotRef = useRef(null); + let root; + + const reportComplete = () => { + pivotRef.current.flexmonster.off("reportcomplete"); + drawChart(); + }; + + const drawChart = () => { + // Running Flexmonster's getData() method for amCharts + pivotRef.current.flexmonster.amcharts.getData({}, createChart, updateChart); + }; + + const createChart = (chartData, rawData) => { + // Initializing the root element + root = am5.Root.new("amcharts-container"); + // Applying the amCharts theme + root.setThemes([am5themes_Animated.new(root)]); + // Applying number format from Flexmonster + root.numberFormatter.set("numberFormat", pivotRef.current.flexmonster.amcharts.getNumberFormatPattern(rawData.meta.formats[0])); + + // Creating a chart instance + const chart = root.container.children.push( + am5percent.PieChart.new(root, { + layout: root.verticalLayout, + innerRadius: 100, + }) + ); - const createChart = (chartData, rawData) => { - const root = am5.Root.new('amcharts-container'); - rootRef.current = root; - - const chart = root.container.children.push( - am5xy.XYChart.new(root, {}) - ); - - root.setThemes([am5themes_Animated.new(root)]); - - root.numberFormatter.set( - 'numberFormat', - pivotRef.current.flexmonster.amcharts.getNumberFormatPattern( - rawData.meta.formats[0] - ) - ); - - const yAxis = chart.yAxes.push( - am5xy.CategoryAxis.new(root, { - categoryField: pivotRef.current.flexmonster.amcharts.getCategoryName( - rawData - ), - renderer: am5xy.AxisRendererY.new(root, { - cellStartLocation: 0.1, - cellEndLocation: 0.9, - }), - }) - ); - - const xAxis = chart.xAxes.push(am5xy.ValueAxis.new(root, { - renderer: am5xy.AxisRendererX.new(root, {}), - })); - - xAxis.set('numberFormatter', am5.NumberFormatter.new(root, { - 'numberFormat': '#a' - })); - - const series = chart.series.push( - am5xy.ColumnSeries.new(root, { - name: pivotRef.current.flexmonster.amcharts.getMeasureNameByIndex( - rawData, - 0 - ), - xAxis: xAxis, - yAxis: yAxis, - sequencedInterpolation: true, - valueXField: pivotRef.current.flexmonster.amcharts.getMeasureNameByIndex( - rawData, - 0 - ), - categoryYField: pivotRef.current.flexmonster.amcharts.getCategoryName( - rawData - ), - tooltip: am5.Tooltip.new(root, { - labelText: '{name}: [bold]{valueX}[/]', - }), - }) - ); - - chart.set('cursor', am5xy.XYCursor.new(root, { - behavior: 'none', - xAxis: xAxis, - yAxis: yAxis, - })); - - yAxis.data.setAll(chartData.data); - series.data.setAll(chartData.data); - - series.appear(1000); - chart.appear(1000, 100); - }; + const series = chart.series.push( + am5percent.PieSeries.new(root, { + valueField: pivotRef.current.flexmonster.amcharts.getMeasureNameByIndex(rawData, 0), + categoryField: pivotRef.current.flexmonster.amcharts.getCategoryName(rawData), + }) + ); - const updateChart = (chartData, rawData) => { - if (rootRef.current) { - rootRef.current.dispose(); - } - createChart(chartData, rawData); - }; + series.children.push( + am5.Label.new(root, { + text: "[#999]TOTAL:[/]\n{valueSum.formatNumber()}", + populateText: true, + textAlign: "center", + centerX: am5.p50, + centerY: am5.p50, + fontSize: 24, + fontWeight: "500", + fill: am5.color(0x555555), + oversizedBehavior: "fit", + }) + ); - return ( -
-

Integrating with amCharts

- -
-

- Extend Flexmonster’s visualization functionality by integrating - with the amCharts library:{' '} - - Integration with amCharts - - . -

-
- - { - toolbar.showShareReportTab = true; - }} - reportcomplete={reportComplete} - shareReportConnection={{ - url: 'https://olap.flexmonster.com:9500', - }} - width="100%" - height={600} - report="https://cdn.flexmonster.com/github/demo-report.json" - licenseFilePath="https://cdn.flexmonster.com/jsfiddle.charts.key" - /> -
-
-
-
+ series.slices.template.set("tooltipText", "{category}: {value} ({valuePercentTotal.formatNumber('0.00')}%)"); + series.labels.template.set("visible", false); + series.ticks.template.set("visible", false); + + series.data.setAll(chartData.data); + + const legend = chart.children.push( + am5.Legend.new(root, { + centerX: am5.percent(50), + x: am5.percent(50), + layout: am5.GridLayout.new(root, { + maxColumns: 3, + fixedWidthGrid: true, + }), + height: am5.percent(20), + verticalScrollbar: am5.Scrollbar.new(root, { + orientation: "vertical", + }), + }) ); -}; + legend.data.setAll(series.dataItems); + legend.valueLabels.template.set("forceHidden", true); + + series.appear(1000); + chart.appear(1000, 100); + }; + + const updateChart = (chartData, rawData) => { + root?.dispose(); + createChart(chartData, rawData); + }; + + useEffect(() => { + return () => { + // Disposing of the chart instance when the component is unmounted + root?.dispose(); + }; + }, []); + + return ( + <> +

Integrating with amCharts

+ +
+

+ Extend Flexmonster's visualization functionality by integrating with the amCharts library:{" "} + Integration with amCharts. +

+
+ + { + toolbar.showShareReportTab = true; + }} + reportcomplete={reportComplete} + shareReportConnection={{ + url: "https://olap.flexmonster.com:9500", + }} + licenseFilePath='https://cdn.flexmonster.com/jsfiddle.charts.key' + /> +
+
+
+ + ); +} export default WithAmcharts; diff --git a/ES6/src/components/ReactFlexmonsterExamples/WithAmcharts4.jsx b/ES6/src/components/ReactFlexmonsterExamples/WithAmcharts4.jsx index 8bfcee0..13af1da 100644 --- a/ES6/src/components/ReactFlexmonsterExamples/WithAmcharts4.jsx +++ b/ES6/src/components/ReactFlexmonsterExamples/WithAmcharts4.jsx @@ -1,107 +1,99 @@ -import React, { useEffect, useRef } from 'react'; -import * as FlexmonsterReact from 'react-flexmonster'; +import { useEffect, useRef } from "react"; +import * as FlexmonsterReact from "react-flexmonster"; -import 'flexmonster/lib/flexmonster.amcharts.js'; -import * as am4core from '@amcharts/amcharts4/core'; -import * as am4charts from '@amcharts/amcharts4/charts'; -import am4themes_animated from '@amcharts/amcharts4/themes/animated'; +import "flexmonster/lib/flexmonster.amcharts.js"; +import * as am4core from "@amcharts/amcharts4/core"; +import * as am4charts from "@amcharts/amcharts4/charts"; +import am4themes_animated from "@amcharts/amcharts4/themes/animated"; -function WithAmcharts4() { - const pivotRef = useRef(null); - const chartRef = useRef(null); - - const reportComplete = () => { - pivotRef.current.flexmonster.off('reportcomplete', reportComplete); - drawChart(); - }; - - const drawChart = () => { - pivotRef.current.flexmonster.amcharts.getData( - {}, - (chartData, rawData) => createChart(chartData, rawData), - (chartData, rawData) => updateChart(chartData, rawData) - ); - }; - - const createChart = (chartData, rawData) => { - /* Apply amCharts theme */ - am4core.useTheme(am4themes_animated); - - /* Create chart instance */ - let chart = am4core.create("amcharts-container", am4charts.PieChart); - - /* Add data processed by Flexmonster to the chart */ - chart.data = chartData.data; +// Applying the amCharts theme +am4core.useTheme(am4themes_animated); - /* Set an inner radius to transform a pie chart into a donut chart */ - chart.innerRadius = am4core.percent(50); - - /* Create and configure series for a pie chart */ - var pieSeries = chart.series.push(new am4charts.PieSeries()); - pieSeries.dataFields.category = pivotRef.current.flexmonster.amcharts.getCategoryName(rawData); - pieSeries.dataFields.value = pivotRef.current.flexmonster.amcharts.getMeasureNameByIndex(rawData, 0); - pieSeries.slices.template.stroke = am4core.color("#fff"); - pieSeries.slices.template.strokeWidth = 2; - pieSeries.slices.template.strokeOpacity = 1; - - /* Create initial animation */ - pieSeries.hiddenState.properties.opacity = 1; - pieSeries.hiddenState.properties.endAngle = -90; - pieSeries.hiddenState.properties.startAngle = -90; - - chartRef.current = chart; - }; - - const updateChart = (chartData, rawData) => { - if (chartRef.current) { - chartRef.current.dispose(); - } - createChart(chartData, rawData); +function WithAmcharts4() { + const pivotRef = useRef(null); + const chartRef = useRef(null); + + const reportComplete = () => { + pivotRef.current.flexmonster.off("reportcomplete"); + drawChart(); + }; + + const drawChart = () => { + pivotRef.current.flexmonster.amcharts.getData({}, createChart, updateChart); + }; + + const createChart = (chartData, rawData) => { + // Creating a chart instance + const chart = am4core.create("amcharts-container", am4charts.PieChart); + + // Adding data processed by Flexmonster to the chart + chart.data = chartData.data; + + // Creating and configuring series for a pie chart + const pieSeries = chart.series.push(new am4charts.PieSeries()); + pieSeries.dataFields.category = pivotRef.current.flexmonster.amcharts.getCategoryName(rawData); + pieSeries.dataFields.value = pivotRef.current.flexmonster.amcharts.getMeasureNameByIndex(rawData, 0); + pieSeries.slices.template.stroke = am4core.color("#fff"); + pieSeries.slices.template.strokeWidth = 3; + pieSeries.slices.template.strokeOpacity = 1; + + // Creating initial animation + pieSeries.hiddenState.properties.opacity = 1; + pieSeries.hiddenState.properties.endAngle = -90; + pieSeries.hiddenState.properties.startAngle = -90; + + chartRef.current = chart; + }; + + const updateChart = (chartData, rawData) => { + chartRef.current?.dispose(); + createChart(chartData, rawData); + }; + + useEffect(() => { + return () => { + chartRef.current?.dispose(); }; - - return ( -
-

Integrating with amCharts

- -
-

- Extend Flexmonster’s visualization functionality by integrating - with the amCharts library:{' '} - - Integration with amCharts - - . -

-
- - { - toolbar.showShareReportTab = true; - }} - reportcomplete={reportComplete} - shareReportConnection={{ - url: 'https://olap.flexmonster.com:9500', - }} - width="100%" - height={600} - report="https://cdn.flexmonster.com/github/demo-report.json" - licenseFilePath="https://cdn.flexmonster.com/jsfiddle.charts.key" - /> -
-
-
-
- ); -}; + }, []); + + return ( + <> +

Integrating with amCharts 4

+ +
+

+ Extend Flexmonster's visualization functionality by integrating with the amCharts library:{" "} + Integration with amCharts. +

+
+ + { + toolbar.showShareReportTab = true; + }} + reportcomplete={reportComplete} + shareReportConnection={{ + url: "https://olap.flexmonster.com:9500", + }} + licenseFilePath="https://cdn.flexmonster.com/jsfiddle.charts.key" + /> +
+
+
+ + ); +} export default WithAmcharts4; diff --git a/ES6/src/components/ReactFlexmonsterExamples/WithHighcharts.jsx b/ES6/src/components/ReactFlexmonsterExamples/WithHighcharts.jsx index 2acbb7a..287fb8c 100644 --- a/ES6/src/components/ReactFlexmonsterExamples/WithHighcharts.jsx +++ b/ES6/src/components/ReactFlexmonsterExamples/WithHighcharts.jsx @@ -1,70 +1,73 @@ -import React, { useEffect, useRef } from 'react'; -import * as FlexmonsterReact from 'react-flexmonster'; -import 'flexmonster/lib/flexmonster.highcharts.js'; -import Highcharts from 'highcharts'; +import { useRef, useState } from "react"; +import * as FlexmonsterReact from "react-flexmonster"; +import "flexmonster/lib/flexmonster.highcharts.js"; + +import Highcharts from "highcharts"; +import HighchartsReact from "highcharts-react-official"; +import "highcharts/modules/accessibility"; function WithHighcharts() { - const pivotRef = useRef(null); + const pivotRef = useRef(null); + const [chartOptions, setChartOptions] = useState({}); - const reportComplete = () => { - pivotRef.current.flexmonster.off('reportcomplete', reportComplete); - createChart(); - }; + const reportComplete = () => { + pivotRef.current.flexmonster.off("reportcomplete"); + createChart(); + }; - const createChart = () => { - pivotRef.current.flexmonster.highcharts.getData( - { - type: 'spline', - }, - function (data) { - Highcharts.chart('highcharts-container', data); - }, - function (data) { - Highcharts.chart('highcharts-container', data); - } - ); - }; + const createChart = () => { + pivotRef.current.flexmonster.highcharts.getData( + { + type: "spline", + }, + function (data) { + setChartOptions(data); + }, + function (data) { + setChartOptions(data); + } + ); + }; - return ( -
-

Integrating with Highcharts

+ return ( + <> +

Integrating with Highcharts

-
-

- Integrate Flexmonster with Highcharts and see your data from a new - perspective: - Integration with Highcharts - - . -

-
+
+

+ Integrate Flexmonster with Highcharts and see your data from a new perspective:{" "} + Integration with Highcharts. +

+
- { - toolbar.showShareReportTab = true; - }} - reportcomplete={reportComplete} - shareReportConnection={{ - url: 'https://olap.flexmonster.com:9500', - }} - width="100%" - height={600} - report="https://cdn.flexmonster.com/github/highcharts-report.json" - licenseFilePath="https://cdn.flexmonster.com/jsfiddle.charts.key" - //licenseKey="XXXX-XXXX-XXXX-XXXX-XXXX" - /> -
-
-
-
- ); -}; + { + toolbar.showShareReportTab = true; + }} + reportcomplete={reportComplete} + shareReportConnection={{ + url: "https://olap.flexmonster.com:9500", + }} + licenseFilePath="https://cdn.flexmonster.com/jsfiddle.charts.key" + //licenseKey="XXXX-XXXX-XXXX-XXXX-XXXX" + /> +
+ +
+ + ); +} export default WithHighcharts; diff --git a/ES6/src/components/UIElements/LogsList.jsx b/ES6/src/components/UIElements/LogsList.jsx index d6ae623..b47dc2d 100644 --- a/ES6/src/components/UIElements/LogsList.jsx +++ b/ES6/src/components/UIElements/LogsList.jsx @@ -1,28 +1,41 @@ import React from "react"; const LogsList = React.forwardRef((props, ref) => { - const { logsList, title } = props; - - const logsTemplate = logsList.map((logElement, index) => { - const docRef = `https://www.flexmonster.com/api/${logElement.event}/?r=rm_react`; - return
- [ Event ] {logElement.date.toLocaleTimeString()}: - {logElement.event + " "} - [ see details ] -
- }); + const { logsList, title, id } = props; + const logsTemplate = logsList.map((logElement, index) => { + const docRef = `https://www.flexmonster.com/api/${logElement.event}/?r=rm_react`; return ( - <> -

{title}

-
-
- {logsTemplate} -
-
- +
+ [ Event ] {logElement.date.toLocaleTimeString()}: + {logElement.event + " "}[{" "} + + see details + {" "} + ] +
); + }); + + return ( + <> +

{title}

+
+
{logsTemplate}
+
+ + ); }); export default LogsList; diff --git a/nextjs-ts/package.json b/nextjs-ts/package.json index 00d4de9..23227c0 100644 --- a/nextjs-ts/package.json +++ b/nextjs-ts/package.json @@ -11,18 +11,18 @@ "lint": "next lint" }, "dependencies": { - "@amcharts/amcharts4": "^4.10.36", - "@amcharts/amcharts5": "^5.3.15", - "@types/node": "20.2.5", - "@types/react": "^19.0.0", - "@types/react-dom": "^19.0.0", + "@amcharts/amcharts4": "^4.10.40", + "@amcharts/amcharts5": "^5.13.4", + "@types/node": "^20.19.0 || >=22.12.0", + "@types/react": "^19.1.9", + "@types/react-dom": "^19.1.7", "flexmonster": "latest", - "highcharts": "^11.1.0", - "next": "15.1.3", - "open-cli": "^7.2.0", - "react": "^19.0.0", - "react-dom": "^19.0.0", + "highcharts-react-official": "^3.2.2", + "next": "15.4.5", + "open-cli": "^8.0.0", + "react": "^19.1.1", + "react-dom": "^19.1.1", "react-flexmonster": "latest", - "typescript": "5.1.3" + "typescript": "5.8.3" } } diff --git a/nextjs-ts/src/UIElements/LogsList.tsx b/nextjs-ts/src/UIElements/LogsList.tsx index fab2de4..e08e8b5 100644 --- a/nextjs-ts/src/UIElements/LogsList.tsx +++ b/nextjs-ts/src/UIElements/LogsList.tsx @@ -1,38 +1,52 @@ type Props = { - logsList: { - date: Date, - event: string - }[], - title: string + logsList: { + date: Date; + event: string; + }[]; + title: string; + id?: string; }; const LogsList = (props: Props) => { + const { logsList, title, id } = props; - const {logsList, title} = props; - - const logsTemplate = logsList.map((logElement: { - date: Date, - event: string - }, index: number) => { - const docRef = `https://www.flexmonster.com/api/${logElement.event}/?r=rm_react`; - return
- [ Event ] { logElement.date.toLocaleTimeString()}: - {logElement.event + " "} - [ see details ] + const logsTemplate = logsList.map( + ( + logElement: { + date: Date; + event: string; + }, + index: number + ) => { + const docRef = `https://www.flexmonster.com/api/${logElement.event}/?r=rm_react`; + return ( +
+ [ Event ] {logElement.date.toLocaleTimeString()}: + {logElement.event + " "}[{" "} + + see details + {" "} + ]
- }) - return ( - <> -

{title}

-
-
- {logsTemplate} -
-
- - ); - -} + ); + } + ); + return ( + <> +

{title}

+
+
{logsTemplate}
+
+ + ); +}; -export default LogsList; \ No newline at end of file +export default LogsList; diff --git a/nextjs-ts/src/UIElements/TopMenu.tsx b/nextjs-ts/src/UIElements/TopMenu.tsx index 1efe629..02bae2f 100644 --- a/nextjs-ts/src/UIElements/TopMenu.tsx +++ b/nextjs-ts/src/UIElements/TopMenu.tsx @@ -11,7 +11,7 @@ export default function TopMenu() {
  • - Integration with React + Integration with Next.js
  • Docs diff --git a/nextjs-ts/src/app/customizing-grid/page.tsx b/nextjs-ts/src/app/customizing-grid/page.tsx index 3d60195..f3aa4a5 100644 --- a/nextjs-ts/src/app/customizing-grid/page.tsx +++ b/nextjs-ts/src/app/customizing-grid/page.tsx @@ -1,99 +1,91 @@ -// Must be a client component because we pass function in the beforetoolbarcreated param -"use client" -import * as React from "react"; +// Must be a client component because we pass a function in the beforetoolbarcreated param +"use client"; +import { useRef } from "react"; import ToggleButton from "@/UIElements/ToggleButton"; -// Types are static, so we can safely import it for use in references -import type {Pivot} from "react-flexmonster"; +// Types are static, so we can safely import them to use in refs +import type { Pivot } from "react-flexmonster"; import dynamic from "next/dynamic"; -// Wrapper must be imported dynamically, since it contains Flexmonster pivot -const FlexmonsterPivot = dynamic(() => import('@/UIElements/PivotWrapper'), { - ssr: false, - loading: () =>

    Loading Flexmonster...

    +// Wrapper must be imported dynamically, since it contains Flexmonster Pivot +const FlexmonsterPivot = dynamic(() => import("@/UIElements/PivotWrapper"), { + ssr: false, + loading: () =>

    Loading Flexmonster...

    , }); export default function CustomizingGrid() { + const pivotRef: React.RefObject = useRef(null); - const pivotRef: React.RefObject = React.useRef(null); - - const customizeCellFunction = (cell: Flexmonster.CellBuilder, data: Flexmonster.CellData) => { - if (data.measure && data.measure.uniqueName === "Price") { - let backgroundColor = "#00A45A"; - let textShadowColor = "#095231"; - let borderColor = "#009552"; - cell.style = { - ...cell.style, - "background-color": backgroundColor, - "color": "white", - "font-weight": "bold", - "text-shadow": `0px 2px 3px ${textShadowColor}`, - "border-bottom": `1px solid ${borderColor}`, - "border-right": `1px solid ${borderColor}`, - }; - } + const customizeCellFunction = (cell: Flexmonster.CellBuilder, data: Flexmonster.CellData) => { + if (data.measure && data.measure.uniqueName === "Price") { + let backgroundColor = "#00A45A"; + let textShadowColor = "#095231"; + let borderColor = "#009552"; + cell.style = { + ...cell.style, + "background-color": backgroundColor, + "color": "white", + "font-weight": "bold", + "text-shadow": `0px 2px 3px ${textShadowColor}`, + "border-bottom": `1px solid ${borderColor}`, + "border-right": `1px solid ${borderColor}`, + }; } + }; - const controlCustomization = (isCustomized: boolean) => { - isCustomized ? applyCustomization() : removeCustomization() - } + const toggleCustomization = (isCustomized: boolean) => { + isCustomized ? applyCustomization() : removeCustomization(); + }; - const removeCustomization = () => { - pivotRef.current?.flexmonster.customizeCell((null as any)); - } + const removeCustomization = () => { + pivotRef.current?.flexmonster.customizeCell(null as any); + }; - const applyCustomization = () => { - //running grid customization using "customizeCellFunction" - pivotRef.current?.flexmonster.customizeCell(customizeCellFunction); - } + const applyCustomization = () => { + pivotRef.current?.flexmonster.customizeCell(customizeCellFunction); + }; - return ( - <> -

    Customizing the grid

    + return ( + <> +

    Customizing the grid

    -
    -

    - Style the grid by adding links, applying custom CSS, or formatting the - cells. Check our docs for details:{" "} - - Customizing the grid - - . -

    -

    - In this demo, the Price measure is customized. -

    -
    +
    +

    + Style the grid by adding links, applying custom CSS, or formatting the cells. Check our docs for details:{" "} + Customizing the grid cells. +

    +

    + In this demo, the Price measure is customized. +

    +
    -
    - -
    +
    + +
    - { - toolbar.showShareReportTab = true; - }} - shareReportConnection={{ - url: "https://olap.flexmonster.com:9500" - }} - width="100%" - height={600} - report="https://cdn.flexmonster.com/github/customizing-grid-report.json" - //licenseKey="XXXX-XXXX-XXXX-XXXX-XXXX" - /> - - ); - -} \ No newline at end of file + { + toolbar.showShareReportTab = true; + }} + shareReportConnection={{ + url: "https://olap.flexmonster.com:9500", + }} + //licenseKey="XXXX-XXXX-XXXX-XXXX-XXXX" + /> + + ); +} diff --git a/nextjs-ts/src/app/customizing-toolbar/page.tsx b/nextjs-ts/src/app/customizing-toolbar/page.tsx index eec079e..81848f8 100644 --- a/nextjs-ts/src/app/customizing-toolbar/page.tsx +++ b/nextjs-ts/src/app/customizing-toolbar/page.tsx @@ -1,67 +1,70 @@ -// Must be a client component because we pass function in the beforetoolbarcreated param -"use client" -import * as React from "react"; -// Types are static, so we can safely import it for use in references -import type {Pivot} from "react-flexmonster"; +// Must be a client component because we pass a function in the beforetoolbarcreated param +"use client"; +import { useRef } from "react"; +// Types are static, so we can safely import them to use in refs +import type { Pivot } from "react-flexmonster"; import dynamic from "next/dynamic"; -// Wrapper must be imported dynamically, since it contains Flexmonster pivot -const FlexmonsterPivot = dynamic(() => import('@/UIElements/PivotWrapper'), { - ssr: false, - loading: () =>

    Loading Flexmonster...

    - }); +// Wrapper must be imported dynamically, since it contains Flexmonster Pivot +const FlexmonsterPivot = dynamic(() => import("@/UIElements/PivotWrapper"), { + ssr: false, + loading: () =>

    Loading Flexmonster...

    , +}); export default function CustomizingToolba() { + const pivotRef: React.RefObject = useRef(null); - const pivotRef: React.RefObject = React.useRef(null); + const customizeToolbar = (toolbar: Flexmonster.Toolbar) => { + let tabs = toolbar.getTabs(); + toolbar.getTabs = () => { + tabs = []; + // Add a new tab + tabs.push({ + id: "fm-tab-newtab", + title: "New Tab", + handler: () => showInfo(), + icon: toolbar.icons.open, + }); + return tabs; + }; + }; - const showInfo = () => { - pivotRef.current?.flexmonster.alert({ - title: "Customizing Flexmonster", - message: - "How to customize the Toolbar: https://www.flexmonster.com/doc/customizing-toolbar/
    ", - type: "info", - blocking: false, - }); - } + const showInfo = () => { + pivotRef.current?.flexmonster.alert({ + title: "Customizing Flexmonster", + message: + "How to customize the Toolbar: https://www.flexmonster.com/doc/customizing-toolbar/
    ", + type: "info", + blocking: false, + }); + }; - const customizeToolbar = (toolbar: Flexmonster.Toolbar) => { - let tabs = toolbar.getTabs(); - toolbar.getTabs = () => { - tabs = []; - // add new tab - tabs.push({ - id: "fm-tab-newtab", - title: "New Tab", - handler: () => showInfo(), - icon: toolbar.icons.open, - }); - return tabs; - }; - } + return ( + <> +

    Customizing the Toolbar

    - return ( - <> -

    Customizing the Toolbar

    +
    +

    You can add, remove, and update the Toolbar tabs.

    +

    + In this demo, we've removed all the tabs and added a custom New Tab. See our docs to learn more about the Toolbar and its + customization:{" "} + Customizing the Toolbar. +

    +
    -
    -

    You can add, remove, and update the Toolbar tabs.

    -

    In this demo, we’ve removed all the tabs and added a custom New Tab. - See our docs to learn more about the Toolbar and its - customization: Customizing the Toolbar. -

    -
    - - - - ); - -} \ No newline at end of file + + + ); +} diff --git a/nextjs-ts/src/app/globals.css b/nextjs-ts/src/app/globals.css index 2ad6b9f..cd30ac7 100644 --- a/nextjs-ts/src/app/globals.css +++ b/nextjs-ts/src/app/globals.css @@ -33,7 +33,7 @@ body { } .chart-container { - margin-top: 70px; + margin-top: 50px; } .first-description-block { @@ -80,6 +80,7 @@ body { margin: 5px 5px 5px 0; position: relative; width: auto; + appearance: none; -webkit-appearance: none; -moz-appearance: none; -webkit-box-sizing: border-box; diff --git a/nextjs-ts/src/app/handling-events/page.tsx b/nextjs-ts/src/app/handling-events/page.tsx index 66bfd14..2b7dff7 100644 --- a/nextjs-ts/src/app/handling-events/page.tsx +++ b/nextjs-ts/src/app/handling-events/page.tsx @@ -1,156 +1,158 @@ -// Must be a client component because we pass function in the beforetoolbarcreated param -"use client" -import * as React from "react"; +// Must be a client component because we pass a function in the beforetoolbarcreated param +"use client"; +import { useRef, useState } from "react"; import LogsList from "@/UIElements/LogsList"; import ToggleButton from "@/UIElements/ToggleButton"; -// Types are static, so we can safely import it for use in references -import type {Pivot} from "react-flexmonster"; +// Types are static, so we can safely import them to use in refs +import type { Pivot } from "react-flexmonster"; import dynamic from "next/dynamic"; -// Wrapper must be imported dynamically, since it contains Flexmonster pivot -const FlexmonsterPivot = dynamic(() => import('@/UIElements/PivotWrapper'), { - ssr: false, - loading: () =>

    Loading Flexmonster...

    +// Wrapper must be imported dynamically, since it contains Flexmonster Pivot +const FlexmonsterPivot = dynamic(() => import("@/UIElements/PivotWrapper"), { + ssr: false, + loading: () =>

    Loading Flexmonster...

    , }); -export default function HandlingEvents() { - // Managing state for functional components - const [logs, setLogs] = React.useState<{ - date: Date, - event: string - }[]>([]); - - const pivotRef: React.RefObject = React.useRef(null); - - // Hook that fires every re-render on the client - React.useEffect(() => { - const logsContainer = document.querySelector(".event-logs-wrapper .content"); - if (logsContainer) { - logsContainer.scrollTop = logsContainer.scrollHeight; - } - // logs is passed here so we can subscribe to its changes - }, [logs]) - - //the list of all supported events - const eventList = [ - "afterchartdraw", - "aftergriddraw", - "beforegriddraw", - "beforetoolbarcreated", - "cellclick", - "celldoubleclick", - "chartclick", - "datachanged", - "dataerror", - "datafilecancelled", - "dataloaded", - "drillthroughclose", - "drillthroughopen", - "exportcomplete", - "exportstart", - "fieldslistclose", - "fieldslistopen", - "filterclose", - "filteropen", - "loadingdata", - "loadinglocalization", - "loadingolapstructure", - "loadingreportfile", - "localizationerror", - "localizationloaded", - "olapstructureerror", - "olapstructureloaded", - "openingreportfile", - "printcomplete", - "printstart", - "querycomplete", - "queryerror", - "ready", - "reportchange", - "reportcomplete", - "reportfilecancelled", - "reportfileerror", - "runningquery", - "update", - ]; +const eventList = [ + "afterchartdraw", + "aftergriddraw", + "beforegriddraw", + "beforetoolbarcreated", + "cellclick", + "celldoubleclick", + "chartclick", + "datachanged", + "dataerror", + "datafilecancelled", + "dataloaded", + "drillthroughclose", + "drillthroughopen", + "exportcomplete", + "exportstart", + "fieldslistclose", + "fieldslistopen", + "filterclose", + "filteropen", + "loadingdata", + "loadinglocalization", + "loadingolapstructure", + "loadingreportfile", + "localizationerror", + "localizationloaded", + "olapstructureerror", + "olapstructureloaded", + "openingreportfile", + "printcomplete", + "printstart", + "querycomplete", + "queryerror", + "ready", + "reportchange", + "reportcomplete", + "reportfilecancelled", + "reportfileerror", + "runningquery", + "update", +]; - const printLog = (event: string) => { - logs.push({ - date: new Date(), - event: event - }); - // This will fire a state change - setLogs([...logs]); - } +export default function HandlingEvents() { + const [logs, setLogs] = useState<{date: Date; event: string;}[]>([]); + const pivotRef: React.RefObject = useRef(null); - const eventsSignerController = (isSigned: boolean) => { - isSigned ? signOnAllEvents() : signOffAllEvents(); - } + const printLog = (event: string) => { + const newLog = { + date: new Date(), + event: event, + }; + setLogs((prevLogs) => [...prevLogs, newLog]); + requestAnimationFrame(() => { + const logsContainer = document.getElementById("logsContainer"); + if (logsContainer) { + logsContainer.scrollTop = logsContainer.scrollHeight; + } + }); + }; - const signOffAllEvents = () => { - for (const eventName of eventList) { - // remove all handlers for specified event - pivotRef.current?.flexmonster.off(eventName); - } - } + const eventsSignerController = (isSigned: boolean) => { + isSigned ? signOnAllEvents() : signOffAllEvents(); + }; - const signOnAllEvents = () => { - for (const eventName of eventList) { - // add handler for specified event - pivotRef.current?.flexmonster.on(eventName, () => { - printLog(eventName); - }); - } + const signOffAllEvents = () => { + for (const eventName of eventList) { + // Remove all handlers for the specified event + pivotRef.current?.flexmonster.off(eventName); } + }; - const clearLogs = () => { - // This will fire a state change - setLogs((_) => []) + const signOnAllEvents = () => { + for (const eventName of eventList) { + // Add handler for the specified event + pivotRef.current?.flexmonster.on(eventName, () => { + printLog(eventName); + }); } + }; - return ( - <> -

    Handling Flexmonster events

    + const clearLogs = () => { + setLogs([]); + }; -
    -

    - Perform an action (for example, click on a grid cell) to trigger a Flexmonster event - . Scroll down to the log output to see which events get triggered. -

    -
    + return ( + <> +

    Handling Flexmonster events

    -
    - -
    +
    +

    + Perform an action (for example, click on a grid cell) to trigger a{" "} + Flexmonster event. Scroll down to the log output to see which events get triggered. +

    +
    -
    - { - toolbar.showShareReportTab = true; - }} - shareReportConnection={{ - url: "https://olap.flexmonster.com:9500" - }} - width="100%" - height={600} - ready={signOnAllEvents} - report="https://cdn.flexmonster.com/github/demo-report.json" - //licenseKey="XXXX-XXXX-XXXX-XXXX-XXXX" - /> -
    -
    - -
    - -
    -
    - - ); +
    + +
    -} \ No newline at end of file +
    + { + toolbar.showShareReportTab = true; + }} + shareReportConnection={{ + url: "https://olap.flexmonster.com:9500", + }} + //licenseKey="XXXX-XXXX-XXXX-XXXX-XXXX" + /> +
    +
    + +
    + +
    +
    + + ); +} diff --git a/nextjs-ts/src/app/pivot-table-demo/page.tsx b/nextjs-ts/src/app/pivot-table-demo/page.tsx index 6badced..74f71e6 100644 --- a/nextjs-ts/src/app/pivot-table-demo/page.tsx +++ b/nextjs-ts/src/app/pivot-table-demo/page.tsx @@ -1,46 +1,49 @@ -// Must be a client component because we pass function in the beforetoolbarcreated param -"use client" -import * as React from "react"; -// Types are static, so we can safely import it for use in references -import type { Pivot } from "react-flexmonster"; +// Must be a client component because we pass a function in the beforetoolbarcreated param +"use client"; import dynamic from "next/dynamic"; -// Wrapper must be imported dynamically, since it contains Flexmonster pivot -const FlexmonsterPivot = dynamic(() => import('@/UIElements/PivotWrapper'), { - ssr: false, - loading: () =>

    Loading Flexmonster...

    +// Wrapper must be imported dynamically, since it contains Flexmonster Pivot +const FlexmonsterPivot = dynamic(() => import("@/UIElements/PivotWrapper"), { + ssr: false, + loading: () =>

    Loading Flexmonster...

    , }); export default function PivotTableDemo() { - return ( - <> -

    Pivot Table Demo

    + return ( + <> +

    Pivot Table Demo

    -
    -

    Flexmonster is a fast and powerful JavaScript pivot grid for data visualization and reporting.

    -

    With Flexmonster, you can create reports based on many data sources, including JSON, CSV, MongoDB, and SQL - databases. - Our component is easy to customize and configure, so it can be seamlessly integrated into any project. -

    -

    Visit our documentation for step-by-step guidance on - Flexmonster.

    -
    +
    +

    Flexmonster is a fast and powerful JavaScript pivot grid for data visualization and reporting.

    +

    + With Flexmonster, you can create reports based on many data sources, including JSON, CSV, MongoDB, and SQL databases. Our component is easy + to customize and configure, so it can be seamlessly integrated into any project. +

    +

    + Visit{" "} + our documentation for step-by-step guidance on Flexmonster. +

    +
    -
    - { - toolbar.showShareReportTab = true; - }} - shareReportConnection={{ - url: "https://olap.flexmonster.com:9500" - }} - width="100%" - height={600} - report="https://cdn.flexmonster.com/github/demo-report.json" - //licenseKey="XXXX-XXXX-XXXX-XXXX-XXXX" - /> -
    - - ); +
    + { + toolbar.showShareReportTab = true; + }} + shareReportConnection={{ + url: "https://olap.flexmonster.com:9500", + }} + //licenseKey="XXXX-XXXX-XXXX-XXXX-XXXX" + /> +
    + + ); } diff --git a/nextjs-ts/src/app/updating-data/page.tsx b/nextjs-ts/src/app/updating-data/page.tsx index ab9aac0..7ff5991 100644 --- a/nextjs-ts/src/app/updating-data/page.tsx +++ b/nextjs-ts/src/app/updating-data/page.tsx @@ -1,112 +1,131 @@ -// Must be a client component because we pass function in the beforetoolbarcreated param -"use client" -import * as React from "react"; -// Types are static, so we can safely import it for use in references +// Must be a client component because we pass a function in the beforetoolbarcreated param +"use client"; +import { useRef } from "react"; +// Types are static, so we can safely import them to use in refs import type { Pivot } from "react-flexmonster"; import dynamic from "next/dynamic"; -// Wrapper must be imported dynamically, since it contains Flexmonster pivot -const FlexmonsterPivot = dynamic(() => import('@/UIElements/PivotWrapper'), { - ssr: false, - loading: () =>

    Loading Flexmonster...

    +// Wrapper must be imported dynamically, since it contains Flexmonster Pivot +const FlexmonsterPivot = dynamic(() => import("@/UIElements/PivotWrapper"), { + ssr: false, + loading: () =>

    Loading Flexmonster...

    , }); export default function UpdatingData() { + const pivotRef: React.RefObject = useRef(null); - const pivotRef: React.RefObject = React.useRef(null); + let data = [ + { + "Category": "Accessories", + "Size": "262 oz", + "Color": "red", + "Destination": "Australia", + "Business Type": "Specialty Bike Shop", + "Country": "Australia", + "Price": 100, + "Quantity": 225, + "Discount": 23, + }, + { + "Category": "Components", + "Size": "235 oz", + "Color": "green", + "Destination": "Australia", + "Business Type": "Warehouse", + "Country": "Australia", + "Price": 200, + "Quantity": 1950, + "Discount": 51, + }, + ]; - let data = [ - { - Category: "Accessories", - Size: "262 oz", - Color: "red", - Destination: "Australia", - "Business Type": "Specialty Bike Shop", - Country: "Australia", - Price: 100, - Quantity: 225, - Discount: 23, - }, - { - Category: "Components", - Size: "235 oz", - Color: "green", - Destination: "Australia", - "Business Type": "Warehouse", - Country: "Australia", - Price: 200, - Quantity: 1950, - Discount: 51, - }, - ]; - - const onReady = () => { - // Connect Flexmonster to the data - pivotRef.current?.flexmonster.connectTo({ data: data }); - } + const onReady = () => { + // Connect Flexmonster to the data + pivotRef.current?.flexmonster.connectTo({ data: data }); + }; - const updateTheData = () => { - // If the data in React got updated, for example: - data = [ - { - Category: "Accessories", - Size: "262 oz", - Color: "red", - Destination: "Australia", - "Business Type": "Specialty Bike Shop", - Country: "Australia", - Price: Math.floor(Math.random() * Math.floor(1000)), - Quantity: 225, - Discount: 23, - }, - { - Category: "Components", - Size: "307 oz", - Color: "white", - Destination: "United Kingdom", - "Business Type": "Warehouse", - Country: "Canada", - Price: Math.floor(Math.random() * Math.floor(1000)), - Quantity: 8212, - Discount: 55, - }, - ]; - // then the data needs to be updated in Flexmonster as well - // this can be done via Flexmonster's updateData() API call: - pivotRef.current?.flexmonster.updateData({ data: data }); - } - - return ( - <> -

    Updating the data in Flexmonster

    + const updateTheData = () => { + // If the data in React got updated, for example: + data = [ + { + "Category": "Accessories", + "Size": "262 oz", + "Color": "red", + "Destination": "Australia", + "Business Type": "Specialty Bike Shop", + "Country": "Australia", + "Price": Math.floor(Math.random() * Math.floor(1000)), + "Quantity": 225, + "Discount": 23, + }, + { + "Category": "Components", + "Size": "307 oz", + "Color": "white", + "Destination": "United Kingdom", + "Business Type": "Warehouse", + "Country": "Canada", + "Price": Math.floor(Math.random() * Math.floor(1000)), + "Quantity": 8212, + "Discount": 55, + }, + { + "Category": "Clothes", + "Size": "400 oz", + "Color": "blue", + "Destination": "Belgium", + "Business Type": "Warehouse", + "Country": "France", + "Price": Math.floor(Math.random() * Math.floor(1000)), + "Quantity": 7978, + "Discount": 30, + }, + ]; + // Then the data needs to be updated in Flexmonster as well + // This can be done via Flexmonster's updateData() API call + pivotRef.current?.flexmonster.updateData({ data: data }); + }; -
    -

    - This demo shows how to refresh the data at runtime and keep the slice, options, and formatting the same. -

    -

    Try it yourself: configure the component as you wish and click the UPDATE DATA button.

    -

    Learn more about updating the data - in our documentation. -

    -
    + return ( + <> +

    Updating the data in Flexmonster

    - +
    +

    This demo shows how to refresh the data at runtime and keep the slice, options, and formatting the same.

    +

    + Try it yourself: configure the component as you wish and click the UPDATE DATA button. +

    +

    + Learn more about updating the data in{" "} + our documentation. +

    +
    - { - toolbar.showShareReportTab = true; - }} - shareReportConnection={{ - url: "https://olap.flexmonster.com:9500" - }} - width="100%" - height={400} - ready={onReady} - //licenseKey="XXXX-XXXX-XXXX-XXXX-XXXX" - /> - - ); + -} \ No newline at end of file + { + toolbar.showShareReportTab = true; + }} + shareReportConnection={{ + url: "https://olap.flexmonster.com:9500", + }} + ready={onReady} + //licenseKey="XXXX-XXXX-XXXX-XXXX-XXXX" + /> + + ); +} diff --git a/nextjs-ts/src/app/using-api-calls/page.tsx b/nextjs-ts/src/app/using-api-calls/page.tsx index 2f1a15c..8030587 100644 --- a/nextjs-ts/src/app/using-api-calls/page.tsx +++ b/nextjs-ts/src/app/using-api-calls/page.tsx @@ -1,95 +1,95 @@ -// Must be a client component because we pass function in the beforetoolbarcreated param -"use client" -import * as React from "react"; -import ToggleSwitch from '@/UIElements/ToggleSwitch'; -// Types are static, so we can safely import it for use in references +// Must be a client component because we pass a function in the beforetoolbarcreated param +"use client"; +import { useRef } from "react"; +import ToggleSwitch from "@/UIElements/ToggleSwitch"; +// Types are static, so we can safely import them to use in refs import type { Pivot } from "react-flexmonster"; import dynamic from "next/dynamic"; -// Wrapper must be imported dynamically, since it contains Flexmonster pivot -const FlexmonsterPivot = dynamic(() => import('@/UIElements/PivotWrapper'), { - ssr: false, - loading: () =>

    Loading Flexmonster...

    +// Wrapper must be imported dynamically, since it contains Flexmonster Pivot +const FlexmonsterPivot = dynamic(() => import("@/UIElements/PivotWrapper"), { + ssr: false, + loading: () =>

    Loading Flexmonster...

    , }); export default function UsingAPICalls() { - - const pivotRef: React.RefObject = React.useRef(null); - - const controllGridCharts = (isGrid: boolean) => { - isGrid ? showGrid() : showChart(); - } - - const controllInteractiveness = (isInteractive: boolean) => { - isInteractive ? interactive() : readOnly() - } - - const showChart = () => { - pivotRef.current?.flexmonster.showCharts("column"); - } - - const showGrid = () => { - pivotRef.current?.flexmonster.showGrid(); - } - - const readOnly = () => { - pivotRef.current?.flexmonster.setOptions({ - readOnly: true - }); - pivotRef.current?.flexmonster.refresh(); - } - - const interactive = () => { - pivotRef.current?.flexmonster.setOptions({ - readOnly: false - }); - pivotRef.current?.flexmonster.refresh(); - } - - const hideContextMenu = () => { - pivotRef.current?.flexmonster.customizeContextMenu(() => { - return []; - }); - } - - const showContextMenu = () => { - pivotRef.current?.flexmonster.customizeContextMenu(null as any); - } - - return ( - <> -

    Using Flexmonster API calls

    - -
    -

    - Flexmonster provides API calls for - interacting with the component. - As an example, we've added the toggle buttons below. Use them to switch between the views or make Flexmonster read-only. -

    -
    - -
    - - -
    - - { - toolbar.showShareReportTab = true; - }} - shareReportConnection={{ - url: "https://olap.flexmonster.com:9500" - }} - width="100%" - height={600} - componentFolder="https://cdn.flexmonster.com/" - report="https://cdn.flexmonster.com/github/demo-report.json" - //licenseKey="XXXX-XXXX-XXXX-XXXX-XXXX" - /> - - ); - - -} \ No newline at end of file + const pivotRef: React.RefObject = useRef(null); + + const switchGridCharts = (isGrid: boolean) => { + isGrid ? showGrid() : showChart(); + }; + + const toggleInteractiveness = (isInteractive: boolean) => { + isInteractive ? interactive() : readOnly(); + }; + + const showChart = () => { + pivotRef.current?.flexmonster.showCharts("column"); + }; + + const showGrid = () => { + pivotRef.current?.flexmonster.showGrid(); + }; + + const readOnly = () => { + pivotRef.current?.flexmonster.setOptions({ + readOnly: true, + }); + pivotRef.current?.flexmonster.refresh(); + }; + + const interactive = () => { + pivotRef.current?.flexmonster.setOptions({ + readOnly: false, + }); + pivotRef.current?.flexmonster.refresh(); + }; + + return ( + <> +

    Using Flexmonster API calls

    + +
    +

    + Flexmonster provides{" "} + API calls for interacting with the component. As an example, we've added the toggle buttons below. Use them to switch between the views or make + Flexmonster read-only. +

    +
    + +
    + + +
    + + { + toolbar.showShareReportTab = true; + }} + shareReportConnection={{ + url: "https://olap.flexmonster.com:9500", + }} + //licenseKey="XXXX-XXXX-XXXX-XXXX-XXXX" + /> + + ); +} diff --git a/nextjs-ts/src/app/with-amcharts/page.tsx b/nextjs-ts/src/app/with-amcharts/page.tsx index 5aebc4e..8e8755b 100644 --- a/nextjs-ts/src/app/with-amcharts/page.tsx +++ b/nextjs-ts/src/app/with-amcharts/page.tsx @@ -1,150 +1,148 @@ -// Must be a client component because we pass function in the beforetoolbarcreated param -"use client" -import * as React from "react"; -// Types are static, so we can safely import it for use in references +// Must be a client component because we pass a function in the beforetoolbarcreated param +"use client"; +import { useEffect, useRef } from "react"; +// Types are static, so we can safely import them to use in refs import type { Pivot } from "react-flexmonster"; import dynamic from "next/dynamic"; -// Wrapper must be imported dynamically, since it contains Flexmonster pivot -const FlexmonsterPivot = dynamic(() => import('@/UIElements/PivotWrapper'), { - ssr: false, - loading: () =>

    Loading Flexmonster...

    +// Wrapper must be imported dynamically, since it contains Flexmonster Pivot +const FlexmonsterPivot = dynamic(() => import("@/UIElements/PivotWrapper"), { + ssr: false, + loading: () =>

    Loading Flexmonster...

    , }); -// amCharts imports +// Importing amCharts import * as am5 from "@amcharts/amcharts5"; -import * as am5xy from "@amcharts/amcharts5/xy"; +import * as am5percent from "@amcharts/amcharts5/percent"; import am5themes_Animated from "@amcharts/amcharts5/themes/Animated"; export default function WithAmcharts() { + const pivotRef: React.RefObject = useRef(null); + let root!: am5.Root; + + const reportComplete = () => { + pivotRef.current!.flexmonster.off("reportcomplete"); + drawChart(); + }; + + const drawChart = () => { + // Running Flexmonster's getData() method for amCharts + pivotRef.current!.flexmonster.amcharts?.getData({}, createChart, updateChart); + }; + + const createChart = (chartData: Flexmonster.GetDataValueObject, rawData: Flexmonster.GetDataValueObject) => { + // Initializing the root element + root = am5.Root.new("amcharts-container"); + // Applying the amCharts theme + root.setThemes([am5themes_Animated.new(root)]); + // Applying number format from Flexmonster + root.numberFormatter.set("numberFormat", pivotRef.current?.flexmonster.amcharts?.getNumberFormatPattern((rawData.meta as any).formats[0])); + + // Creating a chart instance + const chart = root.container.children.push( + am5percent.PieChart.new(root, { + layout: root.verticalLayout, + innerRadius: 100, + }) + ); - const pivotRef: React.RefObject = React.useRef(null); - let root!: am5.Root; - - const reportComplete = () => { - pivotRef.current!.flexmonster.off("reportComplete", reportComplete); - //creating charts after Flexmonster instance is launched - drawChart(); - } - - const drawChart = () => { - //Running Flexmonster's getData method for amCharts - pivotRef.current!.flexmonster.amcharts?.getData( - {}, - createChart, - updateChart - ); - } - - const createChart = (chartData: Flexmonster.GetDataValueObject, rawData: Flexmonster.GetDataValueObject) => { - - /* Create root element and chart instance */ - root = am5.Root.new("amcharts-container"); - let chart = root.container.children.push(am5xy.XYChart.new(root, { - })); - - /* Apply amCharts theme */ - root.setThemes([ - am5themes_Animated.new(root), - ]); - - /* Apply number format from Flexmonster */ - root.numberFormatter.set("numberFormat", pivotRef.current!.flexmonster.amcharts?.getNumberFormatPattern((rawData.meta as any).formats[0])); - - /* Create and configure Y axis */ - let yAxis = chart.yAxes.push(am5xy.CategoryAxis.new(root, { - categoryField: pivotRef.current!.flexmonster.amcharts?.getCategoryName(rawData)!, - renderer: am5xy.AxisRendererY.new(root, { - cellStartLocation: 0.1, - cellEndLocation: 0.9 - }) - })); - - /* Create and configure X axis */ - let xAxis = chart.xAxes.push(am5xy.ValueAxis.new(root, { - renderer: am5xy.AxisRendererX.new(root, {}), - })); - - xAxis.set("numberFormatter", am5.NumberFormatter.new(root, { - "numberFormat": "#a" - })); - - /* Create and configure series for a bar chart */ - let series = chart.series.push(am5xy.ColumnSeries.new(root, { - name: pivotRef.current!.flexmonster.amcharts?.getMeasureNameByIndex(rawData, 0), - xAxis: xAxis, - yAxis: yAxis as any, - sequencedInterpolation: true, - valueXField: pivotRef.current!.flexmonster.amcharts?.getMeasureNameByIndex(rawData, 0), - categoryYField: pivotRef.current!.flexmonster.amcharts?.getCategoryName(rawData), - tooltip: am5.Tooltip.new(root, { - labelText: '{name}: [bold]{valueX}[/]' - }) - })); - - chart.set("cursor", am5xy.XYCursor.new(root, { - behavior: "none", - xAxis: xAxis, - yAxis: yAxis - })); - - /* Add data processed by Flexmonster to the chart */ - yAxis.data.setAll(chartData.data); - series.data.setAll(chartData.data); - - /* Create initial animation */ - series.appear(1000); - chart.appear(1000, 100); - } - - const updateChart = (chartData: Flexmonster.GetDataValueObject, rawData: Flexmonster.GetDataValueObject) => { - root.dispose(); - createChart(chartData, rawData) - } - - return ( -
    -

    Integrating with amCharts

    - -
    -

    - Extend Flexmonster’s visualization functionality by integrating - with the amCharts library:{' '} - - Integration with amCharts - - . -

    -
    - - { - toolbar.showShareReportTab = true; - }} - shareReportConnection={{ - url: "https://olap.flexmonster.com:9500" - }} - width="100%" - height={600} - report="https://cdn.flexmonster.com/github/demo-report.json" - licenseFilePath="https://cdn.flexmonster.com/jsfiddle.charts.key" - reportcomplete={reportComplete} - //licenseKey="XXXX-XXXX-XXXX-XXXX-XXXX" - /> -
    -
    -
    -
    + const series = chart.series.push( + am5percent.PieSeries.new(root, { + valueField: pivotRef.current?.flexmonster.amcharts?.getMeasureNameByIndex(rawData, 0), + categoryField: pivotRef.current?.flexmonster.amcharts?.getCategoryName(rawData), + }) + ); + + series.children.push( + am5.Label.new(root, { + text: "[#999]TOTAL:[/]\n{valueSum.formatNumber()}", + populateText: true, + textAlign: "center", + centerX: am5.p50, + centerY: am5.p50, + fontSize: 24, + fontWeight: "500", + fill: am5.color(0x555555), + oversizedBehavior: "fit", + }) ); -} \ No newline at end of file + series.slices.template.set("tooltipText", "{category}: {value} ({valuePercentTotal.formatNumber('0.00')}%)"); + series.labels.template.set("visible", false); + series.ticks.template.set("visible", false); + + series.data.setAll(chartData.data); + + const legend = chart.children.push( + am5.Legend.new(root, { + centerX: am5.percent(50), + x: am5.percent(50), + layout: am5.GridLayout.new(root, { + maxColumns: 3, + fixedWidthGrid: true, + }), + height: am5.percent(20), + verticalScrollbar: am5.Scrollbar.new(root, { + orientation: "vertical", + }), + }) + ); + legend.data.setAll(series.dataItems); + legend.valueLabels.template.set("forceHidden", true); + + series.appear(1000); + chart.appear(1000, 100); + }; + + const updateChart = (chartData: Flexmonster.GetDataValueObject, rawData: Flexmonster.GetDataValueObject) => { + root?.dispose(); + createChart(chartData, rawData); + }; + + useEffect(() => { + return () => { + // Disposing of the chart instance when the component is unmounted + root?.dispose(); + }; + }); + + return ( + <> +

    Integrating with amCharts

    + +
    +

    + Extend Flexmonster's visualization functionality by integrating with the amCharts library:{" "} + Integration with amCharts. +

    +
    + + { + toolbar.showShareReportTab = true; + }} + shareReportConnection={{ + url: "https://olap.flexmonster.com:9500", + }} + licenseFilePath="https://cdn.flexmonster.com/jsfiddle.charts.key" + reportcomplete={reportComplete} + //licenseKey="XXXX-XXXX-XXXX-XXXX-XXXX" + /> +
    +
    +
    + + ); +} diff --git a/nextjs-ts/src/app/with-amcharts4/page.tsx b/nextjs-ts/src/app/with-amcharts4/page.tsx index 1fcf4ba..9f55e8e 100644 --- a/nextjs-ts/src/app/with-amcharts4/page.tsx +++ b/nextjs-ts/src/app/with-amcharts4/page.tsx @@ -1,109 +1,108 @@ -// Must be a client component because we pass function in the beforetoolbarcreated param -"use client" -import * as React from "react"; -// Types are static, so we can safely import it for use in references +// Must be a client component because we pass a function in the beforetoolbarcreated param +"use client"; +import { useRef, useEffect } from "react"; +// Types are static, so we can safely import them to use in refs import type { Pivot } from "react-flexmonster"; import dynamic from "next/dynamic"; -// Wrapper must be imported dynamically, since it contains Flexmonster pivot -const FlexmonsterPivot = dynamic(() => import('@/UIElements/PivotWrapper'), { - ssr: false, - loading: () =>

    Loading Flexmonster...

    +// Wrapper must be imported dynamically, since it contains Flexmonster Pivot +const FlexmonsterPivot = dynamic(() => import("@/UIElements/PivotWrapper"), { + ssr: false, + loading: () =>

    Loading Flexmonster...

    , }); -// amCharts imports -import * as am4core from '@amcharts/amcharts4/core'; -import * as am4charts from '@amcharts/amcharts4/charts'; -import am4themes_animated from '@amcharts/amcharts4/themes/animated'; +// Importing amCharts +import * as am4core from "@amcharts/amcharts4/core"; +import * as am4charts from "@amcharts/amcharts4/charts"; +import am4themes_animated from "@amcharts/amcharts4/themes/animated"; -export default function WithAmcharts4() { - - const pivotRef: React.RefObject = React.useRef(null); - let chart!: am4charts.PieChart; - - - const reportComplete = () => { - pivotRef.current!.flexmonster.off("reportComplete", reportComplete); - //creating charts after Flexmonster instance is launched - drawChart(); - } - - const drawChart = () => { - //Running Flexmonster's getData method for amCharts - pivotRef.current!.flexmonster.amcharts?.getData( - {}, - createChart, - updateChart - ); - } - - const createChart = (chartData: Flexmonster.GetDataValueObject, rawData: Flexmonster.GetDataValueObject) => { - - if (pivotRef.current!.flexmonster && pivotRef.current!.flexmonster.amcharts) { - /* Apply amCharts theme */ - am4core.useTheme(am4themes_animated); - - /* Create chart instance */ - let chart = am4core.create("chartContainer", am4charts.PieChart); - - /* Add data processed by Flexmonster to the chart */ - chart.data = chartData.data; +// Applying the amCharts theme +am4core.useTheme(am4themes_animated); - /* Set an inner radius to transform a pie chart into a donut chart */ - chart.innerRadius = am4core.percent(50); - - /* Create and configure series for a pie chart */ - var pieSeries = chart.series.push(new am4charts.PieSeries()); - pieSeries.dataFields.category = pivotRef.current!.flexmonster.amcharts.getCategoryName(rawData); - pieSeries.dataFields.value = pivotRef.current!.flexmonster.amcharts.getMeasureNameByIndex(rawData, 0); - pieSeries.slices.template.stroke = am4core.color("#fff"); - pieSeries.slices.template.strokeWidth = 2; - pieSeries.slices.template.strokeOpacity = 1; - - /* Create initial animation */ - pieSeries.hiddenState.properties.opacity = 1; - pieSeries.hiddenState.properties.endAngle = -90; - pieSeries.hiddenState.properties.startAngle = -90; - - chart = chart; - } - - } - - const updateChart = (chartData: Flexmonster.GetDataValueObject, rawData: Flexmonster.GetDataValueObject) => { - chart.dispose(); - createChart(chartData, rawData) - } - - return ( -
    -

    Integrating with amCharts

    - -
    -

    Extend Flexmonster’s visualization functionality by integrating with the amCharts - library: Integration with amCharts. -

    -
    - - { - toolbar.showShareReportTab = true; - }} - shareReportConnection={{ - url: "https://olap.flexmonster.com:9500" - }} - width="100%" - height={600} - report="https://cdn.flexmonster.com/github/demo-report.json" - licenseFilePath="https://cdn.flexmonster.com/jsfiddle.charts.key" - reportcomplete={reportComplete} - //licenseKey="XXXX-XXXX-XXXX-XXXX-XXXX" - /> -
    -
    -
    -
    - ); -} \ No newline at end of file +export default function WithAmcharts4() { + const pivotRef: React.RefObject = useRef(null); + const chartRef: React.RefObject = useRef(null); + + const reportComplete = () => { + pivotRef.current!.flexmonster.off("reportcomplete"); + drawChart(); + }; + + const drawChart = () => { + // Running Flexmonster's getData() method for amCharts + pivotRef.current!.flexmonster.amcharts?.getData({}, createChart, updateChart); + }; + + const createChart = (chartData: Flexmonster.GetDataValueObject, rawData: Flexmonster.GetDataValueObject) => { + // Creating a chart instance + const chart = am4core.create("chartContainer", am4charts.PieChart); + + // Adding data processed by Flexmonster to the chart + chart.data = chartData.data; + + // Creating and configuring series for a pie chart + const pieSeries = chart.series.push(new am4charts.PieSeries()); + pieSeries.dataFields.category = pivotRef.current?.flexmonster.amcharts?.getCategoryName(rawData); + pieSeries.dataFields.value = pivotRef.current?.flexmonster.amcharts?.getMeasureNameByIndex(rawData, 0); + pieSeries.slices.template.stroke = am4core.color("#fff"); + pieSeries.slices.template.strokeWidth = 3; + pieSeries.slices.template.strokeOpacity = 1; + + // Creating initial animation + pieSeries.hiddenState.properties.opacity = 1; + pieSeries.hiddenState.properties.endAngle = -90; + pieSeries.hiddenState.properties.startAngle = -90; + chartRef.current = chart; + }; + + const updateChart = (chartData: Flexmonster.GetDataValueObject, rawData: Flexmonster.GetDataValueObject) => { + chartRef.current?.dispose(); + createChart(chartData, rawData); + }; + + useEffect(() => { + return () => { + chartRef.current?.dispose(); + }; + }); + + return ( + <> +

    Integrating with amCharts 4

    + +
    +

    + Extend Flexmonster's visualization functionality by integrating with the amCharts library:{" "} + Integration with amCharts. +

    +
    + + { + toolbar.showShareReportTab = true; + }} + shareReportConnection={{ + url: "https://olap.flexmonster.com:9500", + }} + licenseFilePath="https://cdn.flexmonster.com/jsfiddle.charts.key" + reportcomplete={reportComplete} + //licenseKey="XXXX-XXXX-XXXX-XXXX-XXXX" + /> +
    +
    +
    + + ); +} diff --git a/nextjs-ts/src/app/with-highcharts/page.tsx b/nextjs-ts/src/app/with-highcharts/page.tsx index 8fd1945..1abe9c5 100644 --- a/nextjs-ts/src/app/with-highcharts/page.tsx +++ b/nextjs-ts/src/app/with-highcharts/page.tsx @@ -1,72 +1,80 @@ -// Must be a client component because we pass function in the beforetoolbarcreated param -"use client" -import * as React from "react"; -// Types are static, so we can safely import it for use in references +// Must be a client component because we pass a function in the beforetoolbarcreated param +"use client"; +import { useRef, useState } from "react"; +// Types are static, so we can safely import them to use in refs import type { Pivot } from "react-flexmonster"; import dynamic from "next/dynamic"; // Wrapper must be imported dynamically, since it contains Flexmonster pivot -const FlexmonsterPivot = dynamic(() => import('@/UIElements/PivotWrapper'), { - ssr: false, - loading: () =>

    Loading Flexmonster...

    +const FlexmonsterPivot = dynamic(() => import("@/UIElements/PivotWrapper"), { + ssr: false, + loading: () =>

    Loading Flexmonster...

    , }); -import * as Highcharts from 'highcharts'; +import Highcharts from "highcharts/esm/highcharts.js"; +import HighchartsReact from "highcharts-react-official"; +import "highcharts/esm/modules/accessibility.js"; export default function WithHighcharts() { + const pivotRef: React.RefObject = useRef(null); + const [chartOptions, setChartOptions] = useState({}); - const pivotRef: React.RefObject = React.useRef(null); + const reportComplete = () => { + pivotRef.current!.flexmonster.off("reportcomplete"); + createChart(); + }; - const reportComplete = () => { - pivotRef.current!.flexmonster.off("reportComplete", reportComplete); - //creating charts after Flexmonster instance is launched - createChart(); - } - - const createChart = () => { - //Running Flexmonster's getData method for Highcharts - pivotRef.current!.flexmonster.highcharts?.getData( - { - type: "spline" - }, - (data: any) => { - Highcharts.chart('highcharts-container', data); - }, - (data: any) => { - Highcharts.chart('highcharts-container', data); - } - ); - } + const createChart = () => { + pivotRef.current!.flexmonster.highcharts?.getData( + { + type: "spline", + }, + (data: Flexmonster.GetDataValueObject) => { + setChartOptions(data as Highcharts.Options); + }, + (data: Flexmonster.GetDataValueObject) => { + setChartOptions(data as Highcharts.Options); + } + ); + }; - return ( -
    -

    Integrating with Highcharts

    + return ( + <> +

    Integrating with Highcharts

    -
    -

    Integrate Flexmonster with Highcharts and see your data from a new - perspective: Integration with Highcharts. -

    -
    +
    +

    + Integrate Flexmonster with Highcharts and see your data from a new perspective:{" "} + Integration with Highcharts. +

    +
    - { - toolbar.showShareReportTab = true; - }} - shareReportConnection={{ - url: "https://olap.flexmonster.com:9500" - }} - width="100%" - height={600} - report="https://cdn.flexmonster.com/github/highcharts-report.json" - licenseFilePath="https://cdn.flexmonster.com/jsfiddle.charts.key" - reportcomplete={reportComplete} - //licenseKey="XXXX-XXXX-XXXX-XXXX-XXXX" - /> -
    -
    -
    -
    - ); -} \ No newline at end of file + { + toolbar.showShareReportTab = true; + }} + shareReportConnection={{ + url: "https://olap.flexmonster.com:9500", + }} + licenseFilePath="https://cdn.flexmonster.com/jsfiddle.charts.key" + reportcomplete={reportComplete} + //licenseKey="XXXX-XXXX-XXXX-XXXX-XXXX" + /> +
    + +
    + + ); +} diff --git a/typescript/README.md b/typescript/README.md index ca6cd43..21e7f37 100644 --- a/typescript/README.md +++ b/typescript/README.md @@ -21,7 +21,7 @@ Table of contents: ## Prerequisites -- [Node.js 14 or later](https://nodejs.org/en/) +- [Node.js 20.19+ or 22.12+](https://nodejs.org/en/) ## Installation diff --git a/typescript/package.json b/typescript/package.json index 6788bbe..0827fa0 100644 --- a/typescript/package.json +++ b/typescript/package.json @@ -11,25 +11,25 @@ "preview": "vite preview" }, "dependencies": { - "@amcharts/amcharts4": "^4.10.36", - "@amcharts/amcharts5": "^5.4.1", - "highcharts": "^11.1.0", - "react": "^19.0.0", - "react-dom": "^19.0.0", + "@amcharts/amcharts4": "^4.10.40", + "@amcharts/amcharts5": "^5.13.4", + "highcharts-react-official": "^3.2.2", + "react": "^19.1.1", + "react-dom": "^19.1.1", "react-flexmonster": "latest", - "react-router-dom": "^6.14.2" + "react-router-dom": "^7.7.1" }, "devDependencies": { - "@types/react": "^19.0.0", - "@types/react-dom": "^19.0.0", - "@typescript-eslint/eslint-plugin": "^6.0.0", - "@typescript-eslint/parser": "^6.0.0", - "@vitejs/plugin-react": "^4.0.3", - "eslint": "^8.45.0", - "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-react-refresh": "^0.4.3", - "express": "^4.18.2", - "typescript": "^5.0.2", - "vite": "^4.4.5" + "@types/react": "^19.1.9", + "@types/react-dom": "^19.1.7", + "@typescript-eslint/eslint-plugin": "^8.38.0", + "@typescript-eslint/parser": "^8.38.0", + "@vitejs/plugin-react": "^4.7.0", + "eslint": "^9.32.0", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.20", + "express": "^5.1.0", + "typescript": "^5.8.3", + "vite": "^7.0.0" } } diff --git a/typescript/src/App.css b/typescript/src/App.css index a0f3dc6..c58cc4e 100644 --- a/typescript/src/App.css +++ b/typescript/src/App.css @@ -31,7 +31,7 @@ body { } .chart-container { - margin-top: 70px; + margin-top: 50px; } .first-description-block { @@ -78,6 +78,7 @@ body { margin: 5px 5px 5px 0; position: relative; width: auto; + appearance: none; -webkit-appearance: none; -moz-appearance: none; -webkit-box-sizing: border-box; diff --git a/typescript/src/components/ReactFlexmonsterExamples/CustomizingGrid.tsx b/typescript/src/components/ReactFlexmonsterExamples/CustomizingGrid.tsx index 33ec3eb..de4e1ed 100644 --- a/typescript/src/components/ReactFlexmonsterExamples/CustomizingGrid.tsx +++ b/typescript/src/components/ReactFlexmonsterExamples/CustomizingGrid.tsx @@ -1,94 +1,89 @@ -import { useRef, useState, useEffect } from 'react'; -import * as FlexmonsterReact from 'react-flexmonster'; -import ToggleButton from '../UIElements/ToggleButton'; -import 'flexmonster'; +import { useRef, useState, useEffect } from "react"; +import * as FlexmonsterReact from "react-flexmonster"; +import ToggleButton from "../UIElements/ToggleButton"; const CustomizingGrid: React.FC = () => { - const pivotRef: React.RefObject = useRef(null); - const [isCustomized, setIsCustomized] = useState(true); + const pivotRef: React.RefObject = useRef(null); + const [isCustomized, setIsCustomized] = useState(true); - useEffect(() => { - customizeGridCells(); - }, [isCustomized]); + useEffect(() => { + customizeGridCells(); + }, [isCustomized]); - const customizeCellFunction = (cell: Flexmonster.CellBuilder, data: Flexmonster.CellData) => { - if (data.measure && data.measure.uniqueName === "Price") { - let backgroundColor = "#00A45A"; - let textShadowColor = "#095231"; - let borderColor = "#009552"; - cell.style = { - ...cell.style, - "background-color": backgroundColor, - "color": "white", - "font-weight": "bold", - "text-shadow": `0px 2px 3px ${textShadowColor}`, - "border-bottom": `1px solid ${borderColor}`, - "border-right": `1px solid ${borderColor}`, - }; - } + const customizeCellFunction = (cell: Flexmonster.CellBuilder, data: Flexmonster.CellData) => { + if (data.measure && data.measure.uniqueName === "Price") { + let backgroundColor = "#00A45A"; + let textShadowColor = "#095231"; + let borderColor = "#009552"; + cell.style = { + ...cell.style, + "background-color": backgroundColor, + "color": "white", + "font-weight": "bold", + "text-shadow": `0px 2px 3px ${textShadowColor}`, + "border-bottom": `1px solid ${borderColor}`, + "border-right": `1px solid ${borderColor}`, + }; } + }; - const customizeGridCells = () => { - if (isCustomized) { - pivotRef.current?.flexmonster.customizeCell(customizeCellFunction); - } else { - pivotRef.current?.flexmonster.customizeCell(null as any); - } - }; + const customizeGridCells = () => { + if (isCustomized) { + pivotRef.current?.flexmonster.customizeCell(customizeCellFunction); + } else { + pivotRef.current?.flexmonster.customizeCell(null as any); + } + }; - const toggleCustomization = (isChecked: boolean) => { - setIsCustomized(isChecked); - }; + const toggleCustomization = (isChecked: boolean) => { + setIsCustomized(isChecked); + }; - return ( - <> -

    Customizing the grid

    + return ( + <> +

    Customizing the grid

    -
    -

    - Style the grid by adding links, applying custom CSS, or formatting the - cells. Check our docs for details:{" "} - - Customizing the grid - - . -

    -

    - In this demo, the Price measure is customized. -

    -
    +
    +

    + Style the grid by adding links, applying custom CSS, or formatting the + cells. Check our docs for details:{" "} + Customizing the grid cells. +

    +

    + In this demo, the Price measure is customized. +

    +
    -
    - -
    +
    + +
    - { - toolbar.showShareReportTab = true; - }} - shareReportConnection={{ - url: "https://olap.flexmonster.com:9500" - }} - width="100%" - height={600} - report="https://cdn.flexmonster.com/github/customizing-grid-report.json" - //licenseKey="XXXX-XXXX-XXXX-XXXX-XXXX" - /> - - ); + { + toolbar.showShareReportTab = true; + }} + shareReportConnection={{ + url: "https://olap.flexmonster.com:9500", + }} + //licenseKey="XXXX-XXXX-XXXX-XXXX-XXXX" + /> + + ); }; export default CustomizingGrid; diff --git a/typescript/src/components/ReactFlexmonsterExamples/CustomizingToolbar.tsx b/typescript/src/components/ReactFlexmonsterExamples/CustomizingToolbar.tsx index 02769f5..8805faa 100644 --- a/typescript/src/components/ReactFlexmonsterExamples/CustomizingToolbar.tsx +++ b/typescript/src/components/ReactFlexmonsterExamples/CustomizingToolbar.tsx @@ -1,58 +1,62 @@ -import { useRef } from 'react'; -import * as FlexmonsterReact from 'react-flexmonster'; -import 'flexmonster'; +import { useRef } from "react"; +import * as FlexmonsterReact from "react-flexmonster"; const CustomizingToolbar: React.FC = () => { - const pivotRef: React.RefObject = useRef(null); + const pivotRef: React.RefObject = useRef(null); - const showInfo = () => { - pivotRef.current?.flexmonster.alert({ - title: "Customizing Flexmonster", - message: - "How to customize the Toolbar: https://www.flexmonster.com/doc/customizing-toolbar/
    ", - type: "info", - blocking: false, - }); - }; + const showInfo = () => { + pivotRef.current?.flexmonster.alert({ + title: "Customizing Flexmonster", + message: + "How to customize the Toolbar: https://www.flexmonster.com/doc/customizing-toolbar/
    ", + type: "info", + blocking: false, + }); + }; - const customizeToolbar = (toolbar: Flexmonster.Toolbar) => { - let tabs = toolbar.getTabs(); - toolbar.getTabs = () => { - tabs = []; - // add new tab - tabs.push({ - id: "fm-tab-newtab", - title: "New Tab", - handler: showInfo, - icon: toolbar.icons.open, - }); - return tabs; - }; + const customizeToolbar = (toolbar: Flexmonster.Toolbar) => { + let tabs = toolbar.getTabs(); + toolbar.getTabs = () => { + tabs = []; + // Add a new tab + tabs.push({ + id: "fm-tab-newtab", + title: "New Tab", + handler: showInfo, + icon: toolbar.icons.open, + }); + return tabs; }; + }; - return ( - <> -

    Customizing the Toolbar

    + return ( + <> +

    Customizing the Toolbar

    -
    -

    You can add, remove, and update the Toolbar tabs.

    -

    In this demo, we’ve removed all the tabs and added a custom New Tab. - See our docs to learn more about the Toolbar and its - customization: Customizing the Toolbar. -

    -
    +
    +

    You can add, remove, and update the Toolbar tabs.

    +

    + In this demo, we've removed all the tabs and added a custom New Tab. + See our docs to learn more about the Toolbar and its customization:{" "} + Customizing the Toolbar. +

    +
    - - - ); + + + ); }; export default CustomizingToolbar; diff --git a/typescript/src/components/ReactFlexmonsterExamples/HandlingEvents.tsx b/typescript/src/components/ReactFlexmonsterExamples/HandlingEvents.tsx index de6c749..ee3e6be 100644 --- a/typescript/src/components/ReactFlexmonsterExamples/HandlingEvents.tsx +++ b/typescript/src/components/ReactFlexmonsterExamples/HandlingEvents.tsx @@ -1,162 +1,157 @@ -import React, { useState, useEffect, useRef } from 'react'; -import LogsList from '../UIElements/LogsList'; -import * as FlexmonsterReact from 'react-flexmonster'; -import ToggleButton from '../UIElements/ToggleButton'; -import 'flexmonster'; +import { useState, useRef } from "react"; +import * as FlexmonsterReact from "react-flexmonster"; +import LogsList from "../UIElements/LogsList"; +import ToggleButton from "../UIElements/ToggleButton"; -const HandlingEvents: React.FC = () => { - const [logs, setLogs] = useState<{ - date: Date; - event: string; - }[]>([]); - const pivotRef: React.RefObject = useRef(null); - - const eventList = [ - "afterchartdraw", - "aftergriddraw", - "beforegriddraw", - "beforetoolbarcreated", - "cellclick", - "celldoubleclick", - "chartclick", - "datachanged", - "dataerror", - "datafilecancelled", - "dataloaded", - "drillthroughclose", - "drillthroughopen", - "exportcomplete", - "exportstart", - "fieldslistclose", - "fieldslistopen", - "filterclose", - "filteropen", - "loadingdata", - "loadinglocalization", - "loadingolapstructure", - "loadingreportfile", - "localizationerror", - "localizationloaded", - "olapstructureerror", - "olapstructureloaded", - "openingreportfile", - "printcomplete", - "printstart", - "querycomplete", - "queryerror", - "ready", - "reportchange", - "reportcomplete", - "reportfilecancelled", - "reportfileerror", - "runningquery", - "update", - ]; +const eventList = [ + "afterchartdraw", + "aftergriddraw", + "beforegriddraw", + "beforetoolbarcreated", + "cellclick", + "celldoubleclick", + "chartclick", + "datachanged", + "dataerror", + "datafilecancelled", + "dataloaded", + "drillthroughclose", + "drillthroughopen", + "exportcomplete", + "exportstart", + "fieldslistclose", + "fieldslistopen", + "filterclose", + "filteropen", + "loadingdata", + "loadinglocalization", + "loadingolapstructure", + "loadingreportfile", + "localizationerror", + "localizationloaded", + "olapstructureerror", + "olapstructureloaded", + "openingreportfile", + "printcomplete", + "printstart", + "querycomplete", + "queryerror", + "ready", + "reportchange", + "reportcomplete", + "reportfilecancelled", + "reportfileerror", + "runningquery", + "update", +]; - useEffect(() => { - if (pivotRef.current) { - signOnAllEvents(); - } - - return () => { - signOffAllEvents(); - }; - }, []); +const HandlingEvents: React.FC = () => { + const [logs, setLogs] = useState< + { + date: Date; + event: string; + }[] + >([]); + const pivotRef: React.RefObject = useRef(null); - const printLog = (event: string) => { - const newLog = { - date: new Date(), - event: event, - }; - setLogs(prevLogs => [...prevLogs, newLog]); - requestAnimationFrame(() => { - const logsContainer = document.getElementById("logsContainer"); - if (logsContainer) { - logsContainer.scrollTop = logsContainer.scrollHeight; - } - }); + const printLog = (event: string) => { + const newLog = { + date: new Date(), + event: event, }; + setLogs((prevLogs) => [...prevLogs, newLog]); + requestAnimationFrame(() => { + const logsContainer = document.getElementById("logsContainer"); + if (logsContainer) { + logsContainer.scrollTop = logsContainer.scrollHeight; + } + }); + }; - const eventsSignerController = (isSigned: boolean) => { - if (isSigned) { - signOnAllEvents(); - } else { - signOffAllEvents(); - } - }; + const eventsSignerController = (isSigned: boolean) => { + if (isSigned) { + signOnAllEvents(); + } else { + signOffAllEvents(); + } + }; - const signOffAllEvents = () => { - for (const eventName of eventList) { - // remove all handlers for specified event - pivotRef.current?.flexmonster.off(eventName); - } - }; + const signOffAllEvents = () => { + for (const eventName of eventList) { + // Remove all handlers for the specified event + pivotRef.current?.flexmonster.off(eventName); + } + }; - const signOnAllEvents = () => { - for (const eventName of eventList) { - // add handler for specified event - pivotRef.current?.flexmonster.on(eventName, () => { - printLog(eventName); - }); - } - }; + const signOnAllEvents = () => { + for (const eventName of eventList) { + // Add a handler for the specified event + pivotRef.current?.flexmonster.on(eventName, () => { + printLog(eventName); + }); + } + }; - const clearLogs = () => { - setLogs([]); - }; + const clearLogs = () => { + setLogs([]); + }; - return ( - <> -

    Handling Flexmonster events

    + return ( + <> +

    Handling Flexmonster events

    -
    -

    - Perform an action (for example, click on a grid cell) to trigger a{" "} - - Flexmonster event - - . Scroll down to the log output to see which events get triggered. -

    -
    +
    +

    + Perform an action (for example, click on a grid cell) to trigger a{" "} + Flexmonster event. Scroll down to the log output to see which events get triggered. +

    +
    -
    - -
    -
    - { - toolbar.showShareReportTab = true; - }} - shareReportConnection={{ - url: "https://olap.flexmonster.com:9500" - }} - width="100%" - height={600} - report="https://cdn.flexmonster.com/github/demo-report.json" - /> -
    -
    - -
    - -
    -
    - - ); +
    + +
    +
    + { + toolbar.showShareReportTab = true; + }} + shareReportConnection={{ + url: "https://olap.flexmonster.com:9500", + }} + /> +
    +
    + +
    + +
    +
    + + ); }; export default HandlingEvents; diff --git a/typescript/src/components/ReactFlexmonsterExamples/PivotTableDemo.tsx b/typescript/src/components/ReactFlexmonsterExamples/PivotTableDemo.tsx index 461b1f0..e586ca0 100644 --- a/typescript/src/components/ReactFlexmonsterExamples/PivotTableDemo.tsx +++ b/typescript/src/components/ReactFlexmonsterExamples/PivotTableDemo.tsx @@ -1,38 +1,43 @@ -import * as FlexmonsterReact from 'react-flexmonster'; -import 'flexmonster'; +import * as FlexmonsterReact from "react-flexmonster"; const PivotTableDemo = () => { - return ( - <> -

    Pivot Table Demo

    + return ( + <> +

    Pivot Table Demo

    -
    -

    Flexmonster is a fast and powerful JavaScript pivot grid for data visualization and reporting.

    -

    With Flexmonster, you can create reports based on many data sources, including JSON, CSV, MongoDB, and SQL - databases. - Our component is easy to customize and configure, so it can be seamlessly integrated into any project. -

    -

    Visit our documentation for step-by-step guidance on - Flexmonster.

    -
    +
    +

    Flexmonster is a fast and powerful JavaScript pivot grid for data visualization and reporting.

    +

    + With Flexmonster, you can create reports based on many data sources, including JSON, CSV, MongoDB, and SQL databases. + Our component is easy to customize and configure, so it can be seamlessly integrated into any project. +

    +

    + Visit{" "} + our documentation for step-by-step guidance on Flexmonster. +

    +
    -
    - { - toolbar.showShareReportTab = true; - }} - shareReportConnection={{ - url: "https://olap.flexmonster.com:9500" - }} - width="100%" - height={600} - report="https://cdn.flexmonster.com/github/demo-report.json" - //licenseKey="XXXX-XXXX-XXXX-XXXX-XXXX" - /> -
    - - ); -} +
    + { + toolbar.showShareReportTab = true; + }} + shareReportConnection={{ + url: "https://olap.flexmonster.com:9500", + }} + //licenseKey="XXXX-XXXX-XXXX-XXXX-XXXX" + /> +
    + + ); +}; export default PivotTableDemo; diff --git a/typescript/src/components/ReactFlexmonsterExamples/UpdatingData.tsx b/typescript/src/components/ReactFlexmonsterExamples/UpdatingData.tsx index 23e3eec..65b2fe9 100644 --- a/typescript/src/components/ReactFlexmonsterExamples/UpdatingData.tsx +++ b/typescript/src/components/ReactFlexmonsterExamples/UpdatingData.tsx @@ -1,105 +1,123 @@ -import { useRef } from 'react'; -import * as FlexmonsterReact from 'react-flexmonster'; -import 'flexmonster'; +import { useRef } from "react"; +import * as FlexmonsterReact from "react-flexmonster"; const UpdatingData = () => { - const pivotRef: React.RefObject = useRef(null); + const pivotRef: React.RefObject = useRef(null); - let data = [ - { - Category: "Accessories", - Size: "262 oz", - Color: "red", - Destination: "Australia", - "Business Type": "Specialty Bike Shop", - Country: "Australia", - Price: 100, - Quantity: 225, - Discount: 23, - }, - { - Category: "Components", - Size: "235 oz", - Color: "green", - Destination: "Australia", - "Business Type": "Warehouse", - Country: "Australia", - Price: 200, - Quantity: 1950, - Discount: 51, - }, - ]; - - const onReady = () => { - // Connect Flexmonster to the data - pivotRef.current?.flexmonster.connectTo({ data: data }); - } + let data = [ + { + "Category": "Accessories", + "Size": "262 oz", + "Color": "red", + "Destination": "Australia", + "Business Type": "Specialty Bike Shop", + "Country": "Australia", + "Price": 100, + "Quantity": 225, + "Discount": 23, + }, + { + "Category": "Components", + "Size": "235 oz", + "Color": "green", + "Destination": "Australia", + "Business Type": "Warehouse", + "Country": "Australia", + "Price": 200, + "Quantity": 1950, + "Discount": 51, + }, + ]; - const updateTheData = () => { - // If the data in React got updated, for example: - data = [ - { - Category: "Accessories", - Size: "262 oz", - Color: "red", - Destination: "Australia", - "Business Type": "Specialty Bike Shop", - Country: "Australia", - Price: Math.floor(Math.random() * Math.floor(1000)), - Quantity: 225, - Discount: 23, - }, - { - Category: "Components", - Size: "307 oz", - Color: "white", - Destination: "United Kingdom", - "Business Type": "Warehouse", - Country: "Canada", - Price: Math.floor(Math.random() * Math.floor(1000)), - Quantity: 8212, - Discount: 55, - }, - ]; - // then the data needs to be updated in Flexmonster as well - // this can be done via Flexmonster's updateData() API call: - - pivotRef.current?.flexmonster.updateData({ data: data }); - } + const onReady = () => { + // Connect Flexmonster to the data + pivotRef.current?.flexmonster.connectTo({ data: data }); + }; + const updateTheData = () => { + // If the data in React got updated, for example: + data = [ + { + "Category": "Accessories", + "Size": "262 oz", + "Color": "red", + "Destination": "Australia", + "Business Type": "Specialty Bike Shop", + "Country": "Australia", + "Price": Math.floor(Math.random() * Math.floor(1000)), + "Quantity": 225, + "Discount": 23, + }, + { + "Category": "Components", + "Size": "307 oz", + "Color": "white", + "Destination": "United Kingdom", + "Business Type": "Warehouse", + "Country": "Canada", + "Price": Math.floor(Math.random() * Math.floor(1000)), + "Quantity": 8212, + "Discount": 55, + }, + { + "Category": "Clothes", + "Size": "400 oz", + "Color": "blue", + "Destination": "Belgium", + "Business Type": "Warehouse", + "Country": "France", + "Price": Math.floor(Math.random() * Math.floor(1000)), + "Quantity": 7978, + "Discount": 30, + }, + ]; + // Then the data needs to be updated in Flexmonster as well + // This can be done via Flexmonster's updateData() API call + pivotRef.current?.flexmonster.updateData({ data: data }); + }; - return ( - <> -

    Updating the data in Flexmonster

    + return ( + <> +

    Updating the data in Flexmonster

    -
    -

    - This demo shows how to refresh the data at runtime and keep the slice, options, and formatting the same. -

    -

    Try it yourself: configure the component as you wish and click the UPDATE DATA button.

    -

    Learn more about updating the data - in our documentation. -

    -
    +
    +

    This demo shows how to refresh the data at runtime and keep the slice, options, and formatting the same.

    +

    + Try it yourself: configure the component as you wish and click the UPDATE DATA button. +

    +

    + Learn more about updating the data in{" "} + our documentation. +

    +
    - + - { - toolbar.showShareReportTab = true; - }} - shareReportConnection={{ - url: "https://olap.flexmonster.com:9500" - }} - width="100%" - height={400} - ready={onReady} - //licenseKey="XXXX-XXXX-XXXX-XXXX-XXXX" - /> - - ); -} + { + toolbar.showShareReportTab = true; + }} + shareReportConnection={{ + url: "https://olap.flexmonster.com:9500", + }} + ready={onReady} + //licenseKey="XXXX-XXXX-XXXX-XXXX-XXXX" + /> + + ); +}; export default UpdatingData; diff --git a/typescript/src/components/ReactFlexmonsterExamples/UsingAPICalls.tsx b/typescript/src/components/ReactFlexmonsterExamples/UsingAPICalls.tsx index 24bd301..0138faf 100644 --- a/typescript/src/components/ReactFlexmonsterExamples/UsingAPICalls.tsx +++ b/typescript/src/components/ReactFlexmonsterExamples/UsingAPICalls.tsx @@ -1,21 +1,20 @@ -import { useRef } from 'react'; -import ToggleSwitch from '../UIElements/ToggleSwitch'; -import * as FlexmonsterReact from 'react-flexmonster'; -import 'flexmonster'; +import { useRef } from "react"; +import * as FlexmonsterReact from "react-flexmonster"; +import ToggleSwitch from "../UIElements/ToggleSwitch"; const UsingAPICalls = () => { const pivotRef: React.RefObject = useRef(null); - const controllGridCharts = (isGrid: boolean) => { + const switchGridCharts = (isGrid: boolean) => { isGrid ? showGrid() : showChart(); }; - const controllInteractiveness = (isInteractive: boolean) => { + const toggleInteractiveness = (isInteractive: boolean) => { isInteractive ? interactive() : readOnly(); }; const showChart = () => { - pivotRef.current?.flexmonster.showCharts('column'); + pivotRef.current?.flexmonster.showCharts("column"); }; const showGrid = () => { @@ -24,56 +23,45 @@ const UsingAPICalls = () => { const readOnly = () => { pivotRef.current?.flexmonster.setOptions({ - readOnly: true + readOnly: true, }); pivotRef.current?.flexmonster.refresh(); }; const interactive = () => { pivotRef.current?.flexmonster.setOptions({ - readOnly: false + readOnly: false, }); pivotRef.current?.flexmonster.refresh(); }; - // const hideContextMenu = () => { - // pivotRef.current?.flexmonster.customizeContextMenu?.(() => []); - // }; - - // const showContextMenu = () => { - // pivotRef.current?.flexmonster.customizeContextMenu?.((items) => { - // return items; - // }); - // }; - return ( <>

    Using Flexmonster API calls

    - Flexmonster provides - API calls - for interacting with the component. As an example, we've added the - toggle buttons below. Use them to switch between the views or make - Flexmonster read-only. + >API calls for interacting with the component. As an example, we've added the toggle buttons below. + Use them to switch between the views or make Flexmonster read-only.

    @@ -82,16 +70,14 @@ const UsingAPICalls = () => { { toolbar.showShareReportTab = true; }} shareReportConnection={{ - url: 'https://olap.flexmonster.com:9500' + url: "https://olap.flexmonster.com:9500", }} - width="100%" - height={600} - componentFolder="https://cdn.flexmonster.com/" - report="https://cdn.flexmonster.com/github/demo-report.json" //licenseKey="XXXX-XXXX-XXXX-XXXX-XXXX" /> diff --git a/typescript/src/components/ReactFlexmonsterExamples/WithAmcharts.tsx b/typescript/src/components/ReactFlexmonsterExamples/WithAmcharts.tsx index 9debc12..160a48e 100644 --- a/typescript/src/components/ReactFlexmonsterExamples/WithAmcharts.tsx +++ b/typescript/src/components/ReactFlexmonsterExamples/WithAmcharts.tsx @@ -1,129 +1,142 @@ -import React, { useRef } from 'react'; -import * as FlexmonsterReact from 'react-flexmonster'; +import { useEffect, useRef } from "react"; +import * as FlexmonsterReact from "react-flexmonster"; +import Flexmonster from "flexmonster"; +// Importing Flexmonster Connector for amCharts import "flexmonster/lib/flexmonster.amcharts.js"; + +// Importing amCharts import * as am5 from "@amcharts/amcharts5"; -import * as am5xy from "@amcharts/amcharts5/xy"; +import * as am5percent from "@amcharts/amcharts5/percent"; import am5themes_Animated from "@amcharts/amcharts5/themes/Animated"; -import Flexmonster from 'flexmonster'; const WithAmcharts: React.FC = () => { - const pivotRef: React.RefObject = useRef(null); - let root: am5.Root; - - const reportComplete = () => { - pivotRef.current?.flexmonster.off("reportcomplete", reportComplete); - drawChart(); - }; - - const drawChart = () => { - pivotRef.current?.flexmonster.amcharts?.getData( - {}, - createChart, - updateChart - ); - }; + const pivotRef: React.RefObject = useRef(null); + let root: am5.Root; + + const reportComplete = () => { + pivotRef.current?.flexmonster.off("reportcomplete"); + drawChart(); + }; + + const drawChart = () => { + // Running Flexmonster's getData() method for amCharts + pivotRef.current?.flexmonster.amcharts?.getData({}, createChart, updateChart); + }; + + const createChart = (chartData: Flexmonster.GetDataValueObject, rawData: Flexmonster.GetDataValueObject) => { + // Initializing the root element + root = am5.Root.new("amcharts-container"); + // Applying the amCharts theme + root.setThemes([am5themes_Animated.new(root)]); + // Applying number format from Flexmonster + root.numberFormatter.set("numberFormat", pivotRef.current?.flexmonster.amcharts?.getNumberFormatPattern((rawData.meta as any).formats[0])); + + // Creating a chart instance + const chart = root.container.children.push( + am5percent.PieChart.new(root, { + layout: root.verticalLayout, + innerRadius: 100, + }) + ); - const createChart = (chartData: Flexmonster.GetDataValueObject, rawData: Flexmonster.GetDataValueObject) => { - root = am5.Root.new("amcharts-container"); - let chart = root.container.children.push(am5xy.XYChart.new(root, {})); - - root.setThemes([ - am5themes_Animated.new(root), - ]); - - root.numberFormatter.set("numberFormat", pivotRef.current?.flexmonster.amcharts?.getNumberFormatPattern((rawData.meta as any).formats[0])); - - let yAxis = chart.yAxes.push(am5xy.CategoryAxis.new(root, { - categoryField: pivotRef.current?.flexmonster.amcharts?.getCategoryName(rawData)!, - renderer: am5xy.AxisRendererY.new(root, { - cellStartLocation: 0.1, - cellEndLocation: 0.9 - }) - })); - - let xAxis = chart.xAxes.push(am5xy.ValueAxis.new(root, { - renderer: am5xy.AxisRendererX.new(root, {}), - })); - - xAxis.set("numberFormatter", am5.NumberFormatter.new(root, { - "numberFormat": "#a" - })); - - let series = chart.series.push(am5xy.ColumnSeries.new(root, { - name: pivotRef.current?.flexmonster.amcharts?.getMeasureNameByIndex(rawData, 0), - xAxis: xAxis, - yAxis: yAxis as any, - sequencedInterpolation: true, - valueXField: pivotRef.current?.flexmonster.amcharts?.getMeasureNameByIndex(rawData, 0), - categoryYField: pivotRef.current?.flexmonster.amcharts?.getCategoryName(rawData), - tooltip: am5.Tooltip.new(root, { - labelText: '{name}: [bold]{valueX}[/]' - }) - })); - - chart.set("cursor", am5xy.XYCursor.new(root, { - behavior: "none", - xAxis: xAxis, - yAxis: yAxis - })); - - yAxis.data.setAll(chartData.data); - series.data.setAll(chartData.data); - - series.appear(1000); - chart.appear(1000, 100); - }; + const series = chart.series.push( + am5percent.PieSeries.new(root, { + valueField: pivotRef.current?.flexmonster.amcharts?.getMeasureNameByIndex(rawData, 0), + categoryField: pivotRef.current?.flexmonster.amcharts?.getCategoryName(rawData), + }) + ); - const updateChart = (chartData: Flexmonster.GetDataValueObject, rawData: Flexmonster.GetDataValueObject) => { - if (root) { - root.dispose(); - } - createChart(chartData, rawData); - }; + series.children.push( + am5.Label.new(root, { + text: "[#999]TOTAL:[/]\n{valueSum.formatNumber()}", + populateText: true, + textAlign: "center", + centerX: am5.p50, + centerY: am5.p50, + fontSize: 24, + fontWeight: "500", + fill: am5.color(0x555555), + oversizedBehavior: "fit", + }) + ); - return ( -
    -

    Integrating with amCharts

    - -
    -

    - Extend Flexmonster’s visualization functionality by integrating - with the amCharts library:{' '} - - Integration with amCharts - - . -

    -
    - - { - toolbar.showShareReportTab = true; - }} - reportcomplete={reportComplete} - shareReportConnection={{ - url: "https://olap.flexmonster.com:9500" - }} - width="100%" - height={600} - report="https://cdn.flexmonster.com/github/demo-report.json" - licenseFilePath="https://cdn.flexmonster.com/jsfiddle.charts.key" - /> -
    -
    -
    -
    + series.slices.template.set("tooltipText", "{category}: {value} ({valuePercentTotal.formatNumber('0.00')}%)"); + series.labels.template.set("visible", false); + series.ticks.template.set("visible", false); + + series.data.setAll(chartData.data); + + const legend = chart.children.push( + am5.Legend.new(root, { + centerX: am5.percent(50), + x: am5.percent(50), + layout: am5.GridLayout.new(root, { + maxColumns: 3, + fixedWidthGrid: true, + }), + height: am5.percent(20), + verticalScrollbar: am5.Scrollbar.new(root, { + orientation: "vertical", + }), + }) ); + legend.data.setAll(series.dataItems); + legend.valueLabels.template.set("forceHidden", true); + + series.appear(1000); + chart.appear(1000, 100); + }; + + const updateChart = (chartData: Flexmonster.GetDataValueObject, rawData: Flexmonster.GetDataValueObject) => { + root?.dispose(); + createChart(chartData, rawData); + }; + + useEffect(() => { + return () => { + // Disposing of the chart instance when the component is unmounted + root?.dispose(); + }; + }, []); + + return ( + <> +

    Integrating with amCharts

    + +
    +

    + Extend Flexmonster's visualization functionality by integrating with the amCharts library:{" "} + Integration with amCharts. +

    +
    + + { + toolbar.showShareReportTab = true; + }} + reportcomplete={reportComplete} + shareReportConnection={{ + url: "https://olap.flexmonster.com:9500", + }} + height={600} + report="https://cdn.flexmonster.com/github/charts-report.json" + licenseFilePath="https://cdn.flexmonster.com/jsfiddle.charts.key" + /> +
    +
    +
    + + ); }; export default WithAmcharts; diff --git a/typescript/src/components/ReactFlexmonsterExamples/WithAmcharts4.tsx b/typescript/src/components/ReactFlexmonsterExamples/WithAmcharts4.tsx index 203637d..8be9ac6 100644 --- a/typescript/src/components/ReactFlexmonsterExamples/WithAmcharts4.tsx +++ b/typescript/src/components/ReactFlexmonsterExamples/WithAmcharts4.tsx @@ -1,84 +1,92 @@ -import React, { useRef } from 'react'; -import * as FlexmonsterReact from 'react-flexmonster'; +import { useEffect, useRef } from "react"; +import * as FlexmonsterReact from "react-flexmonster"; +import Flexmonster from "flexmonster"; import "flexmonster/lib/flexmonster.amcharts.js"; -import * as am4core from '@amcharts/amcharts4/core'; -import * as am4charts from '@amcharts/amcharts4/charts'; -import am4themes_animated from '@amcharts/amcharts4/themes/animated'; -import Flexmonster from 'flexmonster'; + +import * as am4core from "@amcharts/amcharts4/core"; +import * as am4charts from "@amcharts/amcharts4/charts"; +import am4themes_animated from "@amcharts/amcharts4/themes/animated"; + +am4core.useTheme(am4themes_animated); const WithAmcharts4: React.FC = () => { const pivotRef: React.RefObject = useRef(null); - let chart: am4charts.PieChart; + const chartRef: React.RefObject = useRef(null); - const reportComplete = () => { - pivotRef.current?.flexmonster.off("reportcomplete", reportComplete); - drawChart(); - }; + const reportComplete = () => { + pivotRef.current?.flexmonster.off("reportcomplete"); + drawChart(); + }; - const drawChart = () => { - pivotRef.current?.flexmonster.amcharts?.getData( - {}, - createChart, - updateChart - ); - }; + const drawChart = () => { + pivotRef.current?.flexmonster.amcharts?.getData({}, createChart, updateChart); + }; - const createChart = (chartData: Flexmonster.GetDataValueObject, rawData: Flexmonster.GetDataValueObject) => { - if (pivotRef.current?.flexmonster.amcharts) { - am4core.useTheme(am4themes_animated); - chart = am4core.create("chartContainer", am4charts.PieChart); - - chart.data = chartData.data; - chart.innerRadius = am4core.percent(50); - - var pieSeries = chart.series.push(new am4charts.PieSeries()); - pieSeries.dataFields.category = pivotRef.current?.flexmonster.amcharts.getCategoryName(rawData); - pieSeries.dataFields.value = pivotRef.current?.flexmonster.amcharts.getMeasureNameByIndex(rawData, 0); - pieSeries.slices.template.stroke = am4core.color("#fff"); - pieSeries.slices.template.strokeWidth = 2; - pieSeries.slices.template.strokeOpacity = 1; - - pieSeries.hiddenState.properties.opacity = 1; - pieSeries.hiddenState.properties.endAngle = -90; - pieSeries.hiddenState.properties.startAngle = -90; - } - }; + const createChart = (chartData: Flexmonster.GetDataValueObject, rawData: Flexmonster.GetDataValueObject) => { + const chart = am4core.create("chartContainer", am4charts.PieChart); + + chart.data = chartData.data; + + const pieSeries = chart.series.push(new am4charts.PieSeries()); + pieSeries.dataFields.category = pivotRef.current?.flexmonster.amcharts?.getCategoryName(rawData); + pieSeries.dataFields.value = pivotRef.current?.flexmonster.amcharts?.getMeasureNameByIndex(rawData, 0); + pieSeries.slices.template.stroke = am4core.color("#fff"); + pieSeries.slices.template.strokeWidth = 3; + pieSeries.slices.template.strokeOpacity = 1; + + pieSeries.hiddenState.properties.opacity = 1; + pieSeries.hiddenState.properties.endAngle = -90; + pieSeries.hiddenState.properties.startAngle = -90; + chartRef.current = chart; + }; + + const updateChart = (chartData: Flexmonster.GetDataValueObject, rawData: Flexmonster.GetDataValueObject) => { + chartRef.current?.dispose(); + createChart(chartData, rawData); + }; - const updateChart = (chartData: Flexmonster.GetDataValueObject, rawData: Flexmonster.GetDataValueObject) => { - if (chart) { - chart.dispose(); - } - createChart(chartData, rawData); + useEffect(() => { + return () => { + chartRef.current?.dispose(); }; + }, []); - return ( -
    -

    Integrating with amCharts

    -
    -

    Extend Flexmonster’s visualization functionality by integrating with the amCharts - library: Integration with amCharts. -

    -
    - { - toolbar.showShareReportTab = true; - }} - reportcomplete={reportComplete} - shareReportConnection={{ - url: "https://olap.flexmonster.com:9500" - }} - width="100%" - height={600} - report="https://cdn.flexmonster.com/github/demo-report.json" - licenseFilePath="https://cdn.flexmonster.com/jsfiddle.charts.key" - /> -
    -
    -
    -
    - ); + return ( + <> +

    Integrating with amCharts 4

    +
    +

    + Extend Flexmonster's visualization functionality by integrating with the amCharts library:{" "} + Integration with amCharts. +

    +
    + { + toolbar.showShareReportTab = true; + }} + reportcomplete={reportComplete} + shareReportConnection={{ + url: "https://olap.flexmonster.com:9500", + }} + licenseFilePath="https://cdn.flexmonster.com/jsfiddle.charts.key" + /> +
    +
    +
    + + ); }; export default WithAmcharts4; diff --git a/typescript/src/components/ReactFlexmonsterExamples/WithHighcharts.tsx b/typescript/src/components/ReactFlexmonsterExamples/WithHighcharts.tsx index 21207ad..daae1ad 100644 --- a/typescript/src/components/ReactFlexmonsterExamples/WithHighcharts.tsx +++ b/typescript/src/components/ReactFlexmonsterExamples/WithHighcharts.tsx @@ -1,70 +1,72 @@ -import React, { useRef } from 'react'; -import * as FlexmonsterReact from 'react-flexmonster'; -import 'flexmonster'; -import 'flexmonster/lib/flexmonster.highcharts.js'; -import * as Highcharts from 'highcharts'; +import { useRef, useState } from "react"; +import * as FlexmonsterReact from "react-flexmonster"; +import Flexmonster from "flexmonster"; +import "flexmonster/lib/flexmonster.highcharts.js"; + +import Highcharts from "highcharts"; +import HighchartsReact from "highcharts-react-official"; +import "highcharts/modules/accessibility"; const WithHighcharts = () => { const pivotRef: React.RefObject = useRef(null); + const [chartOptions, setChartOptions] = useState({}); const reportComplete = () => { - pivotRef.current?.flexmonster.off('reportComplete', reportComplete); + pivotRef.current?.flexmonster.off("reportcomplete"); createChart(); }; const createChart = () => { pivotRef.current?.flexmonster.highcharts?.getData( - { - type: 'spline', - }, - (data: any) => { - Highcharts.chart('highcharts-container', data); - }, - (data: any) => { - Highcharts.chart('highcharts-container', data); - } - ); + { + type: "spline", + }, + (data: Flexmonster.GetDataValueObject) => { + setChartOptions(data as Highcharts.Options); + }, + (data: Flexmonster.GetDataValueObject) => { + setChartOptions(data as Highcharts.Options); + } + ); }; return ( -
    + <>

    Integrating with Highcharts

    - Integrate Flexmonster with Highcharts and see your data from a new - perspective:{' '} + Integrate Flexmonster with Highcharts and see your data from a new perspective:{" "} - Integration with Highcharts - - . + >Integration with Highcharts.

    { toolbar.showShareReportTab = true; }} shareReportConnection={{ - url: 'https://olap.flexmonster.com:9500', + url: "https://olap.flexmonster.com:9500", }} - width="100%" - height={600} - reportcomplete={reportComplete} - report="https://cdn.flexmonster.com/github/highcharts-report.json" licenseFilePath="https://cdn.flexmonster.com/jsfiddle.charts.key" />
    -
    +
    -
    + ); }; diff --git a/typescript/src/components/UIElements/LogsList.tsx b/typescript/src/components/UIElements/LogsList.tsx index d656356..e08e8b5 100644 --- a/typescript/src/components/UIElements/LogsList.tsx +++ b/typescript/src/components/UIElements/LogsList.tsx @@ -1,38 +1,52 @@ type Props = { - logsList: { - date: Date, - event: string - }[], - title: string + logsList: { + date: Date; + event: string; + }[]; + title: string; + id?: string; }; const LogsList = (props: Props) => { + const { logsList, title, id } = props; - const {logsList, title} = props; - - const logsTemplate = logsList.map((logElement: { - date: Date, - event: string - }, index: number) => { - const docRef = `https://www.flexmonster.com/api/${logElement.event}/?r=rm_react`; - return
    - [ Event ] { logElement.date.toLocaleTimeString()}: - {logElement.event + " "} - [ see details ] -
    - }) - return ( - <> -

    {title}

    -
    -
    - {logsTemplate} -
    -
    - - ); - -} + const logsTemplate = logsList.map( + ( + logElement: { + date: Date; + event: string; + }, + index: number + ) => { + const docRef = `https://www.flexmonster.com/api/${logElement.event}/?r=rm_react`; + return ( +
    + [ Event ] {logElement.date.toLocaleTimeString()}: + {logElement.event + " "}[{" "} + + see details + {" "} + ] +
    + ); + } + ); + return ( + <> +

    {title}

    +
    +
    {logsTemplate}
    +
    + + ); +}; -export default LogsList; \ No newline at end of file +export default LogsList;