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>
);
}
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);
});
I am trying to save Fabric.js canvas and reload it using loadFromJson. But I am getting error patternSourceCanvas is not defined. I thought I should make it global so I removed var.
How to set the global variable in Fabric JS and use var patternSourceCanvas?
When I use the code below, then everything is working fine and the JSON is loaded easily.
var t = https://image.freepik.com/free-photo/roof-texture_21206171.jpg
fabric.util.loadImage(t, function(t) {
var svg_width = i.width;
console.log('svg widh' + i.width + 'svg height' + i.height);
console.log('img width t'+ t.width + ' img height' + t.height);
if(svg_width >= 300){
if (i.isSameColor && i.isSameColor() || !i.paths) {
i.setPatternFill({
source: t, repeat: 'repeat', offsetX:200 , offsetY : -110 // working
}), e.fabric.renderAll();
console.log('in if image 300 up ', t);
} else if (i.paths){
for (var r = 0; r < i.paths.length; r++)
i.paths[r].setPatternFill({
source: t, repeat: 'repeat' , offsetX: -100 , offsetY:-110
}), e.fabric.renderAll();
console.log('in image elseeee 300 up ', t);
}
}
})
But when I fill some other new shape with the new patternSourceCanvas variable then it's not working. Kindly help me with dynamic patterns.
var t = https://image.freepik.com/free-photo/roof-texture_21206171.jpg
fabric.Image.fromURL(t, function (img) {
img.scaleToHeight(200);
var patternSourceCanvas = new fabric.StaticCanvas();
patternSourceCanvas.add(img);
patternSourceCanvas.renderAll();
var pattern = new fabric.Pattern({
source: function() {
patternSourceCanvas.setDimensions({
width: img.getScaledWidth() ,
height: img.getScaledHeight()
});
patternSourceCanvas.renderAll();
return patternSourceCanvas.getElement();
},
repeat: r
});
console.log('pattern', pattern);
//p.set('fill', pattern);
canvas.renderAll();
if (i.isSameColor && i.isSameColor() || !i.paths) {
i.setPatternFill(pattern);
} else if(i.paths) {
for (var r = 0; r < i.paths.length; r++) {
i.paths[r].setPatternFill(pattern);
}
}
e.fabric.renderAll();
});
You need to put patternSourceCanvas to global scope/ scope where loadFromJSON can access patternSourceCanvas. Else you can use cors enabled image directly.
DEMO
var imageUrl = 'https://upload.wikimedia.org/wikipedia/commons/2/22/Wikimapia_logotype.svg';
var canvas = new fabric.Canvas('canvas');
var rect = new fabric.Rect({
width: 200,
height: 200,
strokeWidth: 2,
stroke: '#000'
})
canvas.add(rect);
fabric.Image.fromURL(imageUrl, function(img) {
img.scaleToHeight(200);
var patternSourceCanvas = new fabric.StaticCanvas();
patternSourceCanvas.add(img);
patternSourceCanvas.setDimensions({
width: img.getScaledWidth(),
height: img.getScaledHeight()
});
patternSourceCanvas.renderAll();
var pattern = new fabric.Pattern({
source: patternSourceCanvas.getElement()
},
function(patternObj) {
rect.fill = patternObj;
rect.dirty = true;
canvas.renderAll();
});
}, {
crossOrigin: 'annonymous'
});
function loadfromjson() {
var json = canvas.toJSON();
canvas.clear();
setTimeout(function() {
canvas.loadFromJSON(json, canvas.renderAll.bind(canvas));
}, 1000)
}
canvas{
border:2px solid #000;
}
<canvas id="canvas" width="300" height="300"></canvas><br>
<button onclick="loadfromjson()">loadfromjson </button>
<script src='https://rawgit.com/kangax/fabric.js/master/dist/fabric.js'></script>
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>
I'm trying to create a dynamic chart from userTemplate object.
I'm using this directive angular-flot and I want create the dataset and options of directive dynamically.
Its work but I have this error
Error: [$rootScope:infdig] http://errors.angularjs.org/1.2.21/$rootScope/infdig?p0=10&p1=%5B%5B%22fn%3…ection%5C%22%3A%7B%5C%22color%5C%22%3A%5C%22%2354728c%5C%22%7D%7D%22%5D%5D
at Error (native)
at http://mwm3-gui/asset/script/vendor/angular2.1/angular.min.js:6:450
at k.$get.k.$digest (http://mwm3-gui/asset/script/vendor/angular2.1/angular.min.js:110:66)
at k.$get.k.$apply (http://mwm3-gui/asset/script/vendor/angular2.1/angular.min.js:112:173)
at http://mwm3-gui/asset/script/vendor/angular2.1/angular.min.js:122:253
at e (http://mwm3-gui/asset/script/vendor/angular2.1/angular.min.js:37:440)
at http://mwm3-gui/asset/script/vendor/angular2.1/angular.min.js:41:120
HTML
<div ng-repeat="panel in row.panels" class="{{panel.columnClass}}" resizable id="{{panel.id}}" r-directions="['right']">
<flot dataset="getDataForChart(panel)" options="getOptionForChart(panel)" height="{{panel.graph.height}}"></flot>
</div>
CONTROLLER
$scope.userTemplate = [
{
blockId: 'blockUno',
title: 'Block title',
rows: [
{
rowId: 'rowUno',
title: 'Row Title 1',
panels: [
{
id: 'palel-report-1',
title: 'uno',
columnClass: 'col-md-4',
graph: {
height: 250,
type: "BAR",
countBy: "status"
}
},
{
id: 'palel-report-2',
title: 'due',
columnClass: 'col-md-4',
graph: {
height: 250,
type: "PIE",
countBy: "status"
}
},
{
id: 'palel-report-3',
title: 'tre',
columnClass: 'col-md-4',
graph: {
height: 250,
type: "BAR",
countBy: "status"
}
}
]
}
],
tables: []
}
];
$scope.getDataForChart = function(panel) {
var graphData = [];
var countBy = panel.graph.countBy;
var arr = $scope.reportingData;
for (var i = 0; i < arr.length; i++) {
var valueOfkey = arr[i][countBy];
graphData.push(valueOfkey);
}
var a = [], b = [], prev;
graphData.sort();
for (var i = 0; i < graphData.length; i++) {
if (graphData[i] !== prev) {
a.push(graphData[i]);
b.push(1);
} else {
b[b.length - 1]++;
}
prev = graphData[i];
}
var graphData = [];
for (var i = 0; i < a.length; i++) {
var singleO = {label: '' + a[i], data: [[i, b[i]]]};
graphData.push(singleO);
}
return graphData;
};
$scope.getOptionForChart = function(panel) {
var options = angular.copy($scope.defaultPlotOptions);
var typeGraph = panel.graph.type;
switch (typeGraph) {
case "BAR":
options.series.bars.show = true;
break;
case "LINE":
options.series.lines.show = true;
break;
case "PIE":
options.series.pie.show = true;
break;
case "POINT":
options.series.points.show = true;
break;
case "TABLE":
break;
}
return options;
};
The error you get is from an infinite digest loop.
In a couple of places you are calling functions that return new items each time. Here's an example from the docs linked from the error message you received that suggests this may cause this error:
One common mistake is binding to a function which generates a new
array every time it is called. For example:
<div ng-repeat="user in getUsers()">{{ user.name }}</div>
$scope.getUsers = function() { return [ { name: 'Hank' }, { name: 'Francisco' } ]; };
Since getUsers() returns a new array, Angular
determines that the model is different on each $digest cycle,
resulting in the error. The solution is to return the same array
object if the elements have not changed:
var users = [ { name: 'Hank' }, { name: 'Francisco' } ];
$scope.getUsers = function() { return users; };
In your code, you are doing the same binding to getDataForChart and getOptionForChart.