I need to write a function, which generates corridor path by line path and width.
For example, I have array of coords of polyline:
var coords = [
50, 50,
150, 50,
250, 100,
220, 200,
350, 100,
];
https://i.stack.imgur.com/FCCxb.png
Then I use function to get corridor path:
var width = 10;
var corridorPath = getCorridorPath(coords, width);
Function should return something like that:
[
40, 50,
50, 40,
150, 40,
157, 41,
255, 90,
260, 105,
240, 170,
340, 90,
360, 90,
360, 110,
220, 215,
205, 205,
233, 107,
147, 62,
50, 60,
40, 50,
]
https://i.stack.imgur.com/v3wxN.png
Calculate parallel polylines and conjunctions.
For two neighbor edges AB and BC find normalized vectors ab and cb.
Calculate unit bisector vector:
b = (ab + cb).normalized
Calculate length of bisector segments as
len = d / sin(fi)
where d is offset (halfwidth), and fi is angle between vectors b and ab:
fi = atan2(crossproduct(b,ab), dotproduct(b,ab))
Find offset points (left and right ones) as
B' = B + l * b
B'' = B - l * b
Note that you want to cut long triangles, so offset point is valid for side with acute angle, and you need to recalculate two points for cut cap - for example, get central point B''' = B - d * b and add vectors, perpendicular to bisector.
I wrote my own polygon function; the problem is when I want to have the polygon only draw a border, it ends up using the previous fillStyle and draws over previous polygons.
var canvas = document.getElementById('canvas')
var ctx = canvas.getContext('2d')
const HP_DARKGREEN = '#003100'
const HP_LIGHTGREEN = '#007E00'
var health = 50
function polygon(x1, y1, border = {
color: 'black',
width: 1,
lineJoin: 'round',
lineCap: 'square'
}, fillColor = false, ...coords) {
/* Draws a polygon given an array of coordinates */
let c = coords
ctx.translate(x1, y1)
if (border) {
ctx.strokeStyle = border.color
}
ctx.beginPath()
for (let i = 0; i < c.length - 1; i += 2) {
ctx.lineTo(c[i], c[i + 1])
}
ctx.closePath()
if (fillColor) {
ctx.fillStyle = fillColor
ctx.fill()
}
if (border) {
ctx.lineWidth = border.width
ctx.lineCap = border.lineCap
ctx.lineJoin = border.lineJoin
ctx.stroke()
}
ctx.translate(-x1, -y1)
}
//Trying to draw these polygons
polygon(14, 4, false, HP_DARKGREEN, 114, 4, 104, 19, 4, 19, 14, 4)
polygon(14, 4, false, HP_LIGHTGREEN, health + 14, 4, health + 4, 19, 4, 19, 14, 4)
polygon(14, 4, {
color: 'black',
width: 2
}, false, 114, 4, 104, 19, 4, 19, 14, 4)
var Render = {
clear: () => {
ctx.clearRect(0, 0, canvas.width, canvas.height)
},
update: () => {
Render.clear()
Render.display.health()
requestAnimationFrame(() => {
Render.update()
})
}
}
<canvas id='canvas' width=192 height=192></canvas>
Now that I look at it, it seems to work beautifully in JSFiddle. The only difference is that in the actual program, I use requestAnimationFrame() to loop through the rendering process. The problem is being caused by the third polygon (it fills the entire bar with the lightgreen color).
Edit: I just tried to run the function just once in my code. It worked fine; when I ran the loop function, it failed to draw correctly. I'm not sure if this is an issue with the default parameters or something else...
Are you looking for something like this?
var canvas = document.getElementById('canvas')
var ctx = canvas.getContext('2d')
const HP_DARKGREEN = '#003100'
const HP_LIGHTGREEN = '#007E00'
var health = 50
function polygon(x1, y1, border = { color: 'black', width: 1, lineJoin: 'round', lineCap: 'square'}, fillColor = false, ...coords) {
/* Draws a polygon given an array of coordinates */
let c = coords
ctx.translate(x1, y1)
if (border) { ctx.strokeStyle = border.color }
ctx.beginPath()
for (let i=0; i<c.length - 1; i+=2) {
ctx.lineTo(c[i],c[i+1])
}
ctx.closePath()
if (fillColor) {
ctx.fillStyle = fillColor
ctx.fill()
}
if (border) {
ctx.lineWidth = border.width
ctx.lineCap = border.lineCap
ctx.lineJoin = border.lineJoin
ctx.stroke()
}
ctx.translate(-x1, -y1)
}
//Trying to draw these polygons
function drawPoly(){
polygon(14, 4, false, HP_DARKGREEN, 114, 4, 104, 19, 4, 19, 14, 4)
polygon(14, 4, false, HP_LIGHTGREEN, health + 14, 4, health + 4, 19, 4, 19, 14, 4)
polygon(14, 4, { color: 'red', width: 2 }, false, 114, 4, 104, 19, 4, 19, 14, 4)
health--;
if(health<0){
health = 0;
}
window.requestAnimationFrame(drawPoly);
}
drawPoly();
<canvas id='canvas' width=192 height=192></canvas>
Well, the answer is exactly what you would expect. An unfinished line of code completely unrelated to this was causing all of the problems. Programming is fun.
I have this below HTML code.
<div id="ImageWrapper" class="grid_col-xs">
<div id="parentID" style="background-image: url(img/retailshop.jpg);background-size:100%;width: 100%;height: 0;padding-top: 66.64%;" ></div>
<script type="text/javascript">
drawOverlayHeatmap('parentID');
</script>
</div>
drawOverlayHeatmap('parentID') function draws a canvas inside the parentID div tag. But it overflows some content out of my div tag.
<script type="text/javascript">
var X = new Array(10, 10, 10, 30, 10, 30, 10, 20, 30, 40, 50, 60, 70, 80, 50, 60, 70, 80);
var Y = new Array(10, 30, 10, 50, 10, 50, 30, 20, 10, 20, 10, 10, 10, 100, 10, 10, 10, 100);
var C = new Array(5, 10, 7, 20, 5, 20, 5, 10, 7, 20, 5, 20, 5, 10, 7, 20, 5, 20);
var computeRelativePosition = (point, relativeTo) => {
return (point / 100) * relativeTo;
};
function drawOverlayHeatmap(elementName){
var heatmap = h337.create({
container: document.getElementById(elementName),
// a waterdrop gradient ;-)
// gradient: { .1: 'rgba(0,0,0,0)', 0.25: "rgba(0,0,90, .6)", .6: "blue", .9: "cyan", .95: 'rgba(255,255,255,.4)' },
maxOpacity: .6,
radius: 10,
blur: .90
});
var width = (window.getComputedStyle(document.getElementById(elementName)).width.replace(/px/, ''));
var height = (window.getComputedStyle(document.getElementById(elementName)).height.replace(/px/, ''));
console.log(height);
var generate = function (iterator) {
var x = (computeRelativePosition(X[iterator], width)) >> 0;
var y = (computeRelativePosition(Y[iterator], height)) >> 0;
var c = (C[iterator] * 100) >> 0;
// add the datapoint to heatmap instance
heatmap.addData({ x: x, y: y, value: c, radius: 50 });
};
for (i = 0; i < X.length; i++) {
generate(i);
}
}
</script>
How can I forcefully set my dic tag not to let other components inside it to overflow?
EDIT: I have tried to use overflow: auto and hidden. But I don't want to lose the overflow area. I want that area to be shrink and fir on my parentID div tag.
I'm using the https://www.patrick-wied.at/static/heatmapjs/ to draw the heatmaps above the images. I have put the image as my background in the div tag.
I am using fabric.js and trying to allow rotation for any object on my canvas, not freely 360 degrees, but only 15 degrees at a time, using the rotation handle. I searched really hard but couldn't find an answer so far. Is this possible?
Shorter solution:
canvas.on('object:rotating', function(options) {
var step = 15;
options.target.angle = Math.round(options.target.angle / step) * step;
});
UPD: since 1.6.7 you can just use fabric.Object.snapAngle property:
someFabricObject.snapAngle = 15;
You can use canvas.on("object:rotating") to interfer with rotation of all objects.
I defined a set of valid angles, and then on the rotation event i checked which one to use.
var angles = [0, 15, 30, 45, 60, 75, 90, 105, 120, 135, 150, 165, 180, 195, 210, 225, 240, 255, 270, 285, 300, 315, 330, 345, 360];
canvas.on("object:rotating", function(rotEvtData) {
var targetObj = rotEvtData.target;
var angle = targetObj.angle % 360;
for (var i=0; i < angles.length; i++) {
if (angle <= angles[i]) {
targetObj.angle = angles[i];
break;
}
}
});
var canvas = new fabric.Canvas("c");
var rect = new fabric.Rect({
left: 100,
top: 100,
fill: 'red',
width: 90,
height: 90
});
canvas.add(rect);
var angles = [0, 15, 30, 45, 60, 75, 90, 105, 120, 135, 150, 165, 180, 195, 210, 225, 240, 255, 270, 285, 300, 315, 330, 345, 360];
canvas.on("object:rotating", function(rotEvtData) {
var targetObj = rotEvtData.target;
var angle = targetObj.angle % 360;
for (var i=0; i < angles.length; i++) {
if (angle <= angles[i]) {
targetObj.angle = angles[i];
break;
}
}
});
<script src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.5.0/fabric.min.js"></script>
<canvas id="c" width="400" height="400"></canvas>
I have labels ranging from 50-90, and every number in between in displayed.
I would like to list the labels by 5 or 10 because currently they are all crunched together.
It also make the left part of the y-axis cut off.
EDIT 2: Ok so i actually needed functionality like this in a project I am working on so i have made a custom build of chart.js to include this functionality.http://jsfiddle.net/leighking2/mea767ss/ or https://github.com/leighquince/Chart.js
It's a combination of the two solutions below but tied into the core of CHart.js so no need to specify custom scale and charts.
Both line and bar charts have a new option called
labelsFilter:function(label, index){return false;)
by default this will just return false so all labels on the x-axis will display but if a filter is passed as an option then it will filter the labels
so here is an example with both bar and line
var ctx = document.getElementById("chart").getContext("2d");
var data = {
labels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30],
datasets: [{
label: "My First dataset",
fillColor: "rgba(220,220,220,0.5)",
strokeColor: "rgba(220,220,220,0.8)",
highlightFill: "rgba(220,220,220,0.75)",
highlightStroke: "rgba(220,220,220,1)",
data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
}]
};
var myLineChart = new Chart(ctx).Line(data, {
labelsFilter: function (value, index) {
return (index + 1) % 5 !== 0;
}
});
<script src="http://quincewebdesign.com/cdn/Chart.js"></script>
<canvas id="chart" width="1200px"></canvas>
ORIGINAL ANSWER
You can override the scale draw function to achieve this. Only thing i don;t like about this is it will apply to all your graphs so the other option is to have a custom graph type that makes use of the overridden draw.
EDIT 1: just realized the same affect can be achieved by using the index value rather than the label and this can then be applied to all label types not just numerical ones, this applies for both examples and could be easily changed. Here is the second example using the index rather than the label http://jsfiddle.net/leighking2/n9c8jx55/
1st - Overriding the scale draw function http://jsfiddle.net/leighking2/96grgz0d/
Only change here is before drawing the x-axis label we test if the label is a number and if its remainder when divided by 5 is not equal to 0 (so any number not dividable by 5)
if it matches both those criteria we do not draw the label
Chart.Scale = Chart.Scale.extend({
draw : function(){
console.log(this);
var helpers = Chart.helpers;
var each = helpers.each;
var aliasPixel = helpers.aliasPixel;
var toRadians = helpers.radians;
var ctx = this.ctx,
yLabelGap = (this.endPoint - this.startPoint) / this.steps,
xStart = Math.round(this.xScalePaddingLeft);
if (this.display){
ctx.fillStyle = this.textColor;
ctx.font = this.font;
each(this.yLabels,function(labelString,index){
var yLabelCenter = this.endPoint - (yLabelGap * index),
linePositionY = Math.round(yLabelCenter);
ctx.textAlign = "right";
ctx.textBaseline = "middle";
if (this.showLabels){
ctx.fillText(labelString,xStart - 10,yLabelCenter);
}
ctx.beginPath();
if (index > 0){
// This is a grid line in the centre, so drop that
ctx.lineWidth = this.gridLineWidth;
ctx.strokeStyle = this.gridLineColor;
} else {
// This is the first line on the scale
ctx.lineWidth = this.lineWidth;
ctx.strokeStyle = this.lineColor;
}
linePositionY += helpers.aliasPixel(ctx.lineWidth);
ctx.moveTo(xStart, linePositionY);
ctx.lineTo(this.width, linePositionY);
ctx.stroke();
ctx.closePath();
ctx.lineWidth = this.lineWidth;
ctx.strokeStyle = this.lineColor;
ctx.beginPath();
ctx.moveTo(xStart - 5, linePositionY);
ctx.lineTo(xStart, linePositionY);
ctx.stroke();
ctx.closePath();
},this);
each(this.xLabels,function(label,index){
//================================
//test to see if we draw the label
//================================
if(typeof label === "number" && label%5 != 0){
return;
}
var xPos = this.calculateX(index) + aliasPixel(this.lineWidth),
// Check to see if line/bar here and decide where to place the line
linePos = this.calculateX(index - (this.offsetGridLines ? 0.5 : 0)) + aliasPixel(this.lineWidth),
isRotated = (this.xLabelRotation > 0);
ctx.beginPath();
if (index > 0){
// This is a grid line in the centre, so drop that
ctx.lineWidth = this.gridLineWidth;
ctx.strokeStyle = this.gridLineColor;
} else {
// This is the first line on the scale
ctx.lineWidth = this.lineWidth;
ctx.strokeStyle = this.lineColor;
}
ctx.moveTo(linePos,this.endPoint);
ctx.lineTo(linePos,this.startPoint - 3);
ctx.stroke();
ctx.closePath();
ctx.lineWidth = this.lineWidth;
ctx.strokeStyle = this.lineColor;
// Small lines at the bottom of the base grid line
ctx.beginPath();
ctx.moveTo(linePos,this.endPoint);
ctx.lineTo(linePos,this.endPoint + 5);
ctx.stroke();
ctx.closePath();
ctx.save();
ctx.translate(xPos,(isRotated) ? this.endPoint + 12 : this.endPoint + 8);
ctx.rotate(toRadians(this.xLabelRotation)*-1);
ctx.textAlign = (isRotated) ? "right" : "center";
ctx.textBaseline = (isRotated) ? "middle" : "top";
ctx.fillText(label, 0, 0);
ctx.restore();
},this);
}
}
});
then we can use the graphs like normal. Declare data
var ctx = document.getElementById("chart").getContext("2d");
var data = {
labels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30],
datasets: [{
label: "My First dataset",
fillColor: "rgba(220,220,220,0.2)",
strokeColor: "rgba(220,220,220,1)",
pointColor: "rgba(220,220,220,1)",
pointStrokeColor: "#fff",
pointHighlightFill: "#fff",
pointHighlightStroke: "rgba(220,220,220,1)",
data: [65, 34, 21, 11, 11, 34, 34, 12, 24, 45, 65, 34, 21, 11, 11, 34, 34, 12, 24, 45, 65, 34, 21, 11, 11, 34, 34, 12, 24, 45]
}, ]
};
draw graph
var myLineChart = new Chart(ctx).Line(data);
2nd custom graph + custom scale + filter function http://jsfiddle.net/leighking2/6xej5ek3/
In this method we still need to create a custom scale object but instead of having this applied to all charts we create we can choose to only apply it to those that we have declared. Also in this example we can also have the filter be a function that gets applied at run time so we can have each graph filter the labels differently
first the scale object
Chart.CustomScale = Chart.Scale.extend({
draw: function () {
console.log(this);
var helpers = Chart.helpers;
var each = helpers.each;
var aliasPixel = helpers.aliasPixel;
var toRadians = helpers.radians;
var ctx = this.ctx,
yLabelGap = (this.endPoint - this.startPoint) / this.steps,
xStart = Math.round(this.xScalePaddingLeft);
if (this.display) {
ctx.fillStyle = this.textColor;
ctx.font = this.font;
each(this.yLabels, function (labelString, index) {
var yLabelCenter = this.endPoint - (yLabelGap * index),
linePositionY = Math.round(yLabelCenter);
ctx.textAlign = "right";
ctx.textBaseline = "middle";
if (this.showLabels) {
ctx.fillText(labelString, xStart - 10, yLabelCenter);
}
ctx.beginPath();
if (index > 0) {
// This is a grid line in the centre, so drop that
ctx.lineWidth = this.gridLineWidth;
ctx.strokeStyle = this.gridLineColor;
} else {
// This is the first line on the scale
ctx.lineWidth = this.lineWidth;
ctx.strokeStyle = this.lineColor;
}
linePositionY += helpers.aliasPixel(ctx.lineWidth);
ctx.moveTo(xStart, linePositionY);
ctx.lineTo(this.width, linePositionY);
ctx.stroke();
ctx.closePath();
ctx.lineWidth = this.lineWidth;
ctx.strokeStyle = this.lineColor;
ctx.beginPath();
ctx.moveTo(xStart - 5, linePositionY);
ctx.lineTo(xStart, linePositionY);
ctx.stroke();
ctx.closePath();
}, this);
each(this.xLabels, function (label, index) {
//======================================================
//apply the filter the the label if it is a function
//======================================================
if (typeof this.labelsFilter === "function" && this.labelsFilter(label)) {
return;
}
var xPos = this.calculateX(index) + aliasPixel(this.lineWidth),
// Check to see if line/bar here and decide where to place the line
linePos = this.calculateX(index - (this.offsetGridLines ? 0.5 : 0)) + aliasPixel(this.lineWidth),
isRotated = (this.xLabelRotation > 0);
ctx.beginPath();
if (index > 0) {
// This is a grid line in the centre, so drop that
ctx.lineWidth = this.gridLineWidth;
ctx.strokeStyle = this.gridLineColor;
} else {
// This is the first line on the scale
ctx.lineWidth = this.lineWidth;
ctx.strokeStyle = this.lineColor;
}
ctx.moveTo(linePos, this.endPoint);
ctx.lineTo(linePos, this.startPoint - 3);
ctx.stroke();
ctx.closePath();
ctx.lineWidth = this.lineWidth;
ctx.strokeStyle = this.lineColor;
// Small lines at the bottom of the base grid line
ctx.beginPath();
ctx.moveTo(linePos, this.endPoint);
ctx.lineTo(linePos, this.endPoint + 5);
ctx.stroke();
ctx.closePath();
ctx.save();
ctx.translate(xPos, (isRotated) ? this.endPoint + 12 : this.endPoint + 8);
ctx.rotate(toRadians(this.xLabelRotation) * -1);
ctx.textAlign = (isRotated) ? "right" : "center";
ctx.textBaseline = (isRotated) ? "middle" : "top";
ctx.fillText(label, 0, 0);
ctx.restore();
}, this);
}
}
});
now the custom graph that will make use of this scale, rather annoyingly we have to override the whole of the buildscale function
Chart.types.Line.extend({
name: "LineAlt",
initialize: function (data) {
//======================================================
//ensure the new option is part of the options
//======================================================
this.options.labelsFilter = data.labelsFilter || null;
Chart.types.Line.prototype.initialize.apply(this, arguments);
},
buildScale: function (labels) {
var helpers = Chart.helpers;
var self = this;
var dataTotal = function () {
var values = [];
self.eachPoints(function (point) {
values.push(point.value);
});
return values;
};
var scaleOptions = {
templateString: this.options.scaleLabel,
height: this.chart.height,
width: this.chart.width,
ctx: this.chart.ctx,
textColor: this.options.scaleFontColor,
fontSize: this.options.scaleFontSize,
//======================================================
//pass this new options to the scale object
//======================================================
labelsFilter: this.options.labelsFilter,
fontStyle: this.options.scaleFontStyle,
fontFamily: this.options.scaleFontFamily,
valuesCount: labels.length,
beginAtZero: this.options.scaleBeginAtZero,
integersOnly: this.options.scaleIntegersOnly,
calculateYRange: function (currentHeight) {
var updatedRanges = helpers.calculateScaleRange(
dataTotal(),
currentHeight,
this.fontSize,
this.beginAtZero,
this.integersOnly);
helpers.extend(this, updatedRanges);
},
xLabels: labels,
font: helpers.fontString(this.options.scaleFontSize, this.options.scaleFontStyle, this.options.scaleFontFamily),
lineWidth: this.options.scaleLineWidth,
lineColor: this.options.scaleLineColor,
gridLineWidth: (this.options.scaleShowGridLines) ? this.options.scaleGridLineWidth : 0,
gridLineColor: (this.options.scaleShowGridLines) ? this.options.scaleGridLineColor : "rgba(0,0,0,0)",
padding: (this.options.showScale) ? 0 : this.options.pointDotRadius + this.options.pointDotStrokeWidth,
showLabels: this.options.scaleShowLabels,
display: this.options.showScale
};
if (this.options.scaleOverride) {
helpers.extend(scaleOptions, {
calculateYRange: helpers.noop,
steps: this.options.scaleSteps,
stepValue: this.options.scaleStepWidth,
min: this.options.scaleStartValue,
max: this.options.scaleStartValue + (this.options.scaleSteps * this.options.scaleStepWidth)
});
}
//======================================================
//Use the new Custom Scal that will make use of a labelsFilter function
//======================================================
this.scale = new Chart.CustomScale(scaleOptions);
}
});
then we can use it like normal. Declare the data but this time pass a new option for labelsFilter that is a function to apply the filtering of the x labels
var ctx = document.getElementById("chart").getContext("2d");
var data = {
labels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30],
labelsFilter: function (label) {
//return true if this label should be filtered out
return label % 5 !== 0;
},
datasets: [{
label: "My First dataset",
fillColor: "rgba(220,220,220,0.2)",
strokeColor: "rgba(220,220,220,1)",
pointColor: "rgba(220,220,220,1)",
pointStrokeColor: "#fff",
pointHighlightFill: "#fff",
pointHighlightStroke: "rgba(220,220,220,1)",
data: [65, 34, 21, 11, 11, 34, 34, 12, 24, 45, 65, 34, 21, 11, 11, 34, 34, 12, 24, 45, 65, 34, 21, 11, 11, 34, 34, 12, 24, 45]
}, ]
};
then draw the graph using our new custom graph name
var myLineChart = new Chart(ctx).LineAlt(data);
Overall even though it is a bit more involved i prefer the second method as it means that a custom filter can be applied to each graph i declare.
I updated the provided code snippet to prevent the rotation of the x-axis labels. Also some parameters were not being passed on in the constructor. Check the //Mike Walder comments.
//Code to manually set the interval of X-Axis Labels: From http://jsfiddle.net/leighking2/n9c8jx55/
Chart.CustomScale = Chart.Scale.extend({
draw: function () {
var helpers = Chart.helpers;
var each = helpers.each;
var aliasPixel = helpers.aliasPixel;
var toRadians = helpers.radians;
var ctx = this.ctx,
yLabelGap = (this.endPoint - this.startPoint) / this.steps,
xStart = Math.round(this.xScalePaddingLeft);
if (this.display) {
ctx.fillStyle = this.textColor;
ctx.font = this.font;
each(this.yLabels, function (labelString, index) {
var yLabelCenter = this.endPoint - (yLabelGap * index),
linePositionY = Math.round(yLabelCenter);
ctx.textAlign = "right";
ctx.textBaseline = "middle";
if (this.showLabels) {
ctx.fillText(labelString, xStart - 10, yLabelCenter);
}
ctx.beginPath();
if (index > 0) {
// This is a grid line in the centre, so drop that
ctx.lineWidth = this.gridLineWidth;
ctx.strokeStyle = this.gridLineColor;
} else {
// This is the first line on the scale
ctx.lineWidth = this.lineWidth;
ctx.strokeStyle = this.lineColor;
}
linePositionY += helpers.aliasPixel(ctx.lineWidth);
ctx.moveTo(xStart, linePositionY);
ctx.lineTo(this.width, linePositionY);
ctx.stroke();
ctx.closePath();
ctx.lineWidth = this.lineWidth;
ctx.strokeStyle = this.lineColor;
ctx.beginPath();
ctx.moveTo(xStart - 5, linePositionY);
ctx.lineTo(xStart, linePositionY);
ctx.stroke();
ctx.closePath();
}, this);
each(this.xLabels, function (label, index) {
//======================================================
//apply the filter to the index if it is a function
//======================================================
if (typeof this.labelsFilter === "function" && this.labelsFilter(index)) {
return;
}
//Hack by Mike Walder to enforce X-Labels are Written horizontally
var xLabelRot = this.xLabelRotation;
this.xLabelRotation = 0;
//End of Hack
var xPos = this.calculateX(index) + aliasPixel(this.lineWidth),
// Check to see if line/bar here and decide where to place the line
linePos = this.calculateX(index - (this.offsetGridLines ? 0.5 : 0)) + aliasPixel(this.lineWidth),
//Mike Walder: isRotated nees original Roation Value to display the X-Label in the RollOver Area of a Datapoint
isRotated = true;(xLabelRot > 0);
ctx.beginPath();
if(this.scaleShowVerticalLines){
if (index > 0) {
// This is a grid line in the centre, so drop that
ctx.lineWidth = this.gridLineWidth;
ctx.strokeStyle = this.gridLineColor;
} else {
// This is the first line on the scale
ctx.lineWidth = this.lineWidth;
ctx.strokeStyle = this.lineColor;
}
ctx.moveTo(linePos, this.endPoint);
ctx.lineTo(linePos, this.startPoint - 3);
ctx.stroke();
ctx.closePath();
ctx.lineWidth = this.lineWidth;
ctx.strokeStyle = this.lineColor;
}
// Small lines at the bottom of the base grid line
ctx.beginPath();
ctx.moveTo(linePos, this.endPoint);
ctx.lineTo(linePos, this.endPoint + 5);
ctx.stroke();
ctx.closePath();
ctx.save();
ctx.translate(xPos, (isRotated) ? this.endPoint + 12 : this.endPoint + 8);
ctx.rotate(toRadians(this.xLabelRotation) * -1);
//Mike Walder added center here, because it looks better if the label designator is in the center of the smal line
ctx.textAlign = "center";
ctx.textBaseline = (isRotated) ? "middle" : "top";
ctx.fillText(label, 0, 0);
ctx.restore();
}, this);
}
}
});
Chart.types.Line.extend({
name: "LineAlt",
initialize: function (data) {
//======================================================
//ensure the new option is part of the options
//======================================================
this.options.labelsFilter = data.labelsFilter || null;
Chart.types.Line.prototype.initialize.apply(this, arguments);
},
buildScale: function (labels) {
var helpers = Chart.helpers;
var self = this;
var dataTotal = function () {
var values = [];
self.eachPoints(function (point) {
values.push(point.value);
});
return values;
};
var scaleOptions = {
// Mike Walder: added this configuration option since it is overridden in the new code
scaleShowVerticalLines: this.options.scaleShowVerticalLines,
templateString: this.options.scaleLabel,
height: this.chart.height,
width: this.chart.width,
ctx: this.chart.ctx,
textColor: this.options.scaleFontColor,
fontSize: this.options.scaleFontSize,
//======================================================
//pass this new options to the scale object
//======================================================
labelsFilter: this.options.labelsFilter,
fontStyle: this.options.scaleFontStyle,
fontFamily: this.options.scaleFontFamily,
valuesCount: labels.length,
beginAtZero: this.options.scaleBeginAtZero,
integersOnly: this.options.scaleIntegersOnly,
calculateYRange: function (currentHeight) {
var updatedRanges = helpers.calculateScaleRange(
dataTotal(),
currentHeight,
this.fontSize,
this.beginAtZero,
this.integersOnly);
helpers.extend(this, updatedRanges);
},
xLabels: labels,
font: helpers.fontString(this.options.scaleFontSize, this.options.scaleFontStyle, this.options.scaleFontFamily),
lineWidth: this.options.scaleLineWidth,
lineColor: this.options.scaleLineColor,
gridLineWidth: (this.options.scaleShowGridLines) ? this.options.scaleGridLineWidth : 0,
gridLineColor: (this.options.scaleShowGridLines) ? this.options.scaleGridLineColor : "rgba(0,0,0,0)",
padding: (this.options.showScale) ? 0 : this.options.pointDotRadius + this.options.pointDotStrokeWidth,
showLabels: this.options.scaleShowLabels,
display: this.options.showScale
};
if (this.options.scaleOverride) {
helpers.extend(scaleOptions, {
calculateYRange: helpers.noop,
steps: this.options.scaleSteps,
stepValue: this.options.scaleStepWidth,
min: this.options.scaleStartValue,
max: this.options.scaleStartValue + (this.options.scaleSteps * this.options.scaleStepWidth)
});
}
//======================================================
//Use the new Custom Scal that will make use of a labelsFilter function
//======================================================
this.scale = new Chart.CustomScale(scaleOptions);
}
});