Skip to content

Commit

Permalink
Merge pull request #6 from DataShades/LLCAXCHZF-57
Browse files Browse the repository at this point in the history
LLCAXCHZF-57/Implement Zoom and Pan Functionality for Chart.js
  • Loading branch information
TomeCirun authored Jul 29, 2024
2 parents 8abbfc1 + 358cbee commit 3742900
Show file tree
Hide file tree
Showing 10 changed files with 162 additions and 2 deletions.
52 changes: 50 additions & 2 deletions ckanext/charts/assets/js/charts-render-chartjs.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,56 @@ ckan.module("charts-render-chartjs", function ($, _) {
return;
}

var chart = new Chart(this.el[0].getContext("2d"), this.options.config);
window.charts_chartjs = chart;
const unsupportedTypes = ['pie', 'doughnut', 'radar'];
const isZoomSupported = !unsupportedTypes.includes(this.options.config.type);

if (isZoomSupported) {
const zoomOptions = this.options.config.options.plugins.zoom;

this.options.config.options.plugins.title.text = () => {
return 'Zoom: ' + this.zoomStatus(zoomOptions) + ', Pan: ' + this.panStatus(zoomOptions);
};

$('#resetZoom').on('click', this.resetZoom);
$('#toggleZoom').on('click', (e) => this.toggleZoom(e, zoomOptions));
$('#togglePan').on('click', (e) => this.togglePan(e, zoomOptions));
}

$(".zoom-control").toggle(isZoomSupported);

window.charts_chartjs = new Chart(this.el[0].getContext("2d"), this.options.config);
},

resetZoom: function(event) {
event.preventDefault();
window.charts_chartjs.resetZoom();
},

zoomStatus: function(zoomOptions) {
return zoomOptions.zoom.drag.enabled ? 'enabled' : 'disabled';
},

panStatus: function(zoomOptions) {
return zoomOptions.pan.enabled ? 'enabled' : 'disabled';
},

toggleZoom: function (event, zoomOptions) {
event.preventDefault();

const zoomEnabled = zoomOptions.zoom.wheel.enabled;

zoomOptions.zoom.wheel.enabled = !zoomEnabled;
zoomOptions.zoom.pinch.enabled = !zoomEnabled;
zoomOptions.zoom.drag.enabled = !zoomEnabled;

window.charts_chartjs.update();
},

togglePan: function(event, zoomOptions) {
event.preventDefault();

zoomOptions.pan.enabled = !zoomOptions.pan.enabled;
window.charts_chartjs.update();
}
};
});
7 changes: 7 additions & 0 deletions ckanext/charts/assets/js/vendor/chartjs-plugin-zoom.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions ckanext/charts/assets/js/vendor/hammerjs.min.js

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions ckanext/charts/assets/webassets.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ chartjs:
- js/vendor/chartjs.min.js
- js/vendor/chartjs-adapter-moment.js
- js/charts-render-chartjs.js
- js/vendor/hammerjs.min.js
- js/vendor/chartjs-plugin-zoom.min.js
extra:
preload:
- base/main
Expand Down
11 changes: 11 additions & 0 deletions ckanext/charts/chart_builders/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -661,3 +661,14 @@ def filter_field(self, choices: list[dict[str, str]]) -> dict[str, Any]:
],
"group": "Filter",
}

def engine_details_field(self) -> dict[str, Any]:
"""
Provides details about zoom functionality support in various charting libraries.
"""
return {
"field_name": "engine_details",
"label": "Engine details",
"form_snippet": "chart_engine_details.html",
"group": "Structure",
}
40 changes: 40 additions & 0 deletions ckanext/charts/chart_builders/chartjs.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,36 @@ def get_supported_forms(cls) -> list[type[Any]]:
ChartJSRadarForm,
]

def create_zoom_and_title_options(self, options: str[dict, Any]) -> dict[str, Any]:
"""Add zoom and title plugin options to the provided options dictionary"""
zoom_options = {
"zoom": {
"wheel": {"enabled": True},
"pinch": {"enabled": True},
"drag": {"enabled": True},
"mode": "xy",
},
"pan": {
"enabled": True,
"modifierKey": "shift",
"mode": "xy",
},
}

if "plugins" not in options:
options["plugins"] = {}

options["plugins"].update(
{
"zoom": zoom_options,
"title": {
"display": True,
"position": "bottom",
},
}
)
return options


class ChartJSBarBuilder(ChartJsBuilder):
def _prepare_data(self) -> dict[str, Any]:
Expand Down Expand Up @@ -65,6 +95,7 @@ def _prepare_data(self) -> dict[str, Any]:
)

data["data"]["datasets"] = datasets
data["options"] = self.create_zoom_and_title_options(data["options"])

return data

Expand All @@ -88,6 +119,7 @@ def get_form_fields(self):
self.description_field(),
self.engine_field(),
self.type_field(chart_types),
self.engine_details_field(),
self.x_axis_field(columns),
self.y_multi_axis_field(columns),
self.more_info_button_field(),
Expand Down Expand Up @@ -135,6 +167,7 @@ def to_json(self) -> str:
"reverse": self.settings.get("invert_y", False),
},
}
data["options"] = self.create_zoom_and_title_options(data["options"])
return json.dumps(data)


Expand All @@ -154,6 +187,7 @@ def get_form_fields(self):
self.description_field(),
self.engine_field(),
self.type_field(chart_types),
self.engine_details_field(),
self.x_axis_field(columns),
self.y_multi_axis_field(columns),
self.more_info_button_field(),
Expand Down Expand Up @@ -213,6 +247,7 @@ def get_form_fields(self):
self.description_field(),
self.engine_field(),
self.type_field(chart_types),
self.engine_details_field(),
self.values_field(columns),
self.names_field(columns),
self.more_info_button_field(),
Expand Down Expand Up @@ -257,6 +292,7 @@ def to_json(self) -> str:
"data": dataset_data,
}
]
data["options"] = self.create_zoom_and_title_options(data["options"])
return json.dumps(self._configure_date_axis(data))

def _configure_date_axis(self, data: dict[str, Any]) -> dict[str, Any]:
Expand Down Expand Up @@ -302,6 +338,7 @@ def get_form_fields(self):
self.description_field(),
self.engine_field(),
self.type_field(chart_types),
self.engine_details_field(),
self.x_axis_field(columns),
self.y_axis_field(columns),
self.more_info_button_field(),
Expand Down Expand Up @@ -340,6 +377,8 @@ def to_json(self) -> str:
data["data"]["datasets"] = [
{"label": self.settings["y"], "data": dataset_data},
]
data["options"] = self.create_zoom_and_title_options(data["options"])

return json.dumps(self._configure_date_axis(data))

def _calculate_bubble_radius(self, data_series: pd.Series, max_size: int) -> int:
Expand Down Expand Up @@ -425,6 +464,7 @@ def get_form_fields(self):
self.description_field(),
self.engine_field(),
self.type_field(chart_types),
self.engine_details_field(),
self.names_field(columns),
self.values_multi_field(
columns,
Expand Down
Loading

0 comments on commit 3742900

Please sign in to comment.