Node click event not firing for D3 Force Directed Graph - onclick

I'm trying to make nodes collapsed on click of node itself. The graph at present is force directed graph with draggable nodes.
Problem I'm facing is, after attaching the node click event I cannot get the click to fire instead node is displaced from it's position (like dragged on mouse click).
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height");
var color = d3.scaleOrdinal(d3.schemeCategory20);
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function(d) { return d.id; }))
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(width / 2, height / 2));
var graph = { "links" : [ { "relation" : "Relation 0",
"source" : 0,
"target" : 1
},
{ "relation" : "Relation 1",
"source" : 1,
"target" : 3
},
{ "relation" : "Relation 3",
"source" : 1,
"target" : 4
},
{ "relation" : "Relation 4",
"source" : 1,
"target" : 5
},
{ "relation" : "Relation 5",
"source" : 0,
"target" : 2
},
{ "relation" : "Relation 6",
"source" : 2,
"target" : 6
}
],
"nodes" : [ { "collapsed" : false,
"collapsing" : 0,
"id" : 0,
"name" : "Node 0"
},
{ "collapsed" : false,
"collapsing" : 0,
"id" : 1,
"name" : "Node 1"
},
{ "collapsed" : false,
"collapsing" : 0,
"id" : 2,
"name" : "Node 2"
},
{ "collapsed" : false,
"collapsing" : 0,
"id" : 3,
"name" : "Node 3"
},
{ "collapsed" : false,
"collapsing" : 0,
"id" : 4,
"name" : "Node 4"
},
{ "collapsed" : false,
"collapsing" : 0,
"id" : 5,
"name" : "Node 5"
},
{ "collapsed" : false,
"collapsing" : 0,
"id" : 6,
"name" : "Node 6"
}
]
};
var edges = [];
graph.links.forEach(function(e) {
var sourceNode = graph.nodes.filter(function(n) {
return n.id === e.source;
})[0],
targetNode = graph.nodes.filter(function(n) {
return n.id === e.target;
})[0];
edges.push({
source: sourceNode,
target: targetNode,
relation: e.relation
});
});
update();
function update() {
var link = svg.append("g")
.attr("class", "links")
.selectAll("line")
.data(graph.links)
.enter().append("line")
.attr("stroke-width", function(d) { return Math.sqrt(d.value); });
var node = svg.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(graph.nodes)
.enter().append("circle")
.attr("r", 8)
.attr("fill", function(d) { return color(d.group); })
.on("click", togglenode)
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
node.append("title")
.text(function(d) { return d.id; });
simulation
.nodes(graph.nodes)
.on("tick", ticked);
simulation.force("link")
.links(graph.links);
function ticked() {
link
.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
node
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
}
}
function dragstarted(d) {
console.log('drag started');
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(d) {
console.log('dragged');
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function dragended(d) {
console.log('drag ended');
if (!d3.event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
function togglenode(d) {
console.log('clicked node : '+d.id);
if (!d3.event.defaultPrevented) {
var inc = d.collapsed ? -1 : 1;
recurse(d);
function recurse(sourceNode){
//check if link is from this node, and if so, collapse
edges.forEach(function(l) {
if (l.source.id === sourceNode.id){
l.target.collapsing += inc;
recurse(l.target);
}
});
}
d.collapsed = !d.collapsed;
update();
}
}
.links line {
stroke: #999;
stroke-opacity: 0.6;
}
.nodes circle {
stroke: #fff;
stroke-width: 4.5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.3/d3.js"></script>
<svg width="800" height="500"></svg>

Related

Background-color applying for individual images instead of container

I have 2 images in container & i want to apply background-color for whole container as below image :
But instead of container, background-color is applying for individual images as in below code snippet....
It Looks simple to solve, it may be simple, but I am just css beginner & really tried lot before posting question....
var mask1;
let jsonData = {
"path" : " newyear collage\/",
"info" : {
"author" : "",
"keywords" : "",
"file" : "newyear collage",
"date" : "sRGB",
"title" : "",
"description" : "Normal",
"generator" : "Export Kit v1.2.8"
},
"name" : "newyear collage",
"layers" : [
{
"x" : 0,
"height" : 612,
"layers" : [
{
"x" : 0,
"color" : "0xFFFFFF",
"height" : 612,
"y" : 0,
"width" : 612,
"shapeType" : "rectangle",
"type" : "shape",
"name" : "bg_rectangle"
},
{
"x" : 160,
"height" : 296,
"layers" : [
{
"x" : 0,
"height" : 296,
"src" : "vw6ZYre.png",
"y" : 0,
"width" : 429,
"type" : "image",
"name" : "mask_image_1"
},
{
"radius" : "26 \/ 27",
"color" : "0xACACAC",
"x" : 188,
"y" : 122,
"height" : 53,
"width" : 53,
"shapeType" : "ellipse",
"type" : "shape",
"name" : "useradd_ellipse1"
}
],
"y" : 291,
"width" : 429,
"type" : "group",
"name" : "user_image_1"
},
{
"x" : 25,
"height" : 324,
"layers" : [
{
"x" : 0,
"height" : 324,
"src" : "kbXMnVP.png",
"y" : 0,
"width" : 471,
"type" : "image",
"name" : "mask_image_2"
},
{
"radius" : "26 \/ 27",
"color" : "0xACACAC",
"x" : 209,
"y" : 136,
"height" : 53,
"width" : 53,
"shapeType" : "ellipse",
"type" : "shape",
"name" : "useradd_ellipse_2"
}
],
"y" : 22,
"width" : 471,
"type" : "group",
"name" : "user_image_2"
}
],
"y" : 0,
"width" : 612,
"type" : "group",
"name" : "newyearcollage08"
}
]
};
$(document).ready(function()
{
var maskedImageUrla = "";
var coordinates = {
x: 0,
y: 0
};
var width = 0;
var height = 0;
function json(data)
{
var dataObj = {};
let layer1 = data.layers;
let layer2 = layer1[0].layers;
for (i = 1; i < layer2.length; i++)
{
var x = layer2[i].x;
var y = layer2[i].y;
var src = layer2[i].layers[0].src;
$(".container").css('width', width + "px").css('height', height + "px").addClass('temp');
var mask1 = $(".container").mask({
maskImageUrl: 'https://i.imgur.com/' + src,
onMaskImageCreate: function(img) {
img.css({
"position": "fixed",
"left": x + "px",
"top": y + "px"
});
}
});
fileupa1.onchange = function() {
mask1.loadImage(URL.createObjectURL(fileupa1.files[0]));
};
}
}
json(jsonData);
}); // end of document ready
// jq plugin for mask
(function($) {
var JQmasks = [];
$.fn.mask = function(options) {
// This is the easiest way to have default options.
var settings = $.extend({
// These are the defaults.
maskImageUrl: undefined,
imageUrl: undefined,
scale: 1,
id: new Date().getUTCMilliseconds().toString(),
x: 0, // image start position
y: 0, // image start position
onMaskImageCreate: function(div) {},
}, options);
var container = $(this);
let prevX = 0,
prevY = 0,
draggable = false,
img,
canvas,
context,
image,
timeout,
initImage = false,
startX = settings.x,
startY = settings.y,
div;
container.mousePosition = function(event) {
return {
x: event.pageX || event.offsetX,
y: event.pageY || event.offsetY
};
}
container.selected = function(ev) {
var pos = container.mousePosition(ev);
var item = $(".masked-img canvas").filter(function() {
var offset = $(this).offset()
var x = pos.x - offset.left;
var y = pos.y - offset.top;
var d = this.getContext('2d').getImageData(x, y, 1, 1).data;
return d[0] > 0
});
JQmasks.forEach(function(el) {
var id = item.length > 0 ? $(item).attr("id") : "";
if (el.id == id)
el.item.enable();
else el.item.disable();
});
};
container.enable = function() {
draggable = true;
$(canvas).attr("active", "true");
div.css({
"z-index": 2
});
}
container.disable = function() {
draggable = false;
$(canvas).attr("active", "false");
div.css({
"z-index": 1
});
}
container.onDragStart = function(evt) {
container.selected(evt);
prevX = evt.clientX;
prevY = evt.clientY;
};
container.getImagePosition = function() {
return {
x: settings.x,
y: settings.y,
scale: settings.scale
};
};
container.onDragOver = function(evt) {
if (draggable && $(canvas).attr("active") === "true") {
var x = settings.x + evt.clientX - prevX;
var y = settings.y + evt.clientY - prevY;
if (x == settings.x && y == settings.y)
return; // position has not changed
settings.x += evt.clientX - prevX;
settings.y += evt.clientY - prevY;
prevX = evt.clientX;
prevY = evt.clientY;
container.updateStyle();
}
};
container.updateStyle = function() {
clearTimeout(timeout);
timeout = setTimeout(function() {
context.clearRect(0, 0, canvas.width, canvas.height);
context.beginPath();
context.globalCompositeOperation = "source-over";
image = new Image();
image.setAttribute('crossOrigin', 'anonymous');
image.src = settings.maskImageUrl;
image.onload = function() {
canvas.width = image.width;
canvas.height = image.height;
context.drawImage(image, 0, 0, image.width, image.height);
div.css({
"width": image.width,
"height": image.height
});
};
img = new Image();
img.src = settings.imageUrl;
img.setAttribute('crossOrigin', 'anonymous');
img.onload = function() {
settings.x = settings.x == 0 && initImage ? (canvas.width - (img.width * settings.scale)) / 2 : settings.x;
settings.y = settings.y == 0 && initImage ? (canvas.height - (img.height * settings.scale)) / 2 : settings.y;
context.globalCompositeOperation = 'source-atop';
context.drawImage(img, settings.x, settings.y, img.width * settings.scale, img.height * settings.scale);
initImage = false;
};
}, 0);
};
// change the draggable image
container.loadImage = function(imageUrl) {
if (img)
img.remove();
// reset the code.
settings.y = startY;
settings.x = startX;
prevX = prevY = 0;
settings.imageUrl = imageUrl;
initImage = true;
container.updateStyle();
};
// change the masked Image
container.loadMaskImage = function(imageUrl, from) {
if (div)
div.remove();
canvas = document.createElement("canvas");
context = canvas.getContext('2d');
canvas.setAttribute("draggable", "true");
canvas.setAttribute("id", settings.id);
settings.maskImageUrl = imageUrl;
div = $("<div/>", {
"class": "masked-img"
}).append(canvas);
div.find("canvas").on('touchstart mousedown', function(event) {
if (event.handled === false) return;
event.handled = true;
container.onDragStart(event);
});
div.find("canvas").on('touchend mouseup', function(event) {
if (event.handled === false) return;
event.handled = true;
container.selected(event);
});
div.find("canvas").bind("dragover", container.onDragOver);
container.append(div);
if (settings.onMaskImageCreate)
settings.onMaskImageCreate(div);
container.loadImage(settings.imageUrl);
};
container.loadMaskImage(settings.maskImageUrl);
JQmasks.push({
item: container,
id: settings.id
})
return container;
};
}(jQuery));
.temp
{
border: 1px solid #DDDDDD;
display: flex;
background :gold;
}
.container
{
border: 1px slolid #DDDDDD;
display: flex;
background :silver !important;
width: 612px;
height: 612px;
}
.container canvas {
display: block;
background :black;
}
.masked-img {
overflow: hidden;
margin-top: 50px;
position: relative;
}
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
image 1
<input id="fileupa1" type="file" >
<div class="container">
</div>
Codepen : https://codepen.io/kidsdial/pen/aMvyYg
I see you solved the problem, but also asked for an answer, so I will just post the relevant part:
The point is that if the HTML code has inline style (with a style attribute, and this is whar jQuery's css() does) it will take precedence over styles applied in a CSS <style> tag or file. You can prevent this behaviour by adding !important to your CSS rule so it takes precedence (but it is usually not recommended). Remember that inline style will still be the one applied if both have the !important:
.test {
background-color: blue;
}
.test2 {
background-color: green !important;
}
<div class="test" style="background-color: red";>this div has background-color inline style</div>
<div class="test">this div has no background-color inline style</div>
<div class="test2" style="background-color: yellow !important;">this div has background-color inline style with !important</div>
<div class="test2" style="background-color: yellow;">this div has background-color inline style without !important</div>

How to make hover effect for two bar in highcharts at the same time is there any way by using css or any inbuilt method to achieve this?

I'm trying to create a hover effect for two bar at the same time, is there any possibility to achieve this by using any existing method or external css to achieve this kind of hover effect, on hover event present in highcharts I can only change the colour of the single bar image.
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/highstock/6.0.3/highstock.src.js"></script>
<script src="http://code.highcharts.com/modules/xrange.js"></script>
<div id="container" style="width: 100%; height: 100px"></div>
Highcharts
Highcharts.setOptions({
time: {
useUTC: false
}
});
Highcharts.chart('container',{
chart:{
type : 'xrange',
backgroundColor : '0C0D19',
renderTo:'container',
marginRight: 100,
},
colors : ['#45AD59','#6699FF'],
title : { text : '' },
credits : { enabled : false },
legend : { enabled : false },
exporting : {
buttons : {
contextButton : {
enabled : false
}
}
},
plotOptions : {
series : {
cursor : 'pointer',
}
},
tooltip : { enabled: false },
xAxis : {
type : 'datetime',
opposite : true,
startOnTick: true,
endOnTick: true,
showLastLabel: true,
tickLength: 0,
tickInterval:3600*1000,
gridLineColor:'#2c2d39',
gridLineWidth:1,
min : 1545281770000,
minPadding: 0,
dateTimeLabelFormats : {
millisecond: '%I:%M %P',
second: '%I:%M %P',
minute: '%I:%M %P',
hour: '%I:%M %P',
day: '%I:%M %P',
week: '%I:%M %P',
month: '%I:%M %P',
year: '%I:%M %P'
},
crosshair : {
snap : false,
zIndex : 100,
label: {
enabled: true,
format: '{value:%I:%M %P}'
}
},
labels : {
align : 'left',
style : {
color : 'rgba(255, 255, 255, 0.7)',
fontSize : '12px'
}
},
},
yAxis: {
title: {
text: ''
},
plotBands: [{
from: -0.21001,
to: 0.3291,
color: '#00401f'
},{
from:0.5570,
to:1.275,
color:'#2f4776'
}],
categories: ['Reported','Tracked'],
reversed: true,
labels:{
align:'center',
style:{
color:'rgba(255, 255, 255, 0.7)',
fontSize:'12px'
},
formatter: function() {
return this.value + '<img></img>';
},
useHTML: true
},
lineColor: '#2c2d39',
lineWidth: 1
},
series: [{
pointWidth: 20,
borderWidth:0,
borderRadius:0,
data : [{
"x": 1545281770000,
"x2": 1545284950000,
"y": 1,
"floor": 3,
"room": "3001",
"value": true,
"hoverId": 0
}, {
"x": 1545285388000,
"x2": 1545291448000,
"y": 1,
"floor": 3,
"room": "3001",
"value": true,
"hoverId": 1,
}, {
"x": 1545303407000,
"x2": 1545312167000,
"y": 1,
"floor": 2,
"room": "2001",
"value": true,
"hoverId": 2,
}, {
"x": 1545312218000,
"x2": 1545312338000,
"y": 1,
"floor": 3,
"room": "3000",
"value": true,
"hoverId": 3,
}, {
"x": 1545314138000,
"x2": 1545314738000,
"y": 1,
"floor": 2,
"room": "2001",
"value": true,
"hoverId": 4,
}
,{
x:1545281701745,
x2:1545285267354,
y:0,
},
{
x:1545285327157,
x2:1545292261051,
y:0,
},{
x:1545303345999,
x2:1545314757609,
y:0,
className:'manual',
}
],
dataLabels: {
enabled: false
}
}]
})
CSS
#container .highcharts-grid.highcharts-yaxis-grid path{
display: none;
}
#container .highcharts-axis.highcharts-xaxis path{
display: none;
}
#container .highcharts-point.highcharts-point.highcharts-color-0 rect{
height: 15px;
y: 8;
}
#container .highcharts-point.highcharts-point.highcharts-color-1 rect{
y: 27;
height: 18px;
}
Here is a JSFiddle
You can make it using Highcharts.SVGRenderer which allows you to plot a rectangle and Highcharts.SVGElement.on method which allows you to add events on SVG elements (for example series group). Check demo and code posted below.
Code:
chart: {
type: 'xrange',
backgroundColor: '0C0D19',
renderTo: 'container',
marginRight: 100,
events: {
load: function() {
var chart = this,
series = chart.series[0],
seriesSvg = series.group,
seriesSvgBBox = seriesSvg.getBBox(),
width = 80,
height = seriesSvgBBox.height,
y = chart.plotTop + seriesSvgBBox.y,
x,
tooltip;
seriesSvg.on('mousemove', function(e) {
if (tooltip) {
tooltip.destroy();
}
x = e.offsetX - width / 2
tooltip = chart.renderer
.rect(x, y, width, height)
.attr({
fill: 'rgba(255, 255, 255, 0.2)'
})
.css({
'pointer-events': 'none'
})
.add()
.toFront();
});
seriesSvg.on('mouseout', function(e) {
tooltip.destroy();
tooltip = null;
});
}
}
}
Demo:
http://jsfiddle.net/BlackLabel/z2h59pLf/2/
API reference:
https://api.highcharts.com/class-reference/Highcharts.SVGRenderer#rect
https://api.highcharts.com/class-reference/Highcharts.SVGElement#on

Transform JSON structure in cosmos db

I have the following data structure that I'm looking to transform. The structure exist as follows:
{
"id": "13fd6574-dc33-4b8c-a09b-a937869d184f",
"practiceId": 2,
"extrasCoverServices": [
{
"serviceTypeName": "OCCUPATIONAL THERAPY",
"serviceTypeCode": "H",
"providers": [
{
"providerNumber": "157833AC",
"providerName": "DR TEST"
}
],
"serviceItems": [
{
"itemName": "INITIAL CONS",
"itemNumber": "100",
"fee": 0,
"isReferenceItem": "true",
"customisations": [
{
"practiceDisplayName": "First Assessment",
"fee": 50,
"isPracticeReferenceItem": "true"
}
]
},
{
"itemName": "CONS TREAT",
"itemNumber": "200",
"fee": 0,
"isReferenceItem": "true",
"customisations": [
{
"practiceDisplayName": "Consult One",
"fee": 23.35,
"isPracticeReferenceItem": "true"
},
{
"practiceDisplayName": "Consult Two",
"fee": 15,
"isPracticeReferenceItem": "false"
}
]
}
]
}
]
}
I'm wanting a query that returns the id, practiceId and extrasCoverservices (serviceTypeName, serviceTypeCode and the serviceItems). I don't want to include the provider information.
I've tried this, but I need to specify the position of the element in the array which I don't want to do. Any help would be much appreciated.
SELECT a.id
, a.practiceId
, [{"serviceTypeName": a.extrasCoverServices[0].serviceTypeName, "serviceTypeCode": a.extrasCoverServices[0].serviceTypeCode, "serviceItems": a.extrasCoverServices[0].serviceItems}]
Update
function sample(documentId) {
var collection = getContext().getCollection();
var isAccepted = collection.queryDocuments(
collection.getSelfLink(),
'SELECT ARRAY_CONCAT([{"itemId": s.itemId, "itemName": s.itemName,"itemNumber":s.itemNumber,"fee":s.fee,"isReferenceItem":s.isReferenceItem}], IS_DEFINED(s.customisations) ? s.customisations : []) as extrasCoverServices FROM a JOIN e in a.extrasCoverServices JOIN s in e.serviceItems WHERE a.id =' + "'" + documentId + "'",
function (err, feed, options) {
if (err) throw err;
if (!feed || !feed.length) getContext().getResponse().setBody('no docs found');
else {
console.log(feed.length);
var result = feed.flatten(function(x) {
return x.extrasCoverServices;
});
getContext().getResponse().setBody(result);
}
});
if (!isAccepted) throw new Error('The query was not accepted by the server.');
}
You almost had it. To achieve this, you can use features:
inner-document joining using join keyword
explicit JSON composition using { and } wrappers
The first gives you access to the subItem you want to cherry-pick and the second enables you to glue them back together they way you like it.
The query you are looking for should be along the lines of this:
SELECT
a.id,
a.practiceId,
[{
"serviceTypeName": e.serviceTypeName,
"serviceTypeCode" : e.serviceTypeCode,
"serviceItems": e.serviceItems
}] as extrasCoverServices
FROM a
join e in a.extrasCoverServices
Note that you can combine Sql-like select with explicit JSON building in the same query to keep the query more compact. Also, I suggest you use CosmosDB SQL query cheat sheet to easily discover, what's in the toolbox.
function sample(documentId, itemId) {
var collection = getContext().getCollection();
var query = 'SELECT e.serviceTypeCode, '+
' e.serviceTypeName, '+
' s.itemNumber, '+
' ARRAY_CONCAT( '+
' [{ '+
' "itemId": s.itemId, '+
' "itemName": s.itemName, '+
' "fee":s.fee, '+
' "isReferenceItem":s.isReferenceItem '+
' }], '+
' IS_DEFINED(s.customisations) ? s.customisations : []) as extrasCoverServices '+
' FROM a '+
' JOIN e in a.extrasCoverServices '+
' JOIN s in e.serviceItems '+
' WHERE a.id = ' + "'" + documentId + "'";
var isAccepted = collection.queryDocuments(
collection.getSelfLink(),
query,
function (err, feed, options) {
if (err) throw err;
if (!feed || !feed.length) getContext().getResponse().setBody('no docs found');
var returnResult = [];
for(var i = 0; i<feed.length; i++) {
let serviceItem = feed[i];
let serviceItemsArray = feed[i].extrasCoverServices;
for(var j = 0; j < serviceItemsArray.length; j++) {
let item = serviceItemsArray[j];
let mapped = {
serviceTypeCode: serviceItem.serviceTypeCode
, serviceTypeName: serviceItem.serviceTypeName
, itemId: item.itemId
, itemName: (item.itemName ? item.itemName : item.practiceDisplayName)
, itemNumber: serviceItem.itemNumber
, fee: item.fee
, isReferenceItem: ((item.isReferenceItem && item.isReferenceItem == true) ? item.isReferenceItem: false)
, isPracticeReferenceItem: (item.isPracticeReferenceItem && item.isPracticeReferenceItem == true ? item.isPracticeReferenceItem : false)
};
returnResult.push(mapped);
}
}
if(itemId != undefined) {
var filteredReturnResult = returnResult.filter(r => r.itemId == itemId);
getContext().getResponse().setBody(filteredReturnResult);
return
}
getContext().getResponse().setBody(returnResult);
if (!isAccepted) throw new Error('The query was not accepted by the server.');
})
}
Please use sql like:
SELECT a.id,a.practiceId,e.serviceTypeName,e.serviceTypeCode,e.serviceItems
FROM a
join e in a.extrasCoverServices a
Result:
If you want to make the e.serviceTypeName,e.serviceTypeCode,e.serviceItems into an array, not parallel with id and praticeId, I suggest you using stored procedure in cosmos db.
function sample() {
var collection = getContext().getCollection();
var isAccepted = collection.queryDocuments(
collection.getSelfLink(),
'SELECT c.id,c.practiceId,c.extrasCoverServices FROM root c',
function (err, feed, options) {
if (err) throw err;
if (!feed || !feed.length) getContext().getResponse().setBody('no docs found');
else {
var returnResult = [];
for(var i = 0;i<feed.length;i++){
var obj1 = {
id:"",
practiceId:"",
serviceArray :[]
};
obj1.id = feed[i].id;
obj1.practiceId = feed[i].practiceId;
var loopArray = feed[i].extrasCoverServices;
var serviceResult = [];
for(var j = 0;j<loopArray.length;j++){
var obj2 = {
serviceTypeName:"",
serviceTypeCode:"",
serviceItems:[] };
obj2.serviceTypeName=loopArray[j].serviceTypeName;
obj2.serviceTypeCode=loopArray[j].serviceTypeCode;
obj2.serviceItems=loopArray[j].serviceItems;
serviceResult.push(obj2);
}
obj1.serviceArray= serviceResult;
returnResult.push(obj1);
}
getContext().getResponse().setBody(returnResult);
}
});
if (!isAccepted) throw new Error('The query was not accepted by the server.');
}
Result:
Hope it helps you.
Update Answer 1:
For your further requirement in your comment, I test a sql for you.
SELECT
a.id,
a.practiceId,
[{
"serviceTypeName": e.serviceTypeName,
"serviceTypeCode" : e.serviceTypeCode,
"serviceItems": [
{"itemName": s.itemName,
"itemNumber":s.itemNumber,
"fee":s.fee,
"isReferenceItem":s.isReferenceItem
},
{"practiceDisplayName":c.practiceDisplayName,
"itemNumber":s.itemNumber,
"fee": c.fee,
"isPracticeReferenceItem":c.isPracticeReferenceItem
}
]
}] as extrasCoverServices
FROM a
join e in a.extrasCoverServices
join s in e.serviceItems
join c in s.customisations
However , the results have multiple items because of the join.
[
{
"id": "13fd6574-dc33-4b8c-a09b-a937869d184f",
"practiceId": 2,
"extrasCoverServices": [
{
"serviceTypeName": "OCCUPATIONAL THERAPY",
"serviceTypeCode": "H",
"serviceItems": [
{
"itemName": "INITIAL CONS",
"itemNumber": "100",
"fee": 0,
"isReferenceItem": "true"
},
{
"practiceDisplayName": "First Assessment",
"itemNumber": "100",
"fee": 50,
"isPracticeReferenceItem": "true"
}
]
}
]
},
{
"id": "13fd6574-dc33-4b8c-a09b-a937869d184f",
"practiceId": 2,
"extrasCoverServices": [
{
"serviceTypeName": "OCCUPATIONAL THERAPY",
"serviceTypeCode": "H",
"serviceItems": [
{
"itemName": "CONS TREAT",
"itemNumber": "200",
"fee": 0,
"isReferenceItem": "true"
},
{
"practiceDisplayName": "Consult One",
"itemNumber": "200",
"fee": 23.35,
"isPracticeReferenceItem": "true"
}
]
}
]
},
{
"id": "13fd6574-dc33-4b8c-a09b-a937869d184f",
"practiceId": 2,
"extrasCoverServices": [
{
"serviceTypeName": "OCCUPATIONAL THERAPY",
"serviceTypeCode": "H",
"serviceItems": [
{
"itemName": "CONS TREAT",
"itemNumber": "200",
"fee": 0,
"isReferenceItem": "true"
},
{
"practiceDisplayName": "Consult Two",
"itemNumber": "200",
"fee": 15,
"isPracticeReferenceItem": "false"
}
]
}
]
}
]
So, I suggest you processing the results in the stored procedure to match your requirement.
function sample() {
var collection = getContext().getCollection();
var isAccepted = collection.queryDocuments(
collection.getSelfLink(),
'SELECT a.id, a.practiceId,'+
'[{'+
'"serviceTypeName": e.serviceTypeName, '+
'"serviceTypeCode" : e.serviceTypeCode, '+
'"serviceItems": ['+
'{"itemName": s.itemName,'+
'"itemNumber":s.itemNumber,'+
'"fee":s.fee,'+
'"isReferenceItem":s.isReferenceItem'+
'},'+
'{"practiceDisplayName":c.practiceDisplayName,'+
'"itemNumber":s.itemNumber,'+
'"fee": c.fee,'+
'"isPracticeReferenceItem":c.isPracticeReferenceItem '+
'}'+
']'+
'}] as extrasCoverServices'+
' FROM a '+
' join e in a.extrasCoverServices'+
' join s in e.serviceItems'+
' join c in s.customisations',
function (err, feed, options) {
if (err) throw err;
if (!feed || !feed.length) getContext().getResponse().setBody('no docs found');
else {
var returnResult = [];
var obj1 = {
id:"",
practiceId:"",
extrasCoverServices :[]
};
var temp = "";
for(var i = 0;i<feed.length;i++){
if(temp==feed[i].id){
var extrasArray = obj1.extrasCoverServices[0].serviceItems;
var serviceArray = feed[i].extrasCoverServices[0].serviceItems;
for(var j = 0;j<serviceArray.length;j++){
extrasArray.push(serviceArray[j]);
}
obj1.extrasCoverServices[0].serviceItems = extrasArray;
} else{
obj1.id = feed[i].id;
obj1.practiceId = feed[i].practiceId;
obj1.extrasCoverServices = feed[i].extrasCoverServices;
temp = feed[i].id;
}
}
returnResult.push(obj1);
getContext().getResponse().setBody(returnResult);
}
});
if (!isAccepted) throw new Error('The query was not accepted by the server.');
}
Process Result:
[
{
"id": "13fd6574-dc33-4b8c-a09b-a937869d184f",
"practiceId": 2,
"extrasCoverServices": [
{
"serviceTypeName": "OCCUPATIONAL THERAPY",
"serviceTypeCode": "H",
"serviceItems": [
{
"itemName": "INITIAL CONS",
"itemNumber": "100",
"fee": 0,
"isReferenceItem": "true"
},
{
"practiceDisplayName": "First Assessment",
"itemNumber": "100",
"fee": 50,
"isPracticeReferenceItem": "true"
},
{
"itemName": "CONS TREAT",
"itemNumber": "200",
"fee": 0,
"isReferenceItem": "true"
},
{
"practiceDisplayName": "Consult One",
"itemNumber": "200",
"fee": 23.35,
"isPracticeReferenceItem": "true"
},
{
"itemName": "CONS TREAT",
"itemNumber": "200",
"fee": 0,
"isReferenceItem": "true"
},
{
"practiceDisplayName": "Consult Two",
"itemNumber": "200",
"fee": 15,
"isPracticeReferenceItem": "false"
}
]
}
]
}
]
Update Answer 2:
Well,I still focus on implementing your needs through the Stored Procedure.
I add one item without customisations array into serviceItems as below:
[
{
"id": "13fd6574-dc33-4b8c-a09b-a937869d184f",
"practiceId": 2,
"extrasCoverServices": [
{
"serviceTypeName": "OCCUPATIONAL THERAPY",
"serviceTypeCode": "H",
"serviceItems": [
{
"itemName": "INITIAL CONS",
"itemNumber": "100",
"fee": 0,
"isReferenceItem": "true",
"customisations": [
{
"practiceDisplayName": "First Assessment",
"fee": 50,
"isPracticeReferenceItem": "true"
}
]
},
{
"itemName": "CONS TREAT",
"itemNumber": "200",
"fee": 0,
"isReferenceItem": "true",
"customisations": [
{
"practiceDisplayName": "Consult One",
"fee": 23.35,
"isPracticeReferenceItem": "true"
},
{
"practiceDisplayName": "Consult Two",
"fee": 15,
"isPracticeReferenceItem": "false"
}
]
},
{
"itemName": "FOR TEST",
"itemNumber": "333",
"fee": 20,
"isReferenceItem": "true"
}
]
}
]
}
]
SP CODE:
function sample() {
var collection = getContext().getCollection();
var isAccepted = collection.queryDocuments(
collection.getSelfLink(),
'SELECT a.id, a.practiceId,'+
'[{'+
'"serviceTypeName": e.serviceTypeName, '+
'"serviceTypeCode" : e.serviceTypeCode, '+
'"serviceItems": e.serviceItems'+
'}] as extrasCoverServices'+
' FROM a '+
' join e in a.extrasCoverServices',
function (err, feed, options) {
if (err) throw err;
if (!feed || !feed.length) getContext().getResponse().setBody('no docs found');
else {
for(var i = 0;i<feed.length;i++){
var extraArray = feed[i].extrasCoverServices;
for(var j = 0;j<extraArray.length;j++){
var serviceArray = extraArray[j].serviceItems;
var array = [];
for(var k = 0;k<serviceArray.length;k++){
var o1 = {
"itemName": "",
"itemNumber":"",
"fee" : "",
"isReferenceItem":""
};
console.log(k+"----");
o1.itemName = serviceArray[k].itemName;
o1.itemNumber = serviceArray[k].itemNumber;
o1.fee = serviceArray[k].fee;
o1.isReferenceItem = serviceArray[k].isReferenceItem;
console.log(o1.itemName);
array.push(o1);
if(null != serviceArray[k].customisations){
var customisationsArray = serviceArray[k].customisations;
for(var p = 0;p<customisationsArray.length;p++){
var o2 = {
"practiceDisplayName": "",
"itemNumber":"",
"fee" : "",
"isPracticeReferenceItem":""
};
o2.practiceDisplayName = customisationsArray[p].practiceDisplayName;
o2.itemNumber = o1.itemNumber;
o2.fee = customisationsArray[p].fee;
o2.isPracticeReferenceItem = customisationsArray[p].isPracticeReferenceItem;
array.push(o2);
}
}
}
feed[i].extrasCoverServices[j].serviceItems = array;
}
}
getContext().getResponse().setBody(feed);
}
});
if (!isAccepted) throw new Error('The query was not accepted by the server.');
}
Just for summary, I tidied up your last SP code. This is a good thread.
function sample(documentId, itemId) {
var collection = getContext().getCollection();
var query = 'SELECT e.serviceTypeCode, '+
' e.serviceTypeName, '+
' s.itemNumber, '+
' ARRAY_CONCAT( '+
' [{ '+
' "itemId": s.itemId, '+
' "itemName": s.itemName, '+
' "fee":s.fee, '+
' "isReferenceItem":s.isReferenceItem '+
' }], '+
' IS_DEFINED(s.customisations) ? s.customisations : []) as extrasCoverServices '+
' FROM a '+
' JOIN e in a.extrasCoverServices '+
' JOIN s in e.serviceItems '+
' WHERE a.id = ' + "'" + documentId + "'";
var isAccepted = collection.queryDocuments(
collection.getSelfLink(),
query,
function (err, feed, options) {
if (err) throw err;
if (!feed || !feed.length) getContext().getResponse().setBody('no docs found');
var returnResult = [];
for(var i = 0; i<feed.length; i++) {
let serviceItem = feed[i];
let serviceItemsArray = feed[i].extrasCoverServices;
for(var j = 0; j < serviceItemsArray.length; j++) {
let item = serviceItemsArray[j];
let mapped = {
serviceTypeCode: serviceItem.serviceTypeCode
, serviceTypeName: serviceItem.serviceTypeName
, itemId: item.itemId
, itemName: (item.itemName ? item.itemName : item.practiceDisplayName)
, itemNumber: serviceItem.itemNumber
, fee: item.fee
, isReferenceItem: ((item.isReferenceItem && item.isReferenceItem == true) ? item.isReferenceItem: false)
, isPracticeReferenceItem: (item.isPracticeReferenceItem && item.isPracticeReferenceItem == true ? item.isPracticeReferenceItem : false)
};
returnResult.push(mapped);
}
}
if(itemId != undefined) {
var filteredReturnResult = returnResult.filter(r => r.itemId == itemId);
getContext().getResponse().setBody(filteredReturnResult);
return
}
getContext().getResponse().setBody(returnResult);
if (!isAccepted) throw new Error('The query was not accepted by the server.');
})
}

How to stack Charts with amchart?

is it possible to stack 2 or more graphs in one chart? with the same Scrollbar / Chartcursor?
I tried it with the live editor, but havn't found any option to make this possible.
Here som pictures for explaination:
At the moment i have this graph: http://imgur.com/XpU42xK
But i want a graph like this: http://imgur.com/xdwJ7lu
Thanks for your help :)
Just for the sake of sport I tried to implement it. Good news - it's possible :)
First of all you will need to prepare both charts
First chart
Scrollbar enabled
Chart cursor enabled
Category axis hidden
Legend disabled
Bottom margin: 0
Second chart
Scrollbar disabled
Chart cursor enabled
Category axis enabled
Legend enabled
Top margin: 0
This creates two charts, "glued" together like in your mockup:
Syncing the charts
They still act on their own, like two separate charts. We have to sync them up:
Cursor
Legend
Zoom/pan
That's where this code comes in:
/**
* Use events to sync up cursors and zooms
*/
for ( var x = 0; x < AmCharts.charts.length; x++ ) {
// use "changed" event to track cursor movement on all charts
// place the cursor on other charts on the same index
AmCharts.charts[ x ].addListener( "changed", function( event ) {
// find which category is currently being rolled over
var category = event.chart.dataProvider[ event.index ][ event.chart.categoryField ];
// cycle through all available charts and place the cursor at
// the same category
for ( var i = 0; i < AmCharts.charts.length; i++ ) {
if ( event.chart !== AmCharts.charts[ i ] ) {
AmCharts.charts[ i ].chartCursor.showCursorAt( category );
}
}
} );
// use "zoomed" event to track zooms/pans so we can apply
// the same zoom across other charts
AmCharts.charts[ x ].addListener( "zoomed", function( zoomEvent ) {
// cycle through all available charts and apply same zoom
for ( var i = 0; i < AmCharts.charts.length; i++ ) {
if ( zoomEvent.chart !== AmCharts.charts[ i ] && ( AmCharts.charts[ i ].startIndex != zoomEvent.startIndex || AmCharts.charts[ i ].endIndex != zoomEvent.endIndex ) ) {
AmCharts.charts[ i ].zoomToIndexes( zoomEvent.startIndex, zoomEvent.endIndex );
}
}
} );
}
/**
* Use the last chart to display legend
* We will collect graphs from other charts and mirror them on
* the last chart.
*/
var lastChart = AmCharts.charts[ AmCharts.charts.length - 1 ];
for ( var x = 0; x < ( AmCharts.charts.length - 1 ); x++ ) {
// add graphs
for ( var g = 0; g < AmCharts.charts[ x ].graphs.length; g++ ) {
// create the related graph
var graph = new AmCharts.AmGraph();
graph.lineAlpha = 0;
graph.lineColor = AmCharts.charts[ x ].graphs[ g ].lineColor;
graph.relatedGraph = AmCharts.charts[ x ].graphs[ g ];
graph.valueField = "value_" + x + "_" + g;
graph.showBalloon = false;
graph.includeInMinMax = false;
graph.title = AmCharts.charts[ x ].graphs[ g ].title;
lastChart.addGraph( graph );
// mirror data for rollovers
for ( var i = 0; i < lastChart.dataProvider.length; i++ ) {
lastChart.dataProvider[ i ][ graph.valueField ] = AmCharts.charts[ x ].dataProvider[ i ][ AmCharts.charts[ x ].graphs[ g ].valueField ];
}
}
}
/**
* Add events to the legend of last chart so we can toggle
* graphs of the other charts
*/
lastChart.addListener( "init", function() {
// hide graph
lastChart.legend.addListener( "hideItem", function( event ) {
if ( event.dataItem.relatedGraph !== undefined ) {
event.dataItem.relatedGraph.chart.hideGraph( event.dataItem.relatedGraph );
}
} );
// show graph
lastChart.legend.addListener( "showItem", function( event ) {
if ( event.dataItem.relatedGraph !== undefined ) {
event.dataItem.relatedGraph.chart.showGraph( event.dataItem.relatedGraph );
}
} );
} );
And voila:
Here's a working demo:
/**
* First chart
* With scrollbar
* Without category axis
*/
AmCharts.makeChart( "chartdiv1", {
"type": "serial",
"theme": "light",
"path": "http://www.amcharts.com/lib/3/",
"dataProvider": [ {
"category": "Category #1",
"value": 2025
}, {
"category": "Category #2",
"value": 1882
}, {
"category": "Category #3",
"value": 1809
}, {
"category": "Category #4",
"value": 1322
}, {
"category": "Category #5",
"value": 1122
}, {
"category": "Category #6",
"value": 1114
}, {
"category": "Category #7",
"value": 984
}, {
"category": "Category #8",
"value": 711
}, {
"category": "Category #9",
"value": 665
}, {
"category": "Category #10",
"value": 580
} ],
"valueAxes": [ {
"gridAlpha": 0.2,
"dashLength": 0,
"showFirstLabel": false,
"ignoreAxisWidth": true,
"title": "First graph"
} ],
"startDuration": 1,
"graphs": [ {
"id": "g1",
"lineThickness": 2,
"lineColor": "#f56400",
"type": "step",
"valueField": "value",
"title": "Graph 1"
} ],
"chartCursor": {
"categoryBalloonEnabled": false,
"cursorColor": "#c30000",
"animationDuration": 0
},
"chartScrollbar": {},
"categoryField": "category",
"categoryAxis": {
"ignoreAxisWidth": true,
"labelsEnabled": false,
"axisAlpha": 0
},
"marginBottom": 0,
"marginLeft": 80
} );
/**
* Second chart
* Without scrollbar
* With category axis
*/
AmCharts.makeChart( "chartdiv2", {
"type": "serial",
"theme": "light",
"zoomOutText": "",
"path": "http://www.amcharts.com/lib/3/",
"dataProvider": [ {
"category": "Category #1",
"value": 521
}, {
"category": "Category #2",
"value": 215
}, {
"category": "Category #3",
"value": 655
}, {
"category": "Category #4",
"value": 601
}, {
"category": "Category #5",
"value": 122
}, {
"category": "Category #6",
"value": 114
}, {
"category": "Category #7",
"value": 521
}, {
"category": "Category #8",
"value": 351
}, {
"category": "Category #9",
"value": 222
}, {
"category": "Category #10",
"value": 156
} ],
"valueAxes": [ {
"gridAlpha": 0.2,
"dashLength": 0,
"showLastLabel": false,
"ignoreAxisWidth": true,
"title": "Second graph"
} ],
"startDuration": 1,
"graphs": [ {
"id": "g1",
"lineThickness": 2,
"lineColor": "#fae879",
"type": "step",
"valueField": "value",
"title": "Graph 2"
} ],
"chartCursor": {
"cursorColor": "#c30000",
"animationDuration": 0
},
"categoryField": "category",
"categoryAxis": {
"tickPosition": "middle"
},
"legend": {},
"marginTop": 0,
"marginLeft": 80
} );
/**
* Use events to sync up cursors and zooms
*/
for ( var x = 0; x < AmCharts.charts.length; x++ ) {
// use "changed" event to track cursor movement on all charts
// place the cursor on other charts on the same index
AmCharts.charts[ x ].addListener( "changed", function( event ) {
// find which category is currently being rolled over
var category = event.chart.dataProvider[ event.index ][ event.chart.categoryField ];
// cycle through all available charts and place the cursor at
// the same category
for ( var i = 0; i < AmCharts.charts.length; i++ ) {
if ( event.chart !== AmCharts.charts[ i ] ) {
AmCharts.charts[ i ].chartCursor.showCursorAt( category );
}
}
} );
// use "zoomed" event to track zooms/pans so we can apply
// the same zoom across other charts
AmCharts.charts[ x ].addListener( "zoomed", function( zoomEvent ) {
// cycle through all available charts and apply same zoom
for ( var i = 0; i < AmCharts.charts.length; i++ ) {
if ( zoomEvent.chart !== AmCharts.charts[ i ] && ( AmCharts.charts[ i ].startIndex != zoomEvent.startIndex || AmCharts.charts[ i ].endIndex != zoomEvent.endIndex ) ) {
AmCharts.charts[ i ].zoomToIndexes( zoomEvent.startIndex, zoomEvent.endIndex );
}
}
} );
}
/**
* Use the last chart to display legend
* We will collect graphs from other charts and mirror them on
* the last chart.
*/
var lastChart = AmCharts.charts[ AmCharts.charts.length - 1 ];
for ( var x = 0; x < ( AmCharts.charts.length - 1 ); x++ ) {
// add graphs
for ( var g = 0; g < AmCharts.charts[ x ].graphs.length; g++ ) {
// create the related graph
var graph = new AmCharts.AmGraph();
graph.lineAlpha = 0;
graph.lineColor = AmCharts.charts[ x ].graphs[ g ].lineColor;
graph.relatedGraph = AmCharts.charts[ x ].graphs[ g ];
graph.valueField = "value_" + x + "_" + g;
graph.showBalloon = false;
graph.includeInMinMax = false;
graph.title = AmCharts.charts[ x ].graphs[ g ].title;
lastChart.addGraph( graph );
// mirror data for rollovers
for ( var i = 0; i < lastChart.dataProvider.length; i++ ) {
lastChart.dataProvider[ i ][ graph.valueField ] = AmCharts.charts[ x ].dataProvider[ i ][ AmCharts.charts[ x ].graphs[ g ].valueField ];
}
}
}
/**
* Add events to the legend of last chart so we can toggle
* graphs of the other charts
*/
lastChart.addListener( "init", function() {
// hide graph
lastChart.legend.addListener( "hideItem", function( event ) {
if ( event.dataItem.relatedGraph !== undefined ) {
event.dataItem.relatedGraph.chart.hideGraph( event.dataItem.relatedGraph );
}
} );
// show graph
lastChart.legend.addListener( "showItem", function( event ) {
if ( event.dataItem.relatedGraph !== undefined ) {
event.dataItem.relatedGraph.chart.showGraph( event.dataItem.relatedGraph );
}
} );
} );
.chartdiv {
width: 100%;
height: 300px;
font-size: 11px;
}
<script src="http://www.amcharts.com/lib/3/amcharts.js"></script>
<script src="http://www.amcharts.com/lib/3/serial.js"></script>
<script src="http://www.amcharts.com/lib/3/themes/light.js"></script>
<div id="chartdiv1" class="chartdiv"></div>
<div id="chartdiv2" class="chartdiv"></div>

Retrieving data from ASP.net sql database into amchart

i am facing quite a problem which is to create the nice graph from http://www.amcharts.com/ but i need to retrieve data from my sql database. But i don't know how to place inside. Please guide me. Below is the way how the graph displayed, but i wanted to work with data from database. Thank you.
<script type="text/javascript">
var chartData = generateChartData();
function generateChartData() {
var chartData = [];
var firstDate = new Date(2012, 0, 1);
firstDate.setDate(firstDate.getDate() - 500);
firstDate.setHours(0, 0, 0, 0);
for (var i = 0; i < 500; i++) {
var newDate = new Date(firstDate);
newDate.setDate(newDate.getDate() + i);
var value = Math.round(Math.random() * (40 + i)) + 100 + i;
chartData.push({
date: newDate,
value: value
});
}
return chartData;
}
AmCharts.makeChart("chartdiv", {
type: "stock",
pathToImages: "../amcharts/images/",
dataSets: [{
color: "#b0de09",
fieldMappings: [{
fromField: "value",
toField: "value"
}],
dataProvider: chartData,
categoryField: "date"
}],
panels: [{
showCategoryAxis: true,
title: "Value",
eraseAll: false,
labels: [{
x: 0,
y: 100,
text: "Click on the pencil icon on top-right to start drawing",
align: "center",
size: 16
}],
stockGraphs: [{
id: "g1",
valueField: "value",
bullet: "round",
bulletColor: "#FFFFFF",
bulletBorderColor: "#00BBCC",
bulletBorderAlpha: 1,
bulletBorderThickness: 2,
bulletSize: 7,
lineThickness: 2,
lineColor: "#00BBCC",
useDataSetColors: false
}],
stockLegend: {
valueTextRegular: " ",
markerType: "none"
},
drawingIconsEnabled: true
}],
chartScrollbarSettings: {
graph: "g1"
},
chartCursorSettings: {
valueBalloonsEnabled: true
},
periodSelector: {
position: "bottom",
periods: [{
period: "DD",
count: 10,
label: "10 days"
}, {
period: "MM",
count: 1,
label: "1 month"
}, {
period: "YYYY",
count: 1,
label: "1 year"
}, {
period: "YTD",
label: "YTD"
}, {
period: "MAX",
label: "MAX"
}]
}
});
</script>
Can you generate this script in your code behind ( using a string builder for example ) then use this
ScriptManager.RegisterStartupScript(this, this.GetType(), "", "'" + YourStringBuild.toString() + "'", true);

Resources