I am using a chart to visualize data in a TimeboxScopedApp, and I want to update the data when scope changes. The more brute-force approach of using remove() then redrawing the chart as described here leaves me with an overlaid "Loading..." mask, but otherwise works. The natural approach of using the Highchart native redraw() method would be my preference, only I don't know how to access the actual Highchart object and not the App SDK wrapper.
Here's the relevant part of the code:
var chart = Ext.getCmp('componentQualityChart');
if (chart) {
var chartCfg = chart.getChartConfig();
chartCfg.xAxis.categories = components;
chart.setChartConfig(chartCfg);
chart.setChartData(data);
chart.redraw(); // this doesn't work with the wrapper object
} else { // draw chart for the first time
How do I go about redrawing the chart with the new data?
Assuming chart (componentQualityChart) is an instance of Rally.ui.chart.Chart, you can access the HighCharts instance like this:
var highcharts = chart.down('highchart').chart;
// Now you have access to the normal highcharts interface, so
// you could change the xAxis
highcharts.xAxis[0].setCategories([...], true);
// Or you could change the series data
highcharts.series[0].data.push({ ... }); //Add a new data point
// Or pretty much anything else highcharts lets you do
Using _unmask() removes the overlaid "Loading.." mask
if (this.down('#myChart')) {
this.remove('myChart');
}
this.add(
{
xtype: 'rallychart',
height: 400,
itemId: 'myChart',
chartConfig: {
//....
},
chartData: {
categories: scheduleStateGroups,
series: [
{
//...
}
]
}
}
);
this.down('#myChart')._unmask();
Related
I've build a simple Here Map using Vue 2 and the JS API in version 3.1.30.17. The map works fine in all browsers except Firefox v102.
This is the error message in Firefox:
Tangram [error]: Error for style group 'non-collision' for tile 20/7/68/41/7 CanvasRenderingContext2D.drawImage: Passed-in canvas is empty: loadTexture#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:431:417267
e/sn.addWorker/<#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:431:63015
EventListener.handleEvent*e/sn.addWorker#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:431:62515
e/value/<#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:431:515089
value#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:431:515502
value#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:431:514847
e/value/this.initializing<#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:431:511497
promise callback*value#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:431:511472
Ul#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:335:441
p.eh#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:378:446
p.Ge#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:329:436
p.Ge#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:376:356
S#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:369:214
T.prototype.u#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:410:166
T#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:401:290
... The error is even bigger
The following method I'm using to init Here Maps inside Vue's mounted:
async initializeHereMap() {
const mapContainer = this.$refs.hereMap;
const H = window.H;
// Initialize the platform object:
this.platform = new H.service.Platform({
apikey: this.apiKey,
});
await this.geocode(this.platform, this.originAddress)
.then(data => this.routingParameters.origin = data[0]);
await this.geocode(this.platform, this.destinationAddress)
.then(data => this.routingParameters.destination = data[0]);
// Obtain the default map types from the platform object
const defaultLayers = this.platform.createDefaultLayers({
lg: window.navigator.language,
});
// Instantiate (and display) a map object:
const map = new H.Map(mapContainer, defaultLayers.vector.normal.map, {
zoom: this.zoom,
center: this.center,
padding: {
top: this.padding,
bottom: this.padding,
left: this.padding,
right: this.padding,
},
});
// create map pins
const mapPinOrigin = this.addMapPin('A', 40);
const mapPinDestination = this.addMapPin('B', 40);
let linestring = new H.geo.LineString();
linestring.pushPoint(this.routingParameters.origin);
linestring.pushPoint(this.routingParameters.destination);
// Create a polyline to display the route:
let routeLine = new H.map.Polyline(linestring, {
linestring,
style: { strokeColor: '#3F80C4', lineWidth: 5 },
});
// Create a marker for the start point:
let startMarker = new H.map.Marker(this.routingParameters.origin, { icon: mapPinOrigin });
// Create a marker for the end point:
let endMarker = new H.map.Marker(this.routingParameters.destination, { icon: mapPinDestination });
// Add the route polyline and the two markers to the map:
map.addObjects([routeLine, startMarker, endMarker]);
// Set the map's viewport to make the whole route visible:
map.getViewModel().setLookAtData({bounds: routeLine.getBoundingBox()});
// add behavior control
if (this.behaviors) new H.mapevents.Behavior(new H.mapevents.MapEvents(map));
// add UI
if (this.controls) H.ui.UI.createDefault(map, defaultLayers);
},
Is there some one facing the same issue and could solved it?
Did you follow this example on: https://developer.here.com/tutorials/how-to-implement-a-web-map-using-vuejs/ ?
Tangram error is related to rendering e.g. when render map objects (like icons, markers, polylines etc.) and map vector tiles.
I don't think so that this issue related to HERE JS Map API.
Because all examples on https://developer.here.com/documentation/examples/maps-js are working well on my FireFox 102.0.1
It could be some map objects like icons or markers etc. are created in some moment but is not finished yet and then try to push onto map? Creating an icon in some asynchron function?
Or in like your code:
await this.geocode(this.platform, this.originAddress)
.then(data => this.routingParameters.origin = data[0]);
You don't know when func geocode will be finished (e.g. due slow internet connectivity)
It could be this command above is not done yet, but your code is already start to run this code:
linestring.pushPoint(this.routingParameters.origin);<-- 'this.routingParameters.origin' could be null
linestring.pushPoint(this.routingParameters.destination);
// Create a polyline to display the route:
let routeLine = new H.map.Polyline(linestring, { <-- Could cause Tangram error because 'linestring' is strange due undefined origin yet!
linestring,
style: { strokeColor: '#3F80C4', lineWidth: 5 },
});
The polyline options is not correct in:
new H.map.Polyline(linestring, {
linestring,
style: { strokeColor: '#3F80C4', lineWidth: 5 },
}
Why in above the 'linestring' is second time in options?
Please follow correct syntax on:
https://developer.here.com/documentation/maps/3.1.31.0/api_reference/H.map.Polyline.html#.Options
I'm super new to Vue and I'm trying to get into components.
Basically, I have the main script file with my new vue app (with a countdown function based on setInterval and in the same file a vue component( it's a stamina bar made with canvas) with width increasing and decreasing methods. Basically, I would like to decrease the bar width every second but I don't get how to call the methods declared in the component. I guess that when they are declared inside the component I could access them from everywhere, but I didn't find a proper solution ( I tried with $refs but it's not working)
Is there any way where I can call the addWidth() and subWidth() function from a method in my new Vue app?
thank you
this is the component
Vue.component('stamina', {
template: '<div><canvas ref="stamina" style="height:25px;width:300px;" /></div>',
data(){
return {
stamina_width:300,
// vueCanvas: null
}
},
methods: {
drawStamina(){
// clear canvas
this.vueCanvas.clearRect(0, 0, 300, 50);
// draw rect
this.vueCanvas.rect(20,20, this.stamina_width, 100);
//colorize with gradient
var grd = this.vueCanvas.createLinearGradient(0, 0, 300, 0);
grd.addColorStop(0, "red");
grd.addColorStop(0.5, "orange");
grd.addColorStop(1, "green");
this.vueCanvas.fillStyle = grd;
//fill the rect with gradient
this.vueCanvas.fillRect(0, 10,this.stamina_width, 10);
},
addWidth() {
this.stamina_width += 20
this.drawStamina()
},
subWidth() {
this.stamina_width -= 20
this.drawStamina()
}
},
mounted () {
var ctx = this.$refs.stamina.getContext('2d');
this.vueCanvas = ctx;
var stam = this.stamina_width;
var grd = this.vueCanvas.createLinearGradient(0, 0, 300, 0);
grd.addColorStop(0, "red");
grd.addColorStop(0.5, "orange");
grd.addColorStop(1, "green");
this.vueCanvas.fillStyle = grd;
//fill the rect with gradient
this.vueCanvas.fillRect(0,25,stam,25);
}
});
and this is the main vue
var match = new Vue({
el:'#app',
methods:{
//call the methods from component stamina
}
yes you can call methods up/down of parent/child components. You may need to look at creating custom events and listen for them.
Another option I believe might be less complex is to consider using Vuex.
All of your addWidth and subWidth logic will reside in a centralized place this way. All of your components--no matter how nested can "subscribe" to these things (and modify them if needed).
Check out actions. You'll dispatch an action addWidth which sends it to Vuex. In your component that is responsible for rendering the stamina bar I would use a computed property to watch for updates. Something like this:
computed: {
barWidth() {
return this.$store.getters["bar/width"]; // 20
}
}
That is just a really rough example and will not likely be what you're looking for.
VueSchool has some nice (free) courses to help get you rolling with Vuex as well.
I am using vuejs as my frontend framework and esri-loader to load arcgis js 4.11 in vue.I am beginner in arcgis js api and trying to use SketchViewModel to draw a polygon. However, when I use create() function, I am getting sketchVM.create is not a function as error.
I followed arcgis js 4.11 SketchViewModel's documentation
I have divided the code for arcgis js in two methods:- one method is responsible for loading map and view, and another is used to draw polygon.
views/mapView.vue
<script>
...
draw(){
loadModules(
[
"esri/layers/GraphicsLayer",
"esri/widgets/Sketch/SketchViewModel",
"esri/geometry/geometryEngine"
],
{
url: "https://js.arcgis.com/4.11/" // use a specific version
}
).then(
([
SketchViewModel,
geometryEngine,
GraphicsLayer
]) => {
console.log("Area section active")
this.view.surface.style.cursor = "crosshair"; // change cursor style to crosshair
this.graphicsLayer = new GraphicsLayer();
// needed to sketch polygon
var sketchVM = new SketchViewModel({
layer: this.graphicsLayer, // graphics layer over which polygon will be added
view: this.view, // view where polygon will be rendered
updateOnGraphicClick: true, // to allow graphic updation on through click event
defaultUpdateOptions:{
tool:'reshape', // this will set reshape as default tool for update event
},
polygonSymbol: { // style and type for polygon symbol
type: "simple-fill",
color: "rgba(138,43,226, 0.8)",
style: "solid",
outline: {
color: "white",
width: 1
}
}
});
sketchVM.on("create", (event)=>{
if(event.state === "complete"){
console.log(geometryEngine.planarArea(this.graphicsLayer.graphics.items[0].geometry, "square-meters"))
}
});
sketchVM.on("update", (event)=>{
// if() // event to remove graphic on pressing delete key
console.log("Updated value state : ",event.state)
});
console.log("drawing mode on")
sketchVM.create("polygon", {mode:"click"}); // getting error at this line
console.log("draw view returned")
return this.view;
}
);
},
...
</script>
I am having issues with my solid gauge component using the highcharts-vue wrapper.
Basically every time it receives new data it re-draws the animation from 0. Please see sandbox link below for example: https://codesandbox.io/s/n0no0jky1l
The desired behavour im trying to achieve is shown here: https://www.highcharts.com/demo/gauge-solid
Where the gauge animates from old to new value smoothly.
From what i can tell it is not recommended to access the charts methods manually (for example to call the points.update method). (source: https://github.com/highcharts/highcharts-vue#chart-object-reference)
Any ideas?
It occurs because of mutating data in Highcharts. Please use Point.update, instead of updating whole series, to make animation work. You can access whole Chart object by reference in your component, specifically this.children[0].chart. Here is the code:
watch: {
title(newValue) {
this.chartOptions.title.text = newValue;
},
points(newValue, oldValue) {
console.log("watch firing", newValue, oldValue);
this.$children[0].chart.series[0].data[0].update(oldValue += 1);
},
units(newValue) {
this.chartOptions.series[0].dataLabels.format =
'<div style="text-align:center"><span style="font-size:2rem;color: black">{y}</span><div>' +
newValue +
"</div><div/>";
},
min(newValue) {
this.chartOptions.yAxis.min = newValue;
},
max(newValue) {
this.chartOptions.yAxis.max = newValue;
}
},
Don't worry about your data, Highcharts mutate it, so your points prop should be updated every time.
Live example: https://codesandbox.io/s/ojkzvo05z
Kind regards!
I am trying to add click events on the graphs that I am rendering. From chart.click to chart.on('click', function (e){ }).
What I am trying to do is allow the user to select points on the graph and for me to now what selections the user made. Is that at all possible using chartist.js?
I read through the documentation: CHARTIST.JS
My code:
if (item.GraphType.Description == "Line") {
var chart = new Chartist.Line(
container[0],
{
labels: d.Labels,
series: d.SeriesData
},
{
axisY: {
offset: 60
}
}
);
chart.click(function (e) {
console.log(e);
});
}
It is entirely possible, yes. Chartist renders SVG nodes to the page, so using a library like jQuery you can easily find all nodes that you want and attach events to them. You can be as specific or broad in the nodes you're looking for to only attach events to very specific nodes or elements on the chart.
For completeness sake, here is a short example of how to attach events that log the value of a data point when clicked upon to the console using jQuery:
$('.ct-chart-line .ct-point').click(function () {
var val = $(this).attr("ct:value");
console.log(val);
});
You should, however, make sure that the events attach only when the chart is created or drawn if you want to ensure the data points are on the page, which can be triggered by the "created" or "draw" events:
var chart = new Chartist.Line(...);
// attach an event handler to the "created" event of the chart:
chart.on("created", function () {
// attach the necessary events to the nodes:
$('.ct-chart-line .ct-point').click(function () {
var val = $(this).attr("ct:value");
console.log(val);
});
});