mirror of
https://github.com/discourse/discourse.git
synced 2026-08-02 09:29:37 -05:00
DEV: Load chartjs via npm/webpack (#35249)
This commit is contained in:
@@ -67,8 +67,6 @@ updates:
|
||||
open-pull-requests-limit: 20
|
||||
versioning-strategy: increase
|
||||
ignore: # These are all vendored so need to be updated manually. See lib/tasks/javascript.rake
|
||||
- dependency-name: "chart.js"
|
||||
- dependency-name: "chartjs-plugin-datalabels"
|
||||
- dependency-name: "magnific-popup"
|
||||
- dependency-name: "moment"
|
||||
- dependency-name: "moment-timezone"
|
||||
|
||||
@@ -1,29 +1,33 @@
|
||||
import Component from "@glimmer/component";
|
||||
import { modifier } from "ember-modifier";
|
||||
import loadScript from "discourse/lib/load-script";
|
||||
import loadChartJS, {
|
||||
loadChartJSDatalabels,
|
||||
} from "discourse/lib/load-chart-js";
|
||||
|
||||
// args:
|
||||
// chartConfig - object
|
||||
export default class Chart extends Component {
|
||||
export default class ChartComponent extends Component {
|
||||
renderChart = modifier((element) => {
|
||||
const { chartConfig, loadChartDataLabelsPlugin } = this.args;
|
||||
|
||||
loadScript("/javascripts/Chart.min.js")
|
||||
.then(
|
||||
() =>
|
||||
loadChartDataLabelsPlugin &&
|
||||
loadScript("/javascripts/chartjs-plugin-datalabels.min.js")
|
||||
)
|
||||
.then(() => {
|
||||
if (loadChartDataLabelsPlugin) {
|
||||
(chartConfig.plugins ??= []).push(window.ChartDataLabels);
|
||||
}
|
||||
this.chart = new window.Chart(element.getContext("2d"), chartConfig);
|
||||
});
|
||||
|
||||
this.loadAndInit(element);
|
||||
return () => this.chart?.destroy();
|
||||
});
|
||||
|
||||
async loadAndInit(element) {
|
||||
const chartConfig = { ...this.args.chartConfig };
|
||||
|
||||
const Chart = await loadChartJS();
|
||||
|
||||
if (this.args.loadChartDataLabelsPlugin) {
|
||||
const ChartDataLabelsPlugin = await loadChartJSDatalabels();
|
||||
chartConfig.plugins = [
|
||||
...(chartConfig.plugins || []),
|
||||
ChartDataLabelsPlugin,
|
||||
];
|
||||
}
|
||||
|
||||
this.chart = new Chart(element.getContext("2d"), chartConfig);
|
||||
}
|
||||
|
||||
<template>
|
||||
<div ...attributes>
|
||||
<div class="chart-canvas-container">
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Component from "@glimmer/component";
|
||||
import { action } from "@ember/object";
|
||||
import didInsert from "@ember/render-modifiers/modifiers/did-insert";
|
||||
import loadScript from "discourse/lib/load-script";
|
||||
import loadChartJS from "discourse/lib/load-chart-js";
|
||||
import I18n, { i18n } from "discourse-i18n";
|
||||
|
||||
const oneDay = 86400000; // day in milliseconds
|
||||
@@ -76,7 +76,7 @@ export default class TopicViewsChart extends Component {
|
||||
|
||||
@action
|
||||
async renderChart(element) {
|
||||
await loadScript("/javascripts/Chart.min.js");
|
||||
const Chart = await loadChartJS();
|
||||
|
||||
if (!this.args.views?.stats || this.args.views?.stats?.length === 0) {
|
||||
this.noData = true;
|
||||
@@ -124,7 +124,7 @@ export default class TopicViewsChart extends Component {
|
||||
this.chart.destroy();
|
||||
}
|
||||
|
||||
this.chart = new window.Chart(context, {
|
||||
this.chart = new Chart(context, {
|
||||
type: "line",
|
||||
data: {
|
||||
datasets: [
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import { waitForPromise } from "@ember/test-waiters";
|
||||
|
||||
export default async function loadChartJS() {
|
||||
return (await waitForPromise(import("chart.js/auto"))).default;
|
||||
}
|
||||
|
||||
export async function loadChartJSDatalabels() {
|
||||
return (await waitForPromise(import("chartjs-plugin-datalabels"))).default;
|
||||
}
|
||||
@@ -2,9 +2,6 @@
|
||||
// Update it by running `rake javascript:update`
|
||||
|
||||
export const PUBLIC_JS_VERSIONS = {
|
||||
"chart.min.js": "chart.js/3.5.1/chart.min.js",
|
||||
"chartjs-plugin-datalabels.min.js":
|
||||
"chartjs-plugin-datalabels/2.2.0/chartjs-plugin-datalabels.min.js",
|
||||
"jquery.magnific-popup.min.js":
|
||||
"magnific-popup/1.1.0/jquery.magnific-popup.min.js",
|
||||
};
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
"@messageformat/runtime": "^3.0.1",
|
||||
"ace-builds": "^1.43.3",
|
||||
"decorator-transforms": "^2.3.0",
|
||||
"chart.js": "3.5.1",
|
||||
"chartjs-plugin-datalabels": "2.2.0",
|
||||
"diff": "^8.0.2",
|
||||
"discourse-widget-hbs": "workspace:1.0.0",
|
||||
"ember-curry-component": "^0.3.1",
|
||||
|
||||
@@ -19,19 +19,19 @@ module("Unit | Utility | load-script", function (hooks) {
|
||||
|
||||
test("generates URLs with version number in the query params", function (assert) {
|
||||
assert.strictEqual(
|
||||
cacheBuster("/javascripts/chart.min.js"),
|
||||
`/javascripts/${jsVersions["chart.min.js"]}`
|
||||
cacheBuster("/javascripts/jquery.magnific-popup.min.js"),
|
||||
`/javascripts/${jsVersions["jquery.magnific-popup.min.js"]}`
|
||||
);
|
||||
});
|
||||
|
||||
test("lookups are case-insensitive", (assert) => {
|
||||
assert.strictEqual(
|
||||
cacheBuster("/javascripts/Chart.min.js"),
|
||||
`/javascripts/${jsVersions["chart.min.js"]}`
|
||||
cacheBuster("/javascripts/JQuery.magnific-popup.min.js"),
|
||||
`/javascripts/${jsVersions["jquery.magnific-popup.min.js"]}`
|
||||
);
|
||||
assert.strictEqual(
|
||||
cacheBuster("/javascripts/chart.min.js"),
|
||||
`/javascripts/${jsVersions["chart.min.js"]}`
|
||||
cacheBuster("/javascripts/jquery.magnific-popup.min.js"),
|
||||
`/javascripts/${jsVersions["jquery.magnific-popup.min.js"]}`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -64,11 +64,7 @@ def write_hbs_template(path, task_name, template)
|
||||
end
|
||||
|
||||
def dependencies
|
||||
[
|
||||
{ source: "chart.js/dist/chart.min.js", public: true },
|
||||
{ source: "chartjs-plugin-datalabels/dist/chartjs-plugin-datalabels.min.js", public: true },
|
||||
{ source: "magnific-popup/dist/jquery.magnific-popup.min.js", public: true },
|
||||
]
|
||||
[{ source: "magnific-popup/dist/jquery.magnific-popup.min.js", public: true }]
|
||||
end
|
||||
|
||||
def node_package_name(f)
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
"@glint/template": "^1.6.0-alpha.2",
|
||||
"@rdil/parallel-prettier": "^3.0.0",
|
||||
"@swc/core": "^1.13.5",
|
||||
"chart.js": "3.5.1",
|
||||
"chartjs-plugin-datalabels": "2.2.0",
|
||||
"chrome-launcher": "^1.2.1",
|
||||
"chrome-remote-interface": "^0.33.3",
|
||||
"concurrently": "^9.2.1",
|
||||
|
||||
+2
-3
@@ -3,7 +3,7 @@ import { on } from "@ember/modifier";
|
||||
import { action } from "@ember/object";
|
||||
import didInsert from "@ember/render-modifiers/modifiers/did-insert";
|
||||
import { bind } from "discourse/lib/decorators";
|
||||
import loadScript from "discourse/lib/load-script";
|
||||
import loadChartJS from "discourse/lib/load-chart-js";
|
||||
import themeColor from "../lib/themeColor";
|
||||
|
||||
export default class DataExplorerBarChart extends Component {
|
||||
@@ -80,9 +80,8 @@ export default class DataExplorerBarChart extends Component {
|
||||
|
||||
@bind
|
||||
async initChart(canvas) {
|
||||
await loadScript("/javascripts/Chart.min.js");
|
||||
const Chart = await loadChartJS();
|
||||
const context = canvas.getContext("2d");
|
||||
// eslint-disable-next-line
|
||||
this.chart = new Chart(context, this.config);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ import concatClass from "discourse/helpers/concat-class";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import discourseComputed from "discourse/lib/decorators";
|
||||
import loadScript from "discourse/lib/load-script";
|
||||
import { i18n } from "discourse-i18n";
|
||||
import ComboBox from "select-kit/components/combo-box";
|
||||
import PollBreakdownChart from "discourse/plugins/poll/discourse/components/poll-breakdown-chart";
|
||||
@@ -30,11 +29,9 @@ export default class PollBreakdownModal extends Component {
|
||||
|
||||
init() {
|
||||
this.set("groupedBy", this.groupableUserFields[0]?.id);
|
||||
loadScript("/javascripts/Chart.min.js")
|
||||
.then(() => loadScript("/javascripts/chartjs-plugin-datalabels.min.js"))
|
||||
.then(() => {
|
||||
this.fetchGroupedPollData();
|
||||
});
|
||||
|
||||
this.fetchGroupedPollData();
|
||||
|
||||
super.init(...arguments);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,9 @@ import { next } from "@ember/runloop";
|
||||
import { htmlSafe } from "@ember/template";
|
||||
import { classNames } from "@ember-decorators/component";
|
||||
import discourseComputed from "discourse/lib/decorators";
|
||||
import loadChartJS, {
|
||||
loadChartJSDatalabels,
|
||||
} from "discourse/lib/load-chart-js";
|
||||
import I18n from "discourse-i18n";
|
||||
import { getColors } from "discourse/plugins/poll/lib/chart-colors";
|
||||
import { PIE_CHART_TYPE } from "../components/modal/poll-ui-builder";
|
||||
@@ -37,11 +40,19 @@ export default class PollBreakdownChart extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
didInsertElement() {
|
||||
async didInsertElement() {
|
||||
super.didInsertElement(...arguments);
|
||||
|
||||
const canvas = this.element.querySelector("canvas");
|
||||
this._chart = new window.Chart(canvas.getContext("2d"), this.chartConfig);
|
||||
|
||||
const [Chart, ChartDataLabelsPlugin] = await Promise.all([
|
||||
loadChartJS(),
|
||||
loadChartJSDatalabels(),
|
||||
]);
|
||||
this._chart = new Chart(canvas.getContext("2d"), {
|
||||
...this.chartConfig,
|
||||
plugins: [ChartDataLabelsPlugin],
|
||||
});
|
||||
}
|
||||
|
||||
didReceiveAttrs() {
|
||||
@@ -79,7 +90,6 @@ export default class PollBreakdownChart extends Component {
|
||||
|
||||
return {
|
||||
type: PIE_CHART_TYPE,
|
||||
plugins: [window.ChartDataLabels],
|
||||
data: {
|
||||
datasets: [
|
||||
{
|
||||
|
||||
@@ -6,6 +6,7 @@ import { htmlSafe } from "@ember/template";
|
||||
import { tagName } from "@ember-decorators/component";
|
||||
import { propertyEqual } from "discourse/lib/computed";
|
||||
import discourseComputed from "discourse/lib/decorators";
|
||||
import loadChartJS from "discourse/lib/load-chart-js";
|
||||
import I18n, { i18n } from "discourse-i18n";
|
||||
import { getColors } from "discourse/plugins/poll/lib/chart-colors";
|
||||
|
||||
@@ -22,8 +23,16 @@ export default class PollBreakdownOption extends Component {
|
||||
onMouseOut = null;
|
||||
|
||||
@propertyEqual("highlightedOption", "index") highlighted;
|
||||
|
||||
@equal("displayMode", "percentage") showPercentage;
|
||||
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
loadChartJS().then((Chart) => {
|
||||
this.set("Chart", Chart);
|
||||
});
|
||||
}
|
||||
|
||||
@discourseComputed("option.votes", "totalVotes")
|
||||
percent(votes, total) {
|
||||
return I18n.toNumber((votes / total) * 100.0, { precision: 1 });
|
||||
@@ -42,10 +51,10 @@ export default class PollBreakdownOption extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
@discourseComputed("highlighted", "optionColors", "index")
|
||||
colorPreviewStyle(highlighted, optionColors, index) {
|
||||
@discourseComputed("Chart", "highlighted", "optionColors", "index")
|
||||
colorPreviewStyle(Chart, highlighted, optionColors, index) {
|
||||
const color = highlighted
|
||||
? window.Chart.helpers.getHoverColor(optionColors[index])
|
||||
? Chart?.helpers.getHoverColor(optionColors[index])
|
||||
: optionColors[index];
|
||||
|
||||
return htmlSafe(`background: ${color};`);
|
||||
|
||||
@@ -3,7 +3,7 @@ import { action } from "@ember/object";
|
||||
import didInsert from "@ember/render-modifiers/modifiers/did-insert";
|
||||
import { htmlSafe } from "@ember/template";
|
||||
import { modifier } from "ember-modifier";
|
||||
import loadScript from "discourse/lib/load-script";
|
||||
import loadChartJS from "discourse/lib/load-chart-js";
|
||||
import { getColors } from "discourse/plugins/poll/lib/chart-colors";
|
||||
import { PIE_CHART_TYPE } from "../components/modal/poll-ui-builder";
|
||||
|
||||
@@ -115,7 +115,7 @@ export default class PollResultsPieComponent extends Component {
|
||||
|
||||
@action
|
||||
async drawPie() {
|
||||
await loadScript("/javascripts/Chart.min.js");
|
||||
const Chart = await loadChartJS();
|
||||
|
||||
const data = this.args.options.map((option) => option.votes);
|
||||
const labels = this.args.options.map((option) => option.html);
|
||||
@@ -123,7 +123,7 @@ export default class PollResultsPieComponent extends Component {
|
||||
legendContainerId: this.legendElement.id,
|
||||
});
|
||||
const el = this.canvasElement;
|
||||
// eslint-disable-next-line no-undef
|
||||
|
||||
this._chart = new Chart(el.getContext("2d"), config);
|
||||
}
|
||||
|
||||
|
||||
Generated
+6
-6
@@ -61,12 +61,6 @@ importers:
|
||||
'@swc/core':
|
||||
specifier: ^1.13.5
|
||||
version: 1.13.5
|
||||
chart.js:
|
||||
specifier: 3.5.1
|
||||
version: 3.5.1
|
||||
chartjs-plugin-datalabels:
|
||||
specifier: 2.2.0
|
||||
version: 2.2.0(chart.js@3.5.1)
|
||||
chrome-launcher:
|
||||
specifier: ^1.2.1
|
||||
version: 1.2.1
|
||||
@@ -302,6 +296,12 @@ importers:
|
||||
ace-builds:
|
||||
specifier: ^1.43.3
|
||||
version: 1.43.3
|
||||
chart.js:
|
||||
specifier: 3.5.1
|
||||
version: 3.5.1
|
||||
chartjs-plugin-datalabels:
|
||||
specifier: 2.2.0
|
||||
version: 2.2.0(chart.js@3.5.1)
|
||||
decorator-transforms:
|
||||
specifier: ^2.3.0
|
||||
version: 2.3.0(@babel/core@7.28.4)
|
||||
|
||||
-13
File diff suppressed because one or more lines are too long
-7
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user