Go JS Tree Mapping view in React TS - reactjs

I want to achieve Tree Mapping from Gojs in React typescript.
I found one example of Go js in react but it's still confusing for me to make Tree Mapping in react. Any help would be appreciated to start with Tree Mapping in React TS.
Here is my repo: https://github.com/AdarshPawar29/map-tree-gojs
I manage to create the tree mapping but still some work to be done. I commented on some of the not working functions. I'm also looking for the functional component.
import React, { useState } from "react";
import * as go from "gojs";
import { ReactDiagram } from "gojs-react";
import "./App.css";
class TreeNode extends go.Node {
constructor() {
super();
this.treeExpandedChanged = (node) => {
if (node.containingGroup !== null) {
node.containingGroup
.findExternalLinksConnected()
.each((l) => l.invalidateRoute());
}
};
}
// findVisibleNode() {
// // redirect links to lowest visible "ancestor" in the tree
// var n = this;
// while (n !== null && !n.isVisible()) {
// n = n.findTreeParentNode();
// }
// return n;
// }
}
// end TreeNode
// Control how Mapping links are routed:
// - "Normal": normal routing with fixed fromEndSegmentLength & toEndSegmentLength
// - "ToGroup": so that the link routes stop at the edge of the group,
// rather than going all the way to the connected nodes
// - "ToNode": so that they go all the way to the connected nodes
// but only bend at the edge of the group
var ROUTINGSTYLE = "Normal";
// If you want the regular routing where the Link.[from/to]EndSegmentLength controls
// the length of the horizontal segment adjacent to the port, don't use this class.
// Replace MappingLink with a go.Link in the "Mapping" link template.
class MappingLink extends go.Link {
getLinkPoint(
node: go.Node | null | any,
port: go.GraphObject,
spot: go.Spot,
from: boolean,
ortho: boolean,
othernode: go.Node | null | any,
otherport: go.GraphObject
) {
if (ROUTINGSTYLE !== "ToGroup") {
return super.getLinkPoint(
node,
port,
spot,
from,
ortho,
othernode,
otherport
);
} else {
var r = port.getDocumentBounds();
var group = node.containingGroup;
var b = group !== null ? group.actualBounds : node.actualBounds;
var op = othernode.getDocumentPoint(go.Spot.Center);
var x = op.x > r.centerX ? b.right : b.left;
return new go.Point(x, r.centerY);
}
}
computePoints() {
var result = super.computePoints();
if (result && ROUTINGSTYLE === "ToNode") {
var fn = this.fromNode;
var tn = this.toNode;
if (fn && tn) {
var fg = fn.containingGroup;
var fb = fg ? fg.actualBounds : fn.actualBounds;
var fpt = this.getPoint(0);
var tg = tn.containingGroup;
var tb = tg ? tg.actualBounds : tn.actualBounds;
var tpt = this.getPoint(this.pointsCount - 1);
this.setPoint(
1,
new go.Point(fpt.x < tpt.x ? fb.right : fb.left, fpt.y)
);
this.setPoint(
this.pointsCount - 2,
new go.Point(fpt.x < tpt.x ? tb.left : tb.right, tpt.y)
);
}
}
return result;
}
}
// end MappingLink
// Create some random trees in each group
var nodeDataArray = [
{ isGroup: true, key: -1, text: "Left Side", xy: "0 0", width: 150 },
{ isGroup: true, key: -2, text: "Right Side", xy: "300 0", width: 150 },
];
var linkDataArray = [
{ from: 6, to: 1012, category: "Mapping" },
{ from: 4, to: 1006, category: "Mapping" },
{ from: 9, to: 1004, category: "Mapping" },
{ from: 1, to: 1009, category: "Mapping" },
{ from: 14, to: 1010, category: "Mapping" },
];
export default function App() {
// All links must go from a node inside the "Left Side" Group to a node inside the "Right Side" Group.
function checkLink(
fn: {
[x: string]: any;
containingGroup: { data: { key: number } } | null;
},
fp: any,
tn: {
[x: string]: any;
containingGroup: { data: { key: number } } | null;
},
tp: any,
link: any
) {
// make sure the nodes are inside different Groups
if (fn.containingGroup === null || fn.containingGroup.data.key !== -1)
return false;
if (tn.containingGroup === null || tn.containingGroup.data.key !== -2)
return false;
//// optional limit to a single mapping link per node
if (
fn.linksConnected.any(
(l: { category: string }) => l.category === "Mapping"
)
)
return false;
if (
tn.linksConnected.any(
(l: { category: string }) => l.category === "Mapping"
)
)
return false;
return true;
}
function initDiagram() {
const $ = go.GraphObject.make;
// set your license key here before creating the diagram: go.Diagram.licenseKey = "...";
const diagram = $(go.Diagram, {
"undoManager.isEnabled": true, // must be set to allow for model change listening
"undoManager.maxHistoryLength": 0, // uncomment disable undo/redo functionality
"clickCreatingTool.archetypeNodeData": {
text: "new node",
color: "lightblue",
},
"commandHandler.copiesTree": true,
"commandHandler.deletesTree": true,
// newly drawn links always map a node in one tree to a node in another tree
"linkingTool.archetypeLinkData": { category: "Mapping" },
"linkingTool.linkValidation": checkLink,
"relinkingTool.linkValidation": checkLink,
model: new go.GraphLinksModel({
linkKeyProperty: "key", // IMPORTANT! must be defined for merges and data sync when using GraphLinksModel
}),
});
// // define a simple Node template
// diagram.nodeTemplate = $(
// go.Node,
// "Auto", // the Shape will go around the TextBlock
// new go.Binding("location", "loc", go.Point.parse).makeTwoWay(
// go.Point.stringify
// ),
// $(
// go.Shape,
// "RoundedRectangle",
// { name: "SHAPE", fill: "white", strokeWidth: 0 },
// // Shape.fill is bound to Node.data.color
// new go.Binding("fill", "color")
// ),
// $(
// go.TextBlock,
// { margin: 8, editable: true }, // some room around the text
// new go.Binding("text").makeTwoWay()
// )
// );
diagram.nodeTemplate = $(
TreeNode,
{ movable: false, copyable: false, deletable: false }, // user cannot move an individual node
// no Adornment: instead change panel background color by binding to Node.isSelected
{
selectionAdorned: false,
background: "white",
mouseEnter: (e, node) => (node.background = "aquamarine"),
// mouseLeave: (e, node) =>
// (node.background = node.isSelected ? "skyblue" : "white"),
},
new go.Binding("background", "isSelected", (s) =>
s ? "skyblue" : "white"
).ofObject(),
// whether the user can start drawing a link from or to this node depends on which group it's in
new go.Binding("fromLinkable", "group", (k) => k === -1),
new go.Binding("toLinkable", "group", (k) => k === -2),
$(
"TreeExpanderButton", // support expanding/collapsing subtrees
{
width: 14,
height: 14,
"ButtonIcon.stroke": "white",
"ButtonIcon.strokeWidth": 2,
"ButtonBorder.fill": "goldenrod",
"ButtonBorder.stroke": null,
"ButtonBorder.figure": "Rectangle",
_buttonFillOver: "darkgoldenrod",
_buttonStrokeOver: null,
_buttonFillPressed: null,
}
),
$(
go.Panel,
"Horizontal",
{ position: new go.Point(16, 0) },
//// optional icon for each tree node
//$(go.Picture,
// { width: 14, height: 14,
// margin: new go.Margin(0, 4, 0, 0),
// imageStretch: go.GraphObject.Uniform,
// source: "images/defaultIcon.png" },
// new go.Binding("source", "src")),
$(go.TextBlock, new go.Binding("text", "key", (s) => "item " + s))
) // end Horizontal Panel
); // end Node
// These are the links connecting tree nodes within each group.
diagram.linkTemplate = $(go.Link); // without lines
diagram.linkTemplate = // with lines
$(
go.Link,
{
selectable: false,
routing: go.Link.Orthogonal,
fromEndSegmentLength: 4,
toEndSegmentLength: 4,
fromSpot: new go.Spot(0.001, 1, 7, 0),
toSpot: go.Spot.Left,
},
$(go.Shape, { stroke: "lightgray" })
);
// These are the blue links connecting a tree node on the left side with one on the right side.
diagram.linkTemplateMap.add(
"Mapping",
$(
MappingLink,
{
isTreeLink: false,
isLayoutPositioned: false,
layerName: "Foreground",
},
{ fromSpot: go.Spot.Right, toSpot: go.Spot.Left },
{ relinkableFrom: true, relinkableTo: true },
$(go.Shape, { stroke: "blue", strokeWidth: 2 })
)
);
function updateNodeWidths(
group: {
memberParts: {
each: (arg0: {
(n: any): void;
(n: any): void;
(n: any): void;
}) => void;
};
},
width: number
) {
if (isNaN(width)) {
group.memberParts.each((n: { width: number }) => {
if (n instanceof go.Node) n.width = NaN; // back to natural width
});
} else {
var minx = Infinity; // figure out minimum group width
group.memberParts.each((n: { actualBounds: { x: number } }) => {
if (n instanceof go.Node) {
minx = Math.min(minx, n.actualBounds.x);
}
});
if (minx === Infinity) return;
var right = minx + width;
group.memberParts.each(
(n: { width: number; actualBounds: { x: number } }) => {
if (n instanceof go.Node)
n.width = Math.max(0, right - n.actualBounds.x);
}
);
}
}
function makeGroupLayout() {
return $(
go.TreeLayout, // taken from samples/treeView.html
{
alignment: go.TreeLayout.AlignmentStart,
angle: 0,
compaction: go.TreeLayout.CompactionNone,
layerSpacing: 16,
layerSpacingParentOverlap: 1,
nodeIndentPastParent: 1.0,
nodeSpacing: 0,
setsPortSpot: false,
setsChildPortSpot: false,
// after the tree layout, change the width of each node so that all
// of the nodes have widths such that the collection has a given width
// commitNodes: function () {
// // overriding TreeLayout.commitNodes
// go.TreeLayout.prototype.commitNodes();
// if (ROUTINGSTYLE === "ToGroup") {
// updateNodeWidths(group, group.data.width || 100);
// }
// },
}
);
}
diagram.groupTemplate = $(
go.Group,
"Auto",
{ deletable: false, layout: makeGroupLayout() },
new go.Binding("position", "xy", go.Point.parse).makeTwoWay(
go.Point.stringify
),
new go.Binding("layout", "width", makeGroupLayout),
$(go.Shape, { fill: "white", stroke: "lightgray" }),
$(
go.Panel,
"Vertical",
{ defaultAlignment: go.Spot.Left },
$(
go.TextBlock,
{ font: "bold 14pt sans-serif", margin: new go.Margin(5, 5, 0, 5) },
new go.Binding("text")
),
$(go.Placeholder, { padding: 5 })
)
);
// initialize tree on left side
var root: any = { key: 0, group: -1 };
nodeDataArray.push(root);
for (var i = 0; i < 11; ) {
i = makeTree(3, i, 17, nodeDataArray, linkDataArray, root, -1, root.key);
}
// initialize tree on right side
root = { key: 1000, group: -2 };
nodeDataArray.push(root);
for (var i = 0; i < 15; ) {
i = makeTree(3, i, 15, nodeDataArray, linkDataArray, root, -2, root.key);
}
diagram.model = new go.GraphLinksModel(nodeDataArray, linkDataArray);
// help create a random tree structure
function makeTree(
level: number,
count: number,
max: number,
nodeDataArray:
| {
isGroup: boolean;
key: number;
text: string;
xy: string;
width: number;
}[]
| { key: any; group: any }[],
linkDataArray: { from: any; to: any }[],
parentdata: { key: any; group?: any },
groupkey: number,
rootkey: number
) {
var numchildren = Math.floor(Math.random() * 10);
for (var i = 0; i < numchildren; i++) {
if (count >= max) return count;
count++;
var childdata: any = { key: rootkey + count, group: groupkey };
nodeDataArray.push(childdata);
linkDataArray.push({ from: parentdata.key, to: childdata.key });
if (level > 0 && Math.random() > 0.5) {
count = makeTree(
level - 1,
count,
max,
nodeDataArray,
linkDataArray,
childdata,
groupkey,
rootkey
);
}
}
return count;
}
return diagram;
}
function handleModelChange(changes: any) {
alert("GoJS model changed!");
}
return (
<div>
<ReactDiagram
initDiagram={initDiagram}
divClassName="diagram-component"
nodeDataArray={nodeDataArray}
linkDataArray={linkDataArray}
onModelChange={handleModelChange}
/>
</div>
);
}

Related

Highcharts | Network Graph - Is there a way to expand leaf nodes on click of the Parent node?

Highcharts | Network Graph - Is there a way to expand leaf nodes on click of the Parent node?
Sample Code`Highcharts.addEvent(
Highcharts.Series,
'afterSetOptions',
function (e) {
var colors = Highcharts.getOptions().color
i = 0,
nodes = {};
if (
this instanceof Highcharts.seriesTypes.networkgraph &&
e.options.id === 'lang-tree'
) {
e.options.data.forEach(function (link) {
if (link[0] === 'Parent') {
nodes['Parent'] = {
id: 'Parent',
marker: {
radius: 20
}
};
nodes[link[1]] = {
id: link[1],
marker: {
radius: 10
},
color: colors[i++]
};
} else if (nodes[link[0]] && nodes[link[0]].color) {
nodes[link[1]] = {
id: link[1],
color: nodes[link[0]].color
};
}
});
e.options.nodes = Object.keys(nodes).map(function (id) {
return nodes[id];
});
}
}
);`
Currently, this feature is not available to achieve from the API options without any customization.
Please take a look at this demo where you can find some custom functions to collapse the child nodes on the click event: https://jsfiddle.net/BlackLabel/9mv0ny3j/
point: {
events: {
click: function() {
var point = this;
point.linksFrom.forEach(link => {
if (link.toNode.isHidden) {
link.graphic.show();
link.toNode.graphic.css({
opacity: 1
});
link.toNode.dataLabel.css({
opacity: 1
})
link.toNode.isHidden = false;
} else {
link.graphic.hide();
link.toNode.graphic.css({
opacity: 0
});
link.toNode.dataLabel.css({
opacity: 0
})
link.toNode.isHidden = true;
}
})
}
}
},
API: https://api.highcharts.com/highcharts/series.line.events.click

Dots persist on D3 graph for angularjs

I am using NVD3 for my graphs and I have this issue where the dots that show up on hover will start to persist as you over over the line. Does anyone have any idea on how to make sure these disappear when the move moves away from them?
Here is the component:
;(function() {
angular.module('canopy.common.components.largeStandardChart')
.component('largeStandardChart', {
templateUrl: 'app/common/components/chart-components/large-standard-chart/large-standard-chart.html',
controller: LargeStandardChartController,
controllerAs: 'vm',
bindings: {
kpi: "<",
updateGraph: '=',
frequency: '<'
}
});
LargeStandardChartController.$inject = ['$rootScope', 'BanyanUtilsService', 'ConfigurationService', '$timeout'];
function LargeStandardChartController($rootScope, UtilsService, CS, $timeout) {
var vm = this;
vm.kpiTrend = [];
vm.kpiTargetTrend = [];
vm.kpiProjectedTrend = [];
vm.predictedDate = null;
var allTrends = vm.kpi.trend.length && vm.kpi.trend[0].values.length ? vm.kpi.trend[0].values : [];
vm.chart = {
chartOptions: {
chart: {
type: 'lineChart',
height: 250,
area: CS.getOrgConfig().graph.general.fillArea,
margin : {
top: 15,
right: 40,
bottom: 50,
left: 70
},
x: (function(d) { return d.time }),
y: (function(d) { return d.value }),
clipVoronoi: false,
xAxis: {
showMaxMin: false,
staggerLabels: vm.frequency === 'DAY' ? false : true,
tickFormat: function(d) {
return vm.frequency === 'DAY'
? d3.time.format(CS.getOrgConfig().dateTime.d3DateFormat)(new Date(d))
: d3.time.format(CS.getOrgConfig().dateTime.d3DateTimeFormat)(new Date(d));
}
},
yAxis: {
showMaxMin: true,
tickFormat: function (d) {
return vm.kpi.kpiMeasure === 'NUMBER' && d ? d.toFixed(1) : UtilsService.getFormattedData(d, vm.kpi.kpiMeasure);
}
},
tooltip: {
hideDelay: 0
},
showXAxis: CS.getOrgConfig().graph.xAxis.showXAxis,
showYAxis: CS.getOrgConfig().graph.yAxis.showYAxis,
showLegend: false,
transitionDuration: 350,
useInteractiveGuideline: false
}
}
};
vm.$onInit = function() {
if(vm.updateGraph) { vm.updateGraph.handler = vm.updateGraphData; }
if (!vm.kpi) { vm.kpi = { trend: vm.kpiTrend, kpiMeasure: "PERCENTAGE" } }
setTrends();
d3.select(window).on('mouseout', function () {
d3.selectAll('.nvtooltip').style('opacity', '0');
});
};
function setTrends() {
_.set(vm.chart, 'chartData', []);
vm.kpiTrend = [];
vm.kpiProjectedTrend = [];
_.forEach(allTrends, function(kpi) {
if (_.has(kpi, 'predict')) {
vm.kpiProjectedTrend.push(kpi);
} else {
if (CS.getOrgConfig().graph.general.showNullValues) {
vm.kpiTrend.push(kpi);
} else {
if (kpi.value) { vm.kpiTrend.push(kpi) }
}
}
});
if (!vm.kpi.hideTarget && !vm.kpiProjectedTrend.length) {
vm.chart.chartData.push({
key: CS.getOrgConfig().labels.target.single,
classed: "dashed",
color: $rootScope.branding.canopyBrandColor,
seriesIndex: 2,
strokeWidth: 1,
values: getTargetValues()
});
}
if (vm.kpiTrend.length) {
vm.chart.chartData.push({
key: 'Value',
classed: "solid",
area: CS.getOrgConfig().graph.general.fillArea,
color: $rootScope.branding.canopyBrandColor,
seriesIndex: 0,
strokeWidth: 2,
values: vm.kpiTrend
});
}
if (vm.kpiProjectedTrend.length) {
vm.chart.chartOptions.chart.useInteractiveGuideline = false;
var lastCurrentValue = angular.copy(vm.kpiTrend).pop();
var firstPredictedValue = angular.copy(vm.kpiTrend).pop();
vm.kpiProjectedTrend.unshift(firstPredictedValue);
vm.endDate = moment.unix(allTrends[ allTrends.length - 1 ].time / 1000).format(CS.getOrgConfig().dateTime.dateFormat); // Divide by 1000 for miliseconds coming from server
vm.chart.chartData.push({
key:'Projected',
classed: "dashed",
color: $rootScope.branding.canopyBrandColor,
strokeWidth: 1,
seriesIndex: 3,
values: vm.kpiProjectedTrend
});
var top = 0, bottom = 0;
if (allTrends.length) {
var top = _.maxBy(allTrends, function(tr) { return tr.value }).value;
var bottom = _.minBy(allTrends, function(tr) { return tr.value }).value;
}
var yTop = vm.kpi.kpiMeasure === 'PERCENTAGE' ? 103 : top + ((top - bottom) * 0.07);
var yBottom = vm.kpi.kpiMeasure === 'PERCENTAGE' ? 0 : bottom - ((top - bottom) * 0.04);
vm.chart.chartData.push({
classed: "solid",
strokeWidth: 1,
seriesIndex: 4,
values: [
{time: lastCurrentValue.time, value: yTop},
{time: lastCurrentValue.time, value: yBottom},
],
color: '#ff0005'
});
}
setDomain();
}
function setDomain () {
var top = 0, bottom = 0;
if (allTrends.length) {
top = _.maxBy(allTrends, function(tr) { return tr.value }).value;
bottom = _.minBy(allTrends, function(tr) { return tr.value }).value;
}
bottom = bottom < 1 && bottom > 0 ? 0 : bottom;
if (top === bottom) { bottom = top - bottom; }
if (top + bottom === 0) { top = 1; }
var yTop = vm.kpi.kpiMeasure === 'PERCENTAGE' ? 103 : top + ((top - bottom) * 0.05);
var yBottom = vm.kpi.kpiMeasure === 'PERCENTAGE' ? 0 : bottom - ((top - bottom) * 0.05);
vm.chart.chartOptions.chart.yDomain = [yBottom, yTop];
}
vm.updateGraphData = function(trend) {
allTrends = trend.length && trend[0].values.length ? trend[0].values : [];
setTrends();
vm.api.updateWithOptions(vm.chart.chartOptions);
vm.api.updateWithData(trend);
vm.api.refresh();
};
function getTargetValues() {
var trend = angular.copy(allTrends);
_.forEach(trend, function(t) {
t.value = vm.kpi.targetValue;
});
return trend;
}
}
})();
and here is what it looks like when I hover:
For anyone having this issue I have finally found the solution. I had to add a listener on the mouseout event and remove the hover class that is added to the .nv-point which is the dot. It looks like this:
d3.select(window).on('mouseout', function () {
d3.selectAll('.nv-point').classed('hover', false);
});

Dynamically change zoom

I need to change zoom of Google Maps. Code:
function _initMap(vm) {
vm.windowOptions = {
show: false
};
var latSum = 0;
var longSum = 0;
for (var i = 0, length = vm.markers.length; i < length; i++) {
//calculate center of map (1st part)
latSum += vm.markers[i].coords.latitude;
longSum += vm.markers[i].coords.longitude;
//assign an icon
vm.markers[i].iconUrl = getIconUrl(vm.markers[i].deviceType);
}
var centeredLatitude = latSum / vm.markers.length;
var centeredLongitude = longSum / vm.markers.length;
vm.control = {};
vm.map = {
center: setCenterMap(),
options: getMapOptions(),
zoom: setMapZoom(),
events: {
click: function (mapModel, eventName, originalEventArgs) {
var e = originalEventArgs[0];
$log.log('gz', e.latLng.lat() + ' ' + e.latLng.lng());
console.log('xxx', mapModel);
}
},
show: true,
refresh: function (a, b, c, d) {
vm.map.control.refresh();
}
};
vm.clusterOptions = {
minimumClusterSize: 2,
zoomOnClick: true,
styles: [{
url: 'assets/images/markers/m1.png',
width: 53,
height: 53,
textColor: 'white',
textSize: 17,
fontFamily: 'Open Sans'
}],
averageCenter: true,
clusterClass: 'cluster-icon'
};
vm.window = {
location: undefined,
templateUrl: 'app/components/maps/maps.info.template.html',
show: false,
options: getMapWindowOptions()
};
vm.clickMarker = function (marker, event, object) {
vm.window.show = false;
vm.window.details = object.details;
vm.window.location = object.coords;
vm.window.show = true;
vm.sendChoosenDeviceToController(object);
angular.element('#right-menu').focus();
};
vm.closeClick = function () {
vm.window.show = false;
}
}
but the code:
center: setCenterMap()
zoom: setMapZoom()
when I call the methods center and zoom does not change center and zoom. How to update center and zoom dynamically ? The methods are properly exectued during initiation of map but after initialization does not want to change.
The solution was just simply:
scope.map.center = {
'latitude': scope.markers[i].coords.latitude,
'longitude': scope.markers[i].coords.longitude
};
GoogleMaps knows about that change and works nice.

how can i draw dynamic highchart. the y-axis and the number of charts are dynamic from json

im new in angular js and i need to use highchart in my angular page . the problem is that i must draw chart with dynamic data from json and the number of charts will be dynamic too , maybe it should draw 3 or 4 different chart from one json . I searched alot but couldnt solve my problem.
this code works but show the data in one chart in different series. I need to show each series in different charts, and in this case the json send 4 data but it will be changed .
1. List item
$scope.draw_chart = function(){
Highcharts.chart('container2', {
chart:{
type: 'spline',
animation: Highcharts.svg, // don't animate in old IE
marginRight: 10,
events: {
load: function () {
var this_chart = this;
$scope.ws = ngSocket('ws://#');
$scope.ws.onOpen(function () {
});
var k = 0 ;
var time=0;
$scope.points_avarage = [];
$scope.ws.onMessage(function (message) {
listener(JSON.parse(message.data));
var z = JSON.parse(message.data);
var line_to_draw = z.result.length;
var j = 0 ;
for(i=0 ; i < line_to_draw*2 ; i+=2)
{
$scope.data_to_draw[i] = {
name : z.result[j][0]['name'] ,
y : z.result[j][0]['rx-bits-per-second']
}
$scope.data_to_draw[i+1] = {
name : z.result[j][0]['name'] ,
y : z.result[j][0]['tx-bits-per-second']
}
j++;
}
this_chart.series[0].name= $scope.data_to_draw[0].name;
this_chart.series[1].name= $scope.data_to_draw[1].name;
this_chart.series[2].name= $scope.data_to_draw[2].name;
this_chart.series[3].name= $scope.data_to_draw[3].name;
for(i=0; i < line_to_draw*2; i++) {
var x = (new Date()).getTime(); // current time
var y = parseInt($scope.data_to_draw[i].y);
this_chart.series[i].addPoint([x, y], true, true);
}
});
var d = new Date().toTimeString();
}
}
},
global: {
useUTC: false
},
title: {
text: 'Live data'
},
xAxis: {
type: 'datetime'//,
},
yAxis: {
title: {
text: 'Value'
},
plotLines: [{
width: 1,
color: '#808080'
}
]
}
plotOptions: {
series: {
marker: {
enabled: false
}
}
},
series: [{
data: (function () {
var data = [],
time = (new Date()).getTime(),
i;
for (i = -5; i <= 0; i += 1) {
data.push({
x: time ,
y: 0
});
}
return data;
}())
},
{
data: (function () {
var data = [],
time = (new Date()).getTime(),
i;
for (i = -5; i <= 0; i += 1) {
data.push({
x: time ,
y: 0
});
}
return data;
}())
},
{
data: (function () {
var data = [],
time = (new Date()).getTime(),
i;
for (i = -5; i <= 0; i += 1) {
data.push({
x: time ,
y: 0
});
}
return data;
}())
},
{
data: (function () {
var data = [],
time = (new Date()).getTime(),
i;
for (i = -5; i <= 0; i += 1) {
data.push({
x: time ,
y: 0
});
}
return data;
}())
}
]
});
};
<div id="containet" ng-init="draw_chart()"></div>

ExtJS5: Custom component(ticker) increasing CPU cycles 10 times

I am using a ticker component in my application. When the text is rolling, the CPU cycles hit 10+. As soon as I hover cursor over it, the scrolling stops and the CPU cycles comes down to 0
Can someone tell if this is normal? If not, how can I make this component use less CPU cycles?
Here is the code for ticker:
Ext.define('MyApp.ux.Ticker', {
extend: 'Ext.Component',
xtype: 'ticker',
baseCls: 'x-ticker',
autoEl: {
tag: 'div',
cls: 'x-ticker-wrap',
children: {
tag: 'div',
cls: 'x-ticker-body'
}
},
body: null,
constructor: function (config) {
Ext.applyIf(config, {
direction: 'left',
speed: 10,
pauseOnHover: true
});
if (config.speed < 1) config.speed = 1;
else if (config.speed > 20) config.speed = 20;
Ext.applyIf(config, {
refreshInterval: parseInt(10 / config.speed * 15)
});
config.unitIncrement = 1;
this.callParent([config]);
},
afterRender: function () {
this.body = this.el.first('.x-ticker-body');
this.body.addCls(this.direction);
this.taskCfg = {
interval: this.refreshInterval,
scope: this
};
var posInfo, body = this.body;
switch (this.direction) {
case "left":
case "right":
posInfo = { left: body.getWidth() };
this.taskCfg.run = this.scroll.horz;
break;
case "up":
case "down":
posInfo = { top: body.getHeight() };
this.taskCfg.run = this.scroll.vert;
break;
}
posInfo.position = 'relative';
body.setPositioning(posInfo);
DHT.ux.Ticker.superclass.afterRender.call(this);
if (this.pauseOnHover) {
this.el.on('mouseover', this.onMouseOver, this);
this.el.on('mouseout', this.onMouseOut, this);
this.el.on('click', this.onMouseClick, this);
}
this.task = Ext.apply({}, this.taskCfg);
Ext.util.TaskManager.start(this.task);
},
add: function (o) {
var dom = Ext.DomHelper.createDom(o);
this.body.appendChild(Ext.fly(dom).addCls('x-ticker-item').addCls(this.direction));
},
onDestroy: function () {
if (this.task) {
Ext.util.TaskManager.stop(this.task);
}
DHT.ux.Ticker.superclass.onDestroy.call(this);
},
onMouseOver: function () {
if (this.task) {
Ext.util.TaskManager.stop(this.task);
delete this.task;
}
},
onMouseClick: function (e, t, o) {
var item = Ext.fly(t).up('.x-ticker-item');
if (item) {
this.fireEvent('itemclick', item, e, t, o);
}
},
onMouseOut: function () {
if (!this.task) {
this.task = Ext.apply({}, this.taskCfg);
Ext.util.TaskManager.start(this.task);
}
},
scroll: {
horz: function () {
var body = this.body;
var bodyLeft = body.getLeft(true);
if (this.direction == 'left') {
var bodyWidth = body.getWidth();
if (bodyLeft <= -bodyWidth) {
bodyLeft = this.el.getWidth(true);
} else {
bodyLeft -= this.unitIncrement;
}
} else {
var elWidth = this.el.getWidth(true);
if (bodyLeft >= elWidth) {
bodyLeft = -body.getWidth(true);
} else {
bodyLeft += this.unitIncrement;
}
}
body.setLeft(bodyLeft);
},
vert: function () {
var body = this.body;
var bodyTop = body.getTop(true);
if (this.direction == 'up') {
var bodyHeight = body.getHeight(true);
if (bodyTop <= -bodyHeight) {
bodyTop = this.el.getHeight(true);
} else {
bodyTop -= this.unitIncrement;
}
} else {
var elHeight = this.el.getHeight(true);
if (bodyTop >= elHeight) {
bodyTop = -body.getHeight(true);
} else {
bodyTop += this.unitIncrement;
}
}
body.setTop(bodyTop);
}
}
});
And this is how I am using it:
{
xtype: 'panel',
border: false,
height: 40,
width: 256,
layout: {
type: 'hbox',
align: 'stretch'
},
items: [{
width: 200,
direction: 'left',
xtype: 'ticker',
itemId: 'rollerPanel'
}],
listeners: {
afterrender: function (panel) {
var ticker = panel.down('ticker');
ticker.add({
tag: 'div',
cls: 'title',
html: "Ticker content."
});
}
}
}
What's wrong with the above code? What may be the reason for higher CPU usage?
The Chrome developer tools will help you profile this but it wouldn't hurt to cache some of the things like the width/height of the body and elements so that you're only reading it when you start up and not on every tick.

Resources