Destroy ChartJS rendered with Symfony - javascript

i have a little problem with my Symfony/ChartJS Application.
So if i create a Chart with JS like var myChart = new Chart.. and so on, i can easily destroy the Chart with myChart.destory(); because i can address the ChartObject.
My Problem:
The first Chart i Render with my SymfonyController. So i render the chart in my Controller with
return $this->render('category.html.twig', [
'chart' => $chart]);
In Twig i assign an ID to the Chart {{ render_chart(chart, {'id': 'my-chart'}) }}.
But i dont really know how i can adress the whole Chartobject in Js. So how i can destroy the Chart i created with my Symfonycontroller? Anyone have a suggestion?
Thank you in advance!
//EDIT
The normal way with const chart = Chart.getChart('my-chart'); don't work either. Here is my Canvas-ConsoleLog for more information:
<canvas data-controller="symfony--ux-chartjs--chart" data-symfony--ux-chartjs--chart-view-value="(i deleted the values for better legibility)" id="my-chart" style="display: block; box-sizing: border-box; height: 407.778px; width: 816.667px;" width="735" height="367"></canvas>
The strange thing:
when i try the log: console.log(document.getElementById("my-chart").getContext("2d");); it shows:
CanvasRenderingContext2D {canvas: canvas#my-chart, globalAlpha: 1, globalCompositeOperation: 'source-over', filter: 'none', imageSmoothingEnabled: true, …}
canvas: canvas#my-chart
direction: "ltr"
fillStyle: "#000000"
filter: "none"
font: "12px \"Helvetica Neue\", Helvetica, Arial, sans-serif"
globalAlpha: 1
globalCompositeOperation: "source-over"
imageSmoothingEnabled: true
imageSmoothingQuality: "low"
lineCap: "butt"
lineDashOffset: 0
lineJoin: "miter"
lineWidth: 1
miterLimit: 10
shadowBlur: 0
shadowColor: "rgba(0, 0, 0, 0)"
shadowOffsetX: 0
shadowOffsetY: 0
strokeStyle: "#000000"
textAlign: "start"
textBaseline: "alphabetic"
[[Prototype]]: CanvasRenderingContext2D
so the log shows that the chart is recognized...

symfny-ux controller creates its own instance of ChartJS inside an appropriate stimulus-controller, and this variable isn't directly accessible. But, symfony/ux developers are smart, and they created events (e.g. chartjs:connect) which you can listen to (link)
If you do so, you will end up with a JS native CustomEvent object and in the details property of this event you will find passed chart instance previously created in symfiny-ux-controller for chart.js
So in theory you would be able just to
document.addEventListener("chartjs:connect",(chartEv) => {
console.log(chartEv.details); // chartEv.details.chart.destroy()
});
I do recommend you to watch Ryan's tutorial on Symfony UX, especially "Extending a UX Controller" chapter where he tries to work with previously created instance of new Chart() like in your case.

You can use the getChart api method chart.js exposes on itself.
So when you know the ID of your canvas you can use this js to get the chart object:
const chart = Chart.getChart('my-chart');

Related

Add custom tooltip for x axis label on hover action

In our Angular application we are using Highcharts. In that we are showing xAxis labeles as below
When the number of items are more and we have long text, we are showing part of the text and want to show tooltip/tilte on hover like below.
I tried something like below:
this.chartOptions.xAxis['labels'].events.mouseover = (e) => {
e.chart.renderer.label("tooltip text", e.x, e.y, 'rectangle').css({
color: '#FFFFFF'
})
.attr({
fill: 'rgba(0, 0, 0, 0.75)',
padding: 8,
r: 4,
})
.add()
.toFront();
}
But, here the problem is the event does not have any renderer in it. So, not able to add the custom label.
I have also tried multiple ways using axisTitle, formatter etc.. (Please check this link for reference)
Please help me solve this problem.
Thanks...
Use a basic function instead of an arrow one and refer to a chart by this keyword:
mouseover: function(e) {
this.chart.renderer.label("tooltip text", e.x, e.y, 'rectangle').css({
color: '#FFFFFF'
})
.attr({
fill: 'rgba(0, 0, 0, 0.75)',
padding: 8,
r: 4,
})
.add()
.toFront();
}
Live demo: http://jsfiddle.net/BlackLabel/dfazcwyr/

Javascript plotly border radius how to

Is there an easy way to create a border radius for a plot in plotly module? I have tried this with no luck...
var trace1 = {
x: time,
y: scaledData,
mode: 'lines',
type: 'scatter'
};
var layout = {
xaxis: {type: 'date'},
yaxis: {title: 'Moisture %'},
width: 320,
height: 320,
margin: {l: 50, r: 30, b: 50, t: 65, pad: 10},
paper_bgcolor: '#79ff4d',
plot_bgcolor: '#c6ffb3',
borderRadius: '15px',
title:'Past 24 Hours'
}
return (
<Plot data={[trace1]}
layout={layout}
/>
);
I also tried the css method but I think I am doing something wrong here as well. I tried creating a div of same size and position and wrapping the plot in it. Then putting a radius on the div but it is behind my plot so it does me no good. Not sure how to do the css hack but I would accept this answer as well, although more work.
It may be possible to get the element by class name if you are displaying this in an HTML page. In my case the class was main-svg. In the javascript on your page use the following:
<script>
var plotDiv = document.getElementsByClassName('main-svg') //class name of plotly main area
plotDiv[0].style.borderRadius = "15px"; //or however round you want
</script>
I just came across this question as I had the same problem. I just wrapped the plotly plot div with a div and applied a css class with border-radius and overflow: hidden as mentioned before. That worked for me.

How to disable Stacking on an individual series using Primefaces jQplot implementation

I am using Primefaces 6 for my companys charting needs, which relies on jQplot.
For a project, I am trying to overlay a line chart on a stacked bar chart with negative values, to obtain something like this:
The problem is that when I try to add a linechartseries to the same model as the two barchartseries , the linechart becomes a part of the stack when setting setStacked(true); on the model, because Primefaces seems to not allow individual disabling of stacking on series, only per model. So I end up with this when rendering the chart with
<p:chart type="bar" model="#{backingBean.cartesianChartModel}"/>
After some investigation I have notoced that jQplot is capable of disabling Stacking on individual series by passing disableStack : true in the JS options, so the question is if it's posssible to override this in some way on the rendered page,either via PF or via some JS hack? I feel that using the extender only apples to the entire model?
Related issues: Disable individual stacking
By pouring through the documentation I found a solution to the problem, if not the question:
It seems that Primefaces allows for individual series to be excempt from the stack in the series creation in this version, by passing
LineChartSeries.setDisableStack(true);
Simple as that.
I guess it may be possible. I used the extender functionality for some jqPlot hacks in the past.
In my case, for example, I had a Donut Chart defined with an extender function as follows:
private void createDonutModel() {
donutModel = new DonutChartModel();
donutModel.setLegendPosition("s");
donutModel.setLegendPlacement(LegendPlacement.OUTSIDE);
donutModel.setSliceMargin(4);
donutModel.setDataFormat("value");
donutModel.setShadow(false);
donutModel.setExtender("donutExtender");
donutModel.setSeriesColors("B81C40, FFA600, 79B54A");
}
The corresponding javascript was doing some changes to the jqPlot:
/**
* Customized jqPlot JQuery layout of the Donut Chart for Status Dashboard.
*/
function donutExtender() {
this.cfg.seriesDefaults = {
// make this a donut chart.
renderer:$.jqplot.DonutRenderer,
rendererOptions:{
thickness: 26,
ringMargin: 0,
fill: true,
padding: 0,
sliceMargin: 4,
// Pies and donuts can start at any arbitrary angle.
startAngle: -90,
showDataLabels: false,
// By default, data labels show the percentage of the donut/pie.
// You can show the data 'value' or data 'label' instead, or 'percent'
dataLabels: 'value',
shadow: false
}
}
this.cfg.gridPadding = {
top: 0, right: 0, bottom: 0, left: 0
}
this.cfg.legend = {
show: false
}
this.cfg.grid = { drawBorder: false,
shadow: false,
background: "transparent"
};
}
So you may try something like this in your case ?
Leave the extension configuration of your series empty, except for the one you are interested in...
function chartExtender() {
this.cfg.series = [
{ //...
},
{ // ...
},
{
disableStack: true
}
]
}
Worth having a shot ...

How to change background colors, marker CSS, and add hover text on marker?

I am trying to create a timeline view using visjs of a upgrade scenario (Pre Upgrade, Pre Release &Post Upgrade) something similar to the image below. Need some pointers to create different region colors as depicted in the image, CSS to change the main marker to an image source and also on hover of the slider (region or markers) it should show some description.
CSS
.vis-item.vis-background.preupgrade {
background-color: rgba(0, 153, 255, 0.2);
}
.vis-item.vis-background.prerelease {
background-color: rgba(102, 204, 255, 0.2);
}
.vis-item.vis-background.postupgrade {
background-color: rgba(204, 204, 255, 0.2);
}
Controller
$scope.visData = new vis.DataSet([
{start: '2015-07-26', end: '2015-08-25', type: 'background', title: 'Pre Upgrade', className: 'preupgrade'},
{start: '2015-08-26', end: '2015-09-30', type: 'background', title: 'Pre Release', className: 'prerelease'},
{start: '2015-10-01', end: '2015-10-31', type: 'background', title: 'Post Upgrade', className: 'postupgrade'}
]);
$scope.visOption = {
editable: false,
autoResize: true,
moveable: true,
margin: {
item: 10,
axis: 20
}
};
Visjs timeline HTML
<vis-timeline data="visData" options="visOption" events="visEvent"></vis-timeline>
I am also providing a plunker link for this problem.
Update Also why my plunker does not show region color changes?
Updated plunker link with some CSS changes, but how to add tooltip on top of background areas and how to add custom markers as shown in image with tooltips?
Update
Now I have achieved most of the things by using both AngularJS and jQuery simultaneously, but need help to convert everything to AngularJS. Still adding a custom time is pending and click event.
Updated Plunker link
Looking at the documentation you can see docs for where they spell out the classes to what you need to update for styling.
http://visjs.org/docs/timeline/#Editing_Items
Also they have events for onmoving and such so you should be able to drag and animate built in but I couldn't find a clear example of it in their docs.

OpenStreetMap add tag on map

I am working on a webapp with openstreetmap and OpenLayers. What I have done is using JavaScript rendering a line on map with some given points, like the screen capture below:
Now what I would like to do is to have a tag displayed above the line, something like below:
I am not sure how I can achieve this through JavaScript, and I couldn't find any useful reference document. Anyone have done this before please share some experience. Thank you!
Try creating opaque (or zero-width) points with styled labels. Here's my proposition based on Labeled Features Example. (I don't have possibility to test it right now, so watch out).
First: Create new vector layer (as styling settings might interfere with your current layer with line) styled with invisible points and some parameters:
var vectorLayer = new OpenLayers.Layer.Vector("Labeled points", {
styleMap: new OpenLayers.StyleMap({'default':{
// should be invisible, if not, set opaque
strokeWidth: 0,
pointRadius: 0,
// label may have \n linebreaks
label : "${label}",
fontColor: "${fontColor}",
fontSize: "12px",
fontFamily: "Courier New, monospace",
fontWeight: "bold",
labelAlign: "${align}",
labelXOffset: "${xOffset}",
labelYOffset: "${yOffset}",
labelOutlineColor: "white",
labelOutlineWidth: 3
}})
});
Second: Here's how you create feature with given parameters (the ${parameter}'s):
var newLabeledPoint = new OpenLayers.Geometry.Point(-101.04, 35.68);
var newLabeledFeature = new OpenLayers.Feature.Vector(newLabeledPoint );
newLabeledFeature .attributes = {
label: "Line 1",
fontColor: 'blue',
align: "cm",
// positive value moves the label to the right
xOffset: 50,
// negative value moves the label down
yOffset: -15
};
and finally: vectorLayer.addFeatures([newLabeledFeature]);.

Categories