AmStockChart zooms window when window is at the edge - javascript

Here is an example of the AmSerialChart, in which you can use the scroll button to scroll the window over the data. When you reach the end (or beginning) and continue scrolling, the window will remain the same width.
Here is another example, using the AmStockChart. The window is zoomed in using a slightly different method: zoomToIndexes does not exist for stockCharts, thus the "zoom" method is used.
var chartData = generateChartData();
var chart = AmCharts.makeChart("chartdiv", {
"categoryAxesSettings": {
minPeriod: "fff",
},
"chartScrollbarSettings": {
graph: "g1",
usePeriod: "fff",
},
"dataSets": [
{
mouseWheelZoomEnabled: false,
categoryField: "date",
dataProvider: chartData,
fieldMappings: [
{
fromField: "gg1",
toField: "gg1"
}, {
fromField: "gg2",
toField: "gg2"
}
],
}
],
"mouseWheelScrollEnabled": true,
"panels": [
{
stockGraphs: [
{
id: "g1",
valueField: "gg1",
type: "step",
}
],
}, {
stockGraphs: [
{
valueField: "gg2",
type: "step",
}
],
}
],
"type": "stock",
});
When you scroll to the left in the StockChart, the window will reduce in size!
So far, I have not been able to identify a reason why the SerialChart does not reduce the size, while the StockChart does. I did find a post on SO that says to set mouseWheelZoomEnabled to false, however this option is for the SerialChart, not the StockChart.
I guess it is possible to add a listner to the scroll event, and prevent the window from reducing in size when it collides with the left or right side, however... I assume there is a better reason.
My question: How to prevent the window from reducing in size in the AmStockChart?

You have to set minSelectedTime in the panelsSettings to achieve the same behavior in a stock chart. Note that this will also prevent the scrollbar from zooming to a smaller time frame when dragging the sliders directly:
var chart = AmCharts.makeChart("chartdiv", {
panelsSettings: {
mouseWheelZoomEnabled: false,
minSelectedTime: 4.32e+9,
mouseWheelScrollEnabled: true
},
// ...
});
Demo

Related

HighCharts / HighStock newly added series have problem with shared tooltips and mouse hover effect

I draw a default OHLC chart. Then add a simple scatter series to it.
I set chart level config to share tooltips.
tooltip: { shared: true }.
But two series won't share tooltips at all.
Another big problem is that I cannot control the mouse hover effect on the new series. If you try the demo below, after clicking the AddSeries button at the bottom, the newly added series will be highlighted on mouse hover. I try to remove the mouse over effect and control it with the lineWidthPlus parameter, but there is no effect on the newly added series. Can anyone shed some light on this?
"hover": {
"enabled": false
},
https://jsfiddle.net/2t7fg9rc/
What do you think about adding the line series instead of scatter? I cannot see the hover issue that you described while using the line series.
var seriesConfig = {
"data": [
[1557322200000, 50.72],
[1566999000000, 51.03],
[1577197800000, 70.73],
[1588858200000, 75.93],
[1601040600000, 108.43],
[1620394200000, 130.85]
],
"type": "line",
"id": "Indicator",
"name": "Indicator",
"yAxis": 0,
"color": "rgb(256,0,0,0.75)",
"marker": {
enabled: true,
"symbol": "circle",
"radius": "2"
},
"showInNavigator": false,
"showInLegend": true,
"states": {
"inactive": {
"opacity": 1
},
"hover": {
"enabled": false
},
"stickyTracking": false
}
};
Demo: https://jsfiddle.net/BlackLabel/hfzwd8Lc/

Apex Charts dont resize properly when using Flexbox

Recently I changed Floats to FlexBox to have easier work with panels (as advised on other questions I did). While most of the things are working as I expect it, I'm having a problem with Apex Charts after the change.
Full code is here:
https://github.com/EvotecIT/PSWriteHTML/blob/master/Examples/Example12-Charts/Example12.html
Here's how it looks when loaded. You will notice that in 1st and 2nd-row charts go out of bounds even thou the panel they are in is in place and it works for the top row.
And if I do resize (like 1mm) it will start working correctly.
Any idea what could be the problem?
In apex charts CSS it has comments to not use overflow (I tried and it doesn't do anything) but to be honest, I even once forgot to attach that CSS and nothing changed (like everything is done by the JS.
.apexcharts-canvas {
position: relative;
user-select: none;
/* cannot give overflow: hidden as it will crop tooltips which overflow outside chart area */
}
/* scrollbar is not visible by default for the legend, hence forcing the visibility */
Keep in mind that I'm a total noob when it comes to JS/CSS/HTML so excuse my language.
You need to move all your scripts to the end instead of injecting in the HTML to allow the SVG Document parser to get the element's size correctly.
Working Codepen Example
var options = {
"chart": {
"height": 350,
"type": "line",
"toolbar": {
"show": true,
"tools": {
"download": true,
"selection": true,
"zoom": true,
"zoomin": true,
"zoomout": true,
"pan": true,
"reset": true
},
"autoSelected": "zoom"
}
},
"plotOptions": {
"bar": {
"horizontal": true
}
},
"dataLabels": {
"enabled": true,
"offsetX": -6,
"style": {
"fontSize": "12px",
"colors": [
null
]
}
},
"series": [{
"name": "People count",
"data": [
400,
430,
448
]
},
{
"name": "People death",
"data": [
450,
0,
200
]
}
],
"xaxis": {
"type": "category",
"categories": [
"2015",
"2016",
"2017"
]
},
"stroke": {
"show": true,
"curve": "straight",
"width": 2,
"colors": [
"#0000ff",
"#008000"
]
},
"legend": {
"position": "right",
"offsetY": 100,
"height": 230
},
"title": {
}
}
var chart = new ApexCharts(document.querySelector('#ChartID-2rhiatbe'),
options
);
chart.render();

Amstock chart doesn't zoom on init event

I need to zoom my chart to a specified period on init event.
"listeners": [{
"event": "zoomed",
"method": this.calulateMetrics
},{
"event": "dataUpdated",
"method": this.showPeriod
}, {
"event": "init",
"method": this.showPeriod
},{
"event": "rendered",
"method": this.showPeriod
}],
showPeriod(event) {
// Retrieve the data
let dates = this.$store.getters.getDates
let startDate = dates[0]
let endDate = (dates[dates.length - 1])
endDate.setHours(22)
try {
this.chart.zoom(startDate, endDate)
console.log("Last date", endDate)
} catch(err) {
console.log("Error",(err.message))
}
},
Although I can't catch any errors the period remains the same.
Beside init I tried rendered and dataUpdated but it didn't help me either.
But when I trigger the call to external event <v-btn v-on:click="showPeriod">Button</v-btn> it works fine.
The whole options file is following:
this.chart = window.AmCharts.makeChart("chartdiv", {
"path": AmCharts_path,
"type": "stock",
"theme": "light",
"dataSets": this.$store.state.portfoliosData.performance.map(function (port, idx) {
return {
"title": port.name,
"fieldMappings": [{
"fromField": "value",
"toField": "value"
}],
"dataProvider": port.data,
"compared": (idx === 0 ? false : true),
"categoryField": "date"
}
}),
"panels": [{
"title": "Value",
"percentHeight": 70,
"stockGraphs": [
{
"id": "g1",
"valueField": "value",
"comparable": true,
"compareField": "value",
"balloonFunction": this.ballonRender,
"compareGraphBalloonFunction": this.ballonRender
}]
}],
"chartScrollbarSettings": {
"graph": "g1",
"markPeriodChange": true
},
"categoryAxis": {
"parseDates": true,
},
"categoryAxesSettings": {
"groupToPeriods": ["DD"]
},
"balloon": {
"fixedPosition": true,
"maxWidth": 10000,
"offsetY": 1,
},
"dataDateFormat": "YYYY-MM-DD",
"chartCursorSettings": {
"valueBalloonsEnabled": true,
"categoryBalloonEnabled": true,
"selectWithoutZooming": true,
"showNextAvailable": true,
"categoryBalloonAlpha": 0.8,
"bulletsEnabled": true,
"bulletSize": 10,
"valueZoomable":true,
"usePeriod": "DD",
"categoryBalloonDateFormats": [
{period:'fff',format:'JJ:NN:SS'},
{period:'ss',format:'JJ:NN:SS'},
{period:'mm',format:'JJ:NN'},
{period:'hh',format:'JJ:NN'},
{period:'DD',format:'EEEE, MMM DD'},
{period:'WW',format:'EEEE, MMM DD'},
{period:'MM',format:'MMM'},
{period:'YYYY',format:'YYYY'}
]
},
"periodSelector": {
"position": "bottom"
},
});
},
Reproduction link can be find here
The main issue is that AmCharts' listener callbacks don't understand your component scope. this in the callbacks refers to AmCharts' callback scope, not your component. Every AmCharts listener provides a reference to itself in the event's chart property (see init, for example), so changing all of your this.chart lines to event.chart in your callbacks will fix that part of the problem. If you need a reference to your component itself, add a custom property to the chart object in your renderGraph() method then refer to that through event.chart:
renderGraph() {
// ...
this.chart = window.AmCharts.makeChart("chartdiv", {
// ...
componentRef: this,
// ...
})
}
//example using initPeriod:
initPeriod(event) { //event parameter contains {type: "init", chart: stockChartReference}
console.log("init period")
let dates = event.chart.componentRef.$store.getters.getDates
let startDate = dates[0]
let endDate = (dates[dates.length - 1])
endDate.setHours(22)
try {
event.chart.zoom(startDate, endDate)
console.log("Last date", endDate)
} catch(err) {
console.log("Error",(err.message))
}
},
Your zoomed listener is refering to an undefined method called calulateMetrics. I see a method called calculateMetrics in amstore but I'm not sure if that's what you meant and changing it to that doesn't seem to work for me, so I defer to you on adding the appropriate method. Adding that missing method along with making sure that you refer to the chart object correctly like the other callbacks will fix your problem.
Demo for everything except zoomed due to the missing method: https://codesandbox.io/s/5wpopzwlnp

Click event for label in amCharts

I am working on amCharts Donut chart.
Following is the script for creating the chart.
JS
var chart = AmCharts.makeChart( "chartdiv", {
"type": "pie",
"pullOutDuration":0.5,
"pullOutRadius": "5",
"theme": "light",
"dataProvider": [ {
"title": "Aaa",
"value": 10,
}, {
"title": "Bbb",
"value": 10,
},{
"title":"Ccc",
"value":10,
},{
"title":"Ddd",
"value":10,
},{
"title":"Eee",
"value":10,
}],
"titleField": "title",
"valueField": "value",
"labelRadius": 50,
"radius": "35%",
"innerRadius": "85%",
"labelText": "[[title]]",
"export": {
"enabled": true
},
"baseColor":"#7a4436",
"pullOutOnlyOne":true,
"startEffect":"easeOutSine",
"pullOutEffect":"easeOutSine",
"showBalloon":false,
"listeners": [{
"event": "clickSlice",
"method": function(e) {
var dp = e.dataItem.dataContext;
alert(dp.title + ':'+dp.value)
e.chart.validateData();
}
}]
});
I am able to give click event listener for each slice of the chart.
But I would like to add a click event for label of each slice. So here in my example click event for the labels Aaa, Bbb, etc..
Edit
or how to give an anchor tag to these Labels??
Here is the working fiddle demo
Normally the listener for clickSlice is only attached to the wedge and the little tick to the label, but not to the label itself.
You can do this manually though, using this code piece:
chart.addListener("init", function() {
var d = chart.chartData;
for (var i = 0; i < d.length; i++) {
d[i].label.node.style.pointerEvents = "auto";
chart.addEventListeners(d[i].labelSet, d[i]);
}
});
As the labels have the pointer-events style assigned to none automatically, you have to change this back, so the mouse-events can be registered. Then you can add a listener manually to the svg element using a method provided by the chart.
You have to do this after the chart was initialized. However if you want to remain the e.chart.validateData() call in your handler, you have to listen on a different event (like drawn).
If the purpose of e.chart.validateData() was to stop a slice to be pulled out, the better way to do this would be using pullOutRadius: 0
Here's a demo.
Updated simple answer for v4:
const yAxisLabel = mySeries.bullets.push(new am4charts.LabelBullet());
yAxisLabel.label.interactionsEnabled = false;

dynamically changing chart series extjs 4

I'm using Extjs 4 with the MVC architecture.
I have a python script that outputs this Json Data :
{
"data": [
{
"inAnalysis": 3,
"inQuest": 2,
"inDevelopment": 6,
"total": 12,
"inValidation": 1,
"Month": 1303
},
{
"inAnalysis": 1,
"total": 5,
"Month": 1304,
"inDevelopment": 4
}
],
"success": true,
"metaData": {
"fields": [
{
"name": "inAnalysis"
},
{
"name": "inQuest"
},
{
"name": "inDevelopment"
},
{
"name": "inValidation"
},
{
"name": "isDuplicate"
},
{
"name": "New"
},
{
"name": "total"
}
],
"root": "data"
}
}
I want the fields of my MetaData to be used as the chart series, so I have a store like this :
Ext.define('Proj.store.ChartData', {
extend: 'Ext.data.Store',
autoload: true,
proxy: {
type: 'ajax',
url : 'data/getParams.py',
reader: new Ext.data.JsonReader({
fields:[]
}),
root: 'data'
}
And to add series to the chart I did this :
var chart = Ext.widget('drawchart');
var fields = [];
chartStore.each(function (field) {
fields.push(Ext.create('Ext.data.Field', {
name: field.get('name')
}));
});
chartModel.prototype.fields.removeAll();
chartModel.prototype.fields.addAll(fields);
var series = [];
for (var i = 1; i < fields.length; i++) {
var newSeries = new Ext.chart.BarSeries({
type: 'column',
displayName: fields[i].name,
xField: ['Month'],
yField: fields[i].name,
style: {
mode: 'stretch',
color: this.chartColors[i + 1]
}
});
series.push(newSeries);
chart.series = series;
};
chart.bindStore(chartStore);
chart.redraw();
chart.refresh();
But It's not working, I think the fields array is always empty...
Any help would be appreciated:
Swapping or reloading a store would be easy, however you'd have a very hard time reconfiguring axes and series a posteriori... Ext's chart just don't support that. It would be possible to replace the axis in the myChart.axes collection, and same for series, and then with a careful study of the code, replace remove the existing sprites, etc. However that's a fool's path since, for once your code will be very fragile against future evolutions of Ext's chart code (which happen), and second there is a far more easier and reliable solution. That is creating a new chart, remove the old one, put the new one in its place, and pouf! The user won't see the difference.
You're not giving a lot of information about your code, so I'll work a solution out of the Bar chart example.
First, you need to fix your store:
Ext.define('Proj.store.ChartData', {
extend: 'Ext.data.Store',
//autoload: true,
autoLoad: true, // there was a type in there
fields: [], // was missing
proxy: {
type: 'ajax',
url : 'data/getParams.py',
// better to inline the proxy (lazy init)
reader: {
type: 'json'
,root: 'data' // and root is an option of the reader, not the proxy
}
// reader: new Ext.data.JsonReader({
// fields:[]
// }),
// root: 'data'
}
});
Then, let's enrich your response a bit in order to minimize the prior client-side knowledge of the model to none. I've added a totalField and a categoryField to the metaData node, that we'll use for the axis and series:
{
"data": [
{
"inAnalysis": 3,
"inQuest": 2,
"inDevelopment": 6,
"total": 12,
"inValidation": 1,
"Month": 1303
},
{
"inAnalysis": 1,
"total": 5,
"Month": 1304,
"inDevelopment": 4
}
],
"success": true,
"metaData": {
"totalField": "total",
"categoryField": "Month",
"fields": [
{
"name": "Month"
},
{
"name": "inAnalysis"
},
{
"name": "inQuest"
},
{
"name": "inDevelopment"
},
{
"name": "inValidation"
},
{
"name": "isDuplicate"
},
{
"name": "New"
},
{
"name": "total"
}
],
"root": "data"
}
}
Please, notice that the proxy will catch the metaData in the response automatically and reconfigure its store's (implicit) model accordingly... so you don't need your gloubiboulga to do it yourself. It is also worth noting that the reader will keep a copy of the raw response data in its rawData property; that will be useful to get the custom information we've added.
Now that we have a proper store that will receive a detailed response, let's use it:
new Proj.store.ChartData({
listeners: {
load: replaceChart
}
});
That will trigger the replaceChart method, that will create a brand new chart from the meta and data given by the server and destroy and replace the old one. Here's the function:
function replaceChart(chartStore) {
// Grab the name of the total & category fields as instructed by the server
var meta = chartStore.getProxy().getReader().rawData.metaData,
totalField = meta.totalField,
categoryField = meta.categoryField;
// Build a list of all field names, excluding the total & category ones
var fields = Ext.Array.filter(
Ext.pluck(chartStore.model.getFields(), 'name'),
function(field) {
return field !== categoryField && field !== totalField;
}
);
// Create a pimping new chat like you like
var chart = Ext.create('Ext.chart.Chart', {
store: chartStore,
legend: true,
axes: [{
type: 'Numeric',
position: 'bottom',
fields: [totalField]
}, {
type: 'Category',
position: 'left',
fields: [categoryField]
}],
series: [{
type: 'bar',
axis: 'bottom',
label: {
display: 'insideEnd',
field: fields
},
xField: categoryField,
yField: fields,
stacked: true // or not... like you want!
}]
});
// Put it in the exact same place as the old one, that will trigger
// a refresh of the layout and a render of the chart
var oldChart = win.down('chart'),
oldIndex = win.items.indexOf(oldChart);
win.remove(oldChart);
win.insert(oldIndex, chart);
// Mission complete.
}
Try to clear lines cache of unused series:
Ext.Array.each(chart.series.items, function(item){
if(!item.items.length){
item.line = null;
}
});

Categories

Resources