I'm having issue with generating arc curves with Raphael.
I created a reduced example here: http://jsfiddle.net/vaxilart/m6cHw/3/
As you can see, the first path drawn isn't the same as the second one, and the second one is only a subpath of the first.
Do you know why both are different? And how could I resolve this issue?
Here's the code:
function drawpath( canvas, bg, pathstr, duration, attr, callback ) {
var guide_path = bg;
var path = canvas.path( guide_path.getSubpath( 0, 1 ) ).attr( attr );
var total_length = guide_path.getTotalLength( guide_path );
var last_point = guide_path.getPointAtLength( 0 );
var start_time = new Date().getTime();
var interval_length = 50;
var result = path;
var run = function run() {
var elapsed_time = new Date().getTime() - start_time;
var this_length = elapsed_time / duration * total_length;
var subpathstr = guide_path.getSubpath( 0, this_length );
path.attr({ path: subpathstr });
if ( elapsed_time >= duration ) {
if ( callback != undefined ) callback();
} else {
requestAnimationFrame(run);
}
};
run();
return result;
}
var sequence_path = [
[ "M", 200, 0 ],
[ "V", 200 ],
[ "A", 100, 100, 90, 0, 0, 300, 300 ],
[ "H", 400 ],
[ "A", 100, -100, 90, 0, 0, 500, 400 ],
[ "V", 500 ],
[ "A", 100, -100, 90, 0, 0, 400, 600 ],
[ "H", 200 ],
[ "A", 100, 100, 90, 0, 0, 100, 700 ],
[ "V", 800 ]
];
var paper = Raphael(10, 50, 700, 1000);
var bg = paper.path(sequence_path).attr({
stroke: 'white',
'stroke-width': 64,
'stroke-opacity': 1,
fill: 'none',
'fill-opacity': 0
});
drawpath( paper, bg, sequence_path, 3500, {
stroke: 'orange',
'stroke-width': 64,
'stroke-opacity': 1,
fill: 'none',
'fill-opacity': 0
});
Looks like Raphael's getSubpath method has a bug where it misinterprets the Large Arc Flags and Sweep Flags of a couple of those curves. I might be wrong.
Edit: OK I was wrong. You have some bad Arcs (A) that are breaking something somewhere between Raphael and the browser, not sure where. But the problem is:
You are setting negative y-radius on the two Arcs that get messed up. Radius cant be negative. in your sequence_path definition, change those two -100's to 100 (positive 100 y radius). updated fiddle: http://jsfiddle.net/m6cHw/4/
If you're going to be hand-writing a lot of paths, I suggest you read the standards specs on how to define them: http://www.w3.org/TR/SVG/paths.html. I tried to avoid reading that for a while but eventually I bit the bullet and went through it. It's weird stuff but you need to understand it if you want to make paths do what you want.
Related
I wanted to modify the response for array of object.
I have below result.
And i wanted to change the response to specific response.
let result = [
{
team_id: 1,
team_name: 'Avengers',
participant1: 98,
participant2: 99,
participant3: 100,
participant4: 101,
phase1: 0,
phase2: 0,
phase3: 0,
phase4: 0,
phase5: 0,
participant1_name: 'test 1003',
participant2_name: 'test 1002',
participant3_name: 'test 1004',
participant4_name: 'test 1005'
}
]
And wanted to convert to below.
[
{
"team_id": 1,
"team_name": "Avengers",
"phase1": 0,
"phase2": 0,
"phase3": 0,
"phase4": 0,
"phase5": 0,
"participantDetails": [
{
"participant1": 98,
"participant1_name": "test 1003"
},
{
"participant2": 99,
"participant2_name": "test 1002"
},
{
"participant3": 100,
"participant3_name": "test 1004"
},
{
"participant4": 101,
"participant4_name": "test 1005"
}
]
}
]
I have tried below: -
const data = result.map((elem) => {
const participantDetails = [];
for (let keys in elem) {
if (keys.startsWith('participant')) {
console.log('elem:-',elem);
participantDetails.push({
[keys]: elem[keys]
})
delete elem[keys]
}
}
return {
...elem,
participantDetails: participantDetails
}
});
I have filter participant but not sure how to filter names also.
And they are having different positions for that.
Please help thanks in advance.
You're already in the right direction. You don't have to filter for participant names since you can easily derive them once you filtered the participant.
Here's my approach:
let result = [
{
team_id: 1,
team_name: 'Avengers',
participant1: 98,
participant2: 99,
participant3: 100,
participant4: 101,
phase1: 0,
phase2: 0,
phase3: 0,
phase4: 0,
phase5: 0,
participant1_name: 'test 1003',
participant2_name: 'test 1002',
participant3_name: 'test 1004',
participant4_name: 'test 1005',
},
];
for (let obj of result) {
let participantDetails = [];
Object.keys(obj)
.filter((key) => /^participant\d+$/.test(key))
.forEach((key) => {
participantDetails.push({
[key]: obj[key],
[`${key}_name`]: obj[`${key}_name`],
});
delete obj[key];
delete obj[`${key}_name`];
});
obj.participantDetails = participantDetails;
}
console.log(JSON.stringify(result, null, 4));
Notice that I used regex to filter strictly on participant. From there, I can derive the values for participant_names and push them into the participantDetails array.
It is also important to note that you are modifying the values of the result array. If you want to keep those values, you can use map instead to create a new instance of the array.
I'm trying to meet a style requirement for highcharts heatmaps. Currently, we style 'incomplete' data with a highcharts pattern fill by applying zones to x axis.
the chart currently looks like this, with the pattern fill applied to the zones on the right:
jsfiddle heatmap with incomplete zones
config for color axis:
colorAxis: {
dataClasses: [
{to: 3.33325, name: "<3.3", color: "#FFC4FF"},
{from: 3.33325, to: 5, name: "3.3 to 5.0", color: "#FF70FF"},
{from: 5, to: 6.66675, name: "5.0 to 6.7", color: "#D500F9"},
{from: 6.66675, to: 8.33325, name: "6.7 to 8.3", color: "#550075"},
{from: 8.33325, name: ">8.3", color: "#330046"},
]
}
series:
series: {
data: {
[
{x: 0, y: 0, z: 1},
{x: 0, y: 1, z: 2},
{x: 0, y: 2, z: 3},
{x: 1, y: 0, z: 4},
{x: 1, y: 1, z: 5},
{x: 1, y: 2, z: 6},
{x: 2, y: 0, z: 7}
{x: 2, y: 1, z: 8}
{x: 2, y: 2, z: 9}
]
}
zones: [
{value: 2},
{
color: {
pattern:
{
backgroundColor: "#CCCCCC",
height: 45,
path: {
d: "M-1,1 l2,-2 M0,45 l45,-45 M44,46 l2,-2",
stroke: "#FFFFFF",
strokeWidth: 3
}
width: 45
}
}
}
]
}
Right now the pattern fill is gray for all of them but I'm trying to figure out if there is a way to set up the config so the background color will respect the color set by dataClasses. I tried setting it to currentColor, but the colorAxis color isn't applied to the parent element so that didn't work. I'm trying to avoid using classNames/styled mode if possible
Any suggestions? Thanks
The most efficient way is to opt out of zones and change how colors for points are generated by overwriting translateColors method:
(function(H) {
H.Series.prototype.translateColors = function() {
var series = this,
points = this.data.length ? this.data : this.points,
nullColor = this.options.nullColor,
colorAxis = this.colorAxis,
colorKey = this.colorKey;
points.forEach(function(point) {
var value = point[colorKey],
color;
color = point.options.color ||
(point.isNull ?
nullColor :
(colorAxis && typeof value !== 'undefined') ?
(
point.x < 2 ?
colorAxis.toColor(value, point) : {
pattern: {
backgroundColor: colorAxis.toColor(value, point),
height: 45,
width: 45,
path: {
d: "M-1,1 l2,-2 M0,45 l45,-45 M44,46 l2,-2",
stroke: '#FFFFFF',
strokeWidth: 3
}
}
}
) :
point.color || series.color);
if (color) {
point.color = color;
}
});
}
}(Highcharts));
Live demo: http://jsfiddle.net/BlackLabel/Lygwz16j/
Docs: https://www.highcharts.com/docs/extending-highcharts/extending-highcharts
My problem appears to be close to THIS post (without solution).
Could anybody help me with a Echarts Pie withour colors? I have 2 versions of Echarts, an official and another modified, and the problem occours only with the official version (latest).
I am using data from PHP variables. Official version works when I change data to static numbers, but loose colors with static data. IMPORTANT: I have the correct data in the variables, because the pie appears with correct data, but black & white only.
Thanx any help.
Here is my pie code:
<div id="main2" style="width: 600px;height:400px;"></div></td></tr></table>
<script>
var csimpa = '<?php echo $csimpa[$mescert] ?>';
var cesprega = '<?php echo $cesprega[$mescert] ?>';
var cespdefa = '<?php echo $cespdefa[$mescert] ?>';
var cinta = '<?php echo $cinta[$mescert] ?>';
var cespparta = '<?php echo $cespparta[$mescert] ?>';
// Create a pie chart:
echarts.init(document.getElementById('main2')).setOption({
/*title : {
text: 'CERTID\u00d5ES EXPEDIDAS',
subtext: '2018',
x:'center'
},*/
tooltip : {
trigger: 'item',
formatter: "{a} <br/>{b} : {c} ({d}%)"
},
/*legend: {
orient: 'vertical',
left: 'left',
data: ['CS','CI']
},*/
visualMap: {
show: false,
min: 80,
max: 600,
inRange: {
colorLightness: [0, 1]
}
},
series : [
{
name: 'CERTID\u00d5ES',
type: 'pie',
radius : '55%',
center: ['50%', '60%'],
data:[
{value: csimpa, name:'Simplificada'},
//{value:<? echo $cespoaba[$mescert] ?>, name:'Esp - OAB'},
{value: cesprega, name:'Esp - Existencia'},
{value: cespdefa, name:'Esp - Definir'},
{value: cinta, name:'Inteiro Teor'},
{value: cespparta, name:'Esp - Participa'}
]/*.sort(function (a, b) { return a.value - b.value; }),
roseType: 'radius'*/,
itemStyle: {
emphasis: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
},
animationType: 'scale',
animationEasing: 'elasticOut',
animationDelay: function (idx) {
return Math.random() * 200;
}
}
]
});
</script>
Make sure if the data is coming through dynamically, that it is loaded before the chart finishes loading. You need the data fully loaded so that the chart can use it.
Instead of giving name and value inside the data create an array of objects and define it in a variable and pass it inside series data.
The values used are just for demo
you can use an array of object creation like objectDemo or objectDemo2
let values = [224, 214, 139, 312, 176]
let categories = ['Simplificada', 'Esp - Existencia', 'Esp - Definir', 'Inteiro Teor', 'Esp - Participa']
let objectDemo2 = values.map((d,i) => {
return {
name: categories[i],
value: values[i]
}
})
let objectDemo = [
{value: 224, name:'Simplificada'},
{value: 214, name:'Esp - Existencia'},
{value: 139, name:'Esp - Definir'},
{value: 312, name:'Inteiro Teor'},
{value: 176, name:'Esp - Participa'}
]
option = {
tooltip : {
trigger: 'item',
formatter: "{a} <br/>{b} : {c} ({d}%)"
},
visualMap: {
show: true,
min: 80,
max: 600,
inRange: {
colorLightness: [0, 1]
}
},
series : [
{
name: 'CERTID\u00d5ES',
type: 'pie',
radius : '55%',
center: ['50%', '60%'],
data: objectDemo2/*.sort(function (a, b) { return a.value - b.value; }),
roseType: 'radius'*/,
itemStyle: {
emphasis: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
},
animationType: 'scale',
animationEasing: 'elasticOut',
animationDelay: function (idx) {
return Math.random() * 200;
}
}
]
};
You can see the working of the above code
So I have created a basic line chart using Chartjs. How would I go about changing the color of the points (pointBackgroundColor) depending on the value of the data? For example, if the data point is less than 10 it changes to red, or if the data point is between 10 and 20 it changes to blue?
const CHART = document.getElementById("lineChart");
let lineChart = new Chart(CHART, {
type: 'line',
data: {
labels: ["5/10/2010", "5/11/2010", "5/12/2010", "5/13/2010", "5/14/2010", "5/15/2010", "5/16/2010"],
datasets: [
{
label: "Theta",
fill: false,
lineTension: 0,
backgroundColor: "rgba(75,192,192,0.4)",
borderColor: "rgba(9,31,62)",
borderCapStyle: 'butt',
borderDash: [],
borderDashOffset: 0.0,
borderJoinStyle: 'miter',
pointBorderColor: "rgba(0,191,255)",
pointBackgroundColor: "rgba(0,191,255)",
pointBorderWidth: 5,
pointBorderRadius: 5,
pointHoverBackgroundColor: "rgba(75,192,192,1)",
pointHoverBorderColor: "rgba(220,220,220,1)",
pointHoverBorderWidth: 2,
pointRadius: 1,
pointHitRadius: 10,
data: [15, 28, 11, 3, 34, 65, 20],
}
]
},
options: {
maintainAspectRatio: false,
responsive: true,
legend: {
display: false,
},
scales: {
yAxes:[{
ticks: {
fontColor: "#091F3e",
beginAtZero: true,
steps: 10,
stepSize: 10,
max: 100
},
gridLines: {
display: false
}
}],
xAxes:[{
ticks: {
fontColor: "#091F3e",
fontSize: "10",
},
gridLines: {
display: false
}
}]
}
}
});
You can use a closure on any option and manipulate the returned value according to the context. In the example bellow I'm the pointBackgroundColor is red when the current value is greater then 0 and blue otherwise.
pointBackgroundColor: function (context) {
let value = context.dataset.data[context.dataIndex];
return value > 0
? 'red'
: 'blue';
},
Here is another thing that may help you Change bar color depending on value.
Its original answer from Tot Zam
Adding the code sample in case the link doesn't work.
var colorChangeValue = 50; //set this to whatever is the decidingcolor change value
var dataset = myChart.data.datasets[0];
for (var i = 0; i < dataset.data.length; i++) {
if (dataset.data[i] > colorChangeValue) {
dataset.backgroundColor[i] = chartColors.red;
}
}
myChart.update();
Its about bars background, but you can try work around and find same solution.
There is a way for get color from a number? it's mathematically possible?
I have an array of positive number like this:
array(1, 2, 1000, 564, 30, 113) and I need a color (humanly distinguishable) for each of these. I can use PHP or JS for this purpose.
I need this because i'm using http://www.chartjs.org/ with dynamic values.
edit:
this is an example from chartjs documentation:
<canvas id="myChart" width="400" height="400"></canvas>
<script>
var ctx = document.getElementById("myChart").getContext('2d');
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)'
],
borderColor: [
'rgba(255,99,132,1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(153, 102, 255, 1)',
'rgba(255, 159, 64, 1)'
],
borderWidth: 1
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero:true
}
}]
}
}
});
</script>
In this example are defined 6 bars (red, blue, yellow, green, purple and orange)
In my case this bars are dynamically generated and I don't know how many bars I have to show.
How I can associate a color for each bar? (this color must be the same everytime page refresh)
Using a method from https://stackoverflow.com/a/2262117/2737978 you can convert an integer into an rgb value.
$("#slider1").on("input", function() {
var value = $(this).val();
var rgbColor = intToRGB(value);
$(".number").html(value);
$(".example").css('background-color', rgbColor);
});
var intToRGB = function(value) {
//credit to https://stackoverflow.com/a/2262117/2737978 for the idea of how to implement
var blue = Math.floor(value % 256);
var green = Math.floor(value / 256 % 256);
var red = Math.floor(value / 256 / 256 % 256);
return "rgb(" + red + "," + green + "," + blue + ")";
}
#slider1 {
width: 100%
}
.example {
width: 50px;
height: 50px;
margin 0 auto;
background-color: #000000;
transition: background-color 100ms ease-in;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="slider1" type="range" min="0" max="16777215" step="1" value="0" />
<div class="number">0</div>
<div class="example"></div>
You would just need to use the intToRGB function in your code. Perhaps though if your numbers are all between 1-1000 you might not see such a gradient so would need to adjust the values (either the 256 or adjust the value going in by a certain factor)
---UPDATE
and here is a live example using your graph and a large factor to give a nice range of colour. You would probably want to add some validation into this to ensure the data does not go above the max but here is a quick go.
Here the int to RGB function has been updated to take in a max value that you would like to represent the top colour. On this a scale can more easily be created to give more diversity between ints, depending on your max the colours will be different as they land on a different part of the overall scale of what can be represented.
var intToRGB = function(value, alpha, max) {
var valueAsPercentageOfMax = value / max;
// actual max is 16777215 but represnts white so we will take a max that is
// below this to avoid white
var MAX_RGB_INT = 16600000;
var valueFromMaxRgbInt = Math.floor(MAX_RGB_INT * valueAsPercentageOfMax);
//credit to https://stackoverflow.com/a/2262117/2737978 for the idea of how to implement
var blue = Math.floor(valueFromMaxRgbInt % 256);
var green = Math.floor(valueFromMaxRgbInt / 256 % 256);
var red = Math.floor(valueFromMaxRgbInt / 256 / 256 % 256);
return "rgba(" + red + "," + green + "," + blue + "," + alpha + ")";
}
var data = [12, 19, 3, 5, 2, 3];
var MAX = 19;
var backgroundColors = data.map(function(item) {
return intToRGB(item, 0.8, MAX);
});
var borderColors = data.map(function(item) {
return intToRGB(item, 1, MAX);
});
var ctx = document.getElementById("myChart").getContext('2d');
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: data,
backgroundColor: backgroundColors,
borderColor: borderColors,
borderWidth: 1
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.1.6/Chart.bundle.js"></script>
<canvas id="myChart" width="400" height="400">
</canvas>