I'd like to create a scatter or bubble chart with elliptical markers, with the ellipse center and axes determined by data values.
Is there any simple approach I can take, perhaps using a custom template ?
Thanks Graham - this is almost what I need, and illustrates the fantastic flexibility of igDataChart !
However I'm getting a little lost in the scaling that's going on. For instance, the code sample above produces a marker at (2,5) with pixel radii independent of chart zoom. I would like this to be rendered as an ellipse extending from -1 to 5 on the x-axis (2-3 to 2+3) and -3 to 13 on the y-axis (5-8 to 5+8)
Can this be achieved with a simple modification ?
Here's an example of one way you could implement an elliptical marker template:
var data = [{ x: 2, y: 5, value1: 3, value2: 8 }, { x: 3, y: 3, value1: 5, value2: 2 }, { x: 1, y: 2, value1: 1, value2: 1 }, { x: 3, y: 2, value1: 4, value2: 3 }, { x: 5, y: 1, value1: 2, value2: 4 }, { x: 4, y: 3, value1: 2, value2: 2 }]; var minRx; var maxRx; var minRy; var maxRy; var minRadius = 5; var maxRadius = 20; var ellipticalMarker = { passStarting: function (passInfo) { maxRx = Number.MIN_VALUE; minRx = Number.MAX_VALUE; maxRy = Number.MIN_VALUE; minRy = Number.MAX_VALUE; for (var i = 0; i < data.length; i++) { maxRx = Math.max(maxRx, data[i].value1); minRx = Math.min(minRx, data[i].value1); maxRy = Math.max(maxRy, data[i].value2); minRy = Math.min(minRy, data[i].value2); } }, measure: function (measureInfo) { var item = measureInfo.data.item(), width = ((item.value1 - minRx) / (maxRx - minRx)) * (maxRadius - minRadius) + minRadius, height = ((item.value2 - minRy) / (maxRy - minRy)) * (maxRadius - minRadius) + minRadius; measureInfo.width = width; measureInfo.height = height; }, render: function (renderInfo) { var ctx = renderInfo.context, x = renderInfo.xPosition, y = renderInfo.yPosition, item = renderInfo.data.item(), width = renderInfo.availableWidth, height = renderInfo.availableHeight; ctx.fillStyle = renderInfo.data.actualItemBrush().fill(); ctx.strokeStyle = renderInfo.data.outline().fill(); ctx.lineWidth = 1.0 / Math.max(width, height); ctx.save(); ctx.translate(x, y); ctx.scale(width, height); ctx.translate(-x, -y); ctx.beginPath(); ctx.arc(x, y, 1, 0, 2.0 * Math.PI, false); ctx.fill(); ctx.stroke(); ctx.restore(); } }; $("#container").igDataChart({ width: "500px", height: "500px", dataSource: data, axes: [{ name: "xAxis", type: "numericX", minimumValue: 0, maximumValue: 8 }, { name: "yAxis", type: "numericY", minimumValue: 0, maximumValue: 8 }], series: [{ name: "series1", title: "Test Series", type: "scatter", xAxis: "xAxis", yAxis: "yAxis", xMemberPath: "x", yMemberPath: "y", markerTemplate: ellipticalMarker, showTooltip: true, tooltipTemplate: "tooltipTemplate" }], horizontalZoomable: true, verticalZoomable: true, windowResponse: "immediate", overviewPlusDetailPaneVisibility: "visible" }); });
Hope this helps! -Graham