So I have a project in GameMaker, which has a chatbox. The messages for this are stored in an array. I would like to be able to scroll through this array, so I can view earlier chat messages.
This is what I currently have:
Create Event
chatLog[0] = "";
chatIndex = 0;
Step Event
if (chatIndex > 0) {
if (mouse_wheel_down()) {
chatIndex--;
}
}
if (chatIndex < array_length_1d(chatLog) - 1) {
if (mouse_wheel_up()) {
chatIndex++;
}
}
var _maxLines = 5;
for (i = 0; i < _maxLines; i++) {
if (i > (array_length_1d(chatLog) - 1)) { exit; }
var _chatLength = array_length_1d(chatLog) - 1;
draw_text(0, 50 - chatHeight, chatLog[_chatLength - i + chatIndex]);
}
First, for convenience of being able to add messages to front / remove them from the back (once there are too many), let's suppose that the log is a list, item 0 being the newest message,
chatLog = ds_list_create();
chatIndex = 0;
for (var i = 1; i <= 15; i++) {
ds_list_insert(chatLog, 0, "message " + string(i));
}
then, the Step Draw event can use information from the list to clamp scroll offset range and draw items:
var maxLines = 5;
// scrolling:
var dz = (mouse_wheel_up() - mouse_wheel_down()) * 3;
if (dz != 0) {
chatIndex = clamp(chatIndex + dz, 0, ds_list_size(chatLog) - maxLines);
}
// drawing:
var i = chatIndex;
var _x = 40;
var _y = 200;
repeat (maxLines) {
var m = chatLog[|i++];
if (m == undefined) break; // reached the end of the list
draw_text(_x, _y, m);
_y -= string_height(m); // draw the next item above the current one
}
live demo
My ambition is to have a Dictionary that contains (among other things) an array and being able to get out the values of that array.
var total: Int = 0;
let dice:[NSTextField:NSArray] = [
d4Amount:[d4OE, 4],
d6Amount:[d6OE, 6],
];
for (die, dieArray) in dice
{
let button:NSButton = dieArray[0] as! NSButton;
let num:Int = dieArray[1] as! Int;
total += DoRoll(die, oe: button, max: num);
}
In the above the line "let button:NSButton = dieArray[0]..." get's the error Thread 1: signal SIGABRT and the program fails.
First I only had the line:
total += DoRoll(die, oe: dieArray[0] as! NS Button, max: dieArray[1] as! Int);
Which didn't either work (quite obviously), but however when I do this, it works...
total += DoRoll(d4Amount, oe: d4OE, max: 4);
It works perfectly.
Any ideas??
The function DoRoll looks like this (which should not be relevant):
private func DoRoll(amount: NSTextField, oe: NSButton, max: Int) -> Int
{
let nrRolls: Int! = Int(amount.stringValue);
var total: Int = 0;
if(nrRolls != nil && nrRolls != 0)
{
OutputText.string = OutputText.string! + "Now rolling d" + String(max) + ": ";
for(var i: Int = 0; i < nrRolls; i++)
{
var randomNr: Int, specialMax: Int;
var textStr: String = "";
specialMax = max;
if(max >= 100)
{
if(max > 100)
{
specialMax = 995;
}
else if(max > 99)
{
specialMax = 95;
}
else
{
specialMax = max - 1;
}
}
repeat
{
randomNr = Int(arc4random_uniform(UInt32(max))) + 1;
total += randomNr;
if(textStr != "") { textStr = textStr + "+"; }
textStr = textStr + String(randomNr);
} while(oe.state == NSOnState && randomNr >= specialMax)
OutputText.string = OutputText.string! + textStr + " ";
}
OutputText.string = OutputText.string! + "\n";
}
return total;
}
I now know what I did wrong.
This is not at all a case of error in the code above but in the naming of items in the project. I had several different D4Amount in the same project in the View and thus that was why it crashed.
Sorry to bother you.
I'm currently writing a visualization via D3 and I hope you can help me out.
To get an idea of what I'm making you can view this link: https://dl.dropboxusercontent.com/u/56480311/Data-visualization/index.html
I'm facing two problems: the first is that I can't seem to place .csv data in a 2D array. I found multiplie tutorials about placing it in a normal array but the only solution I came up with if your data is in a table, is to use a 2D array. I couldn't find how to do this so what I thought would help:
var lines = []; //define lines as an array
//retrieve data from .csv file
d3.csv("https://dl.dropboxusercontent.com/u/56480311/Data-visualization/growth-prep.csv", function(data) {
lines = data.map(function(d) {
return d;
});
});
//create 2D array named myArray
var myArray = new Array(10);
for (var i = 0; i < 10; i++) {
myArray[i] = new Array(18);
}
//place each value of .csv file into myArray
for (var j = 0; j < lines.length; j++) {
var values = lines[j].split(";");
for (var k = 0; k < values.length; k++) {
myArray[k][j] = values[k];
}
}
This code doesn't work, however. Console keeps saying that the arrays are undefined and they're empty.
A second problem I'm facing is in visualizing the data. I sum three values that are next to each other (so for example dataset[0][0] + dataset[0][1] + dataset[0][2]). I draw this value as the width of a rectangle. On top of that, I want to draw three different rectangles each with the value of one of three. So in this case there is one rectangle consisting of dataset[0][0] + dataset[0][1] + dataset[0][2] and on top there is a rectangle showing data dataset[0][0], one showing data dataset[0][1] and a third showing data dataset[0][2]. I want the three smaller ones only to appear once the mouse hovers over the 'sum' / parent rectangle.
If you view the link you can see what I mean. Everything is already there, only the three smaller rectangles have opacity 0 so you don't see them yet (but you can find them via inspect elements).
I figured I could do this by setting the opacity of the three rectangles to 0 and to 1 once the mouse hovers. The best solution to me would be to place the three rectangles into one kind of div. Once the mouse hovers over it, its opacity is 1. Only I can't figure out how to easily give different class names without having to do it by hand for each rectangle separately. Does anyone know how to do this or else have a better solution to change the opacity of all three rectangles once the mouse hovers over the 'bigger' rectangle?
This is the code:
var dataset = [[6,6,3,3,3,0,6,6,0,12,6,6,0,0,18,6,3,3],[3,0,0,6,3,0,3,3,0,9,3,0,0,0,18,6,6,6],[3,0,3,6,3,3,6,0,3,9,6,3,0,0,15,6,6,6],[6,6,3,3,0,3,6,6,6,12,6,6,0,0,18,6,6,3],[6,6,0,6,0,0,6,6,6,12,6,6,0,0,24,6,6,0],[3,6,3,6,3,3,6,6,3,3,0,0,0,0,15,3,9,6],[3,3,0,3,0,3,3,3,3,9,3,0,0,0,15,6,3,9],[0,0,0,3,0,6,6,3,3,3,0,3,0,0,24,6,12,6],[6,6,3,6,0,0,9,9,6,12,6,6,0,0,15,3,3,3],[6,6,0,6,3,0,6,6,0,9,6,3,0,0,9,3,6,0]];
var h = 800;
var w = 800;
//create svg of 800x800px
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
var xPos = 150;
for (var k = 0; k < 10; k++) { //loop through lines of array
var yPos = 40 + k*80;
for (var j = 0; j < 18; j++) { //loop through rows of array
var count = j + 1;
//assign data of three boxes to value1/value2/value3 with which we will later on draw three separate rectangles to visualize the data
if (count == 1 || count == 4 || count == 7 || count == 10 || count == 13 || count == 16) {
var value1 = dataset[k][j];
}
if (count == 2 || count == 5 || count == 8 || count == 11 || count == 14 || count == 17) {
var value2 = dataset[k][j];
}
if (count == 3 || count == 6 || count == 9 || count == 12 || count == 15 || count == 18) {
var value3 = dataset[k][j];
}
if (count % 3 ==0) {
var sum = dataset[k][j] + dataset[k][j-1] + dataset[k][j-2]; //count the three values to also draw one bigger rectangle of their sum
var rectangle = svg.append("rect")
.attr("x", xPos)
.attr("y", yPos)
.attr("width", sum*5)
.attr("height", 20)
.attr("fill", function(d) {
if (count == 3) {
return "LightSeaGreen";
}
else if (count == 6) {
return "MediumSeaGreen";
}
else if (count == 9) {
return "MediumSpringGreen";
}
else if (count == 12) {
return "LimeGreen";
}
else if (count == 15) {
return "ForestGreen"
}
else if (count == 18) {
return "GreenYellow"
}
});
for (var l = 0; l < 3; l++) { //draw three 'sub' rectangles on top of the one 'sum' rectangle. they should appear when the mouse hovers over their 'sum' rectangle
var rectangle2 = svg.append("rect")
.attr("class", "sqr")
.attr("x", function() {
if (l == 0) {
return xPos;
} else if (l == 1) {
return xPos + value1*5;
} else if (l == 2) {
return xPos + (value1+value2)*5;
}
})
.attr("y", yPos)
.attr("width", function() {
if (l == 0) {
return value1*5;
} else if (l == 1) {
return value2*5;
} else if (l == 2) {
return value3*5;
}
})
.attr("height", 20)
.attr("fill", function() {
if (l == 0) {
return "SteelBlue";
} else if (l == 1) {
return "aquamarine";
} else if (l == 2) {
return "SkyBlue";
}
})
.attr("opacity", 0); //in first instance the rectangles are not visible. Opacity should turn to 1 when the mouse hovers over their according div
}
if (sum > 0) {
xPos = xPos + sum*5 + 5;
}
}
}
xPos = 150;
}
I want to be able to color each bar with a different color in a gradient way like the folloing image
Can any body tell me how to do that?
This is using ChartJS 2.4.0. http://www.chartjs.org/docs/latest/charts/bar.html
Given x number of datapoints in your Bar Graph, you'll need to generate an array of x number of colors: one color per each datapoint.
data: [10,20,30,40,50,60,70,80],
backgroundColor: ["#ded21e", "#cbd026", "#b8ce2d", "#a5cc35", "#93cb3c", "#80c944", "#6dc74b", "#5ac553"]
Here is a CodePen: https://codepen.io/pgardner/pen/GyeBLW
Credit goes to Neil McCallion, whose CodePen here does much of the legwork: https://codepen.io/njmcode/pen/axoyD
Here is the essential function:
function color() {
// Converts a #ffffff hex string into an [r,g,b] array
function hex2rgb(hex) {
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? [
parseInt(result[1], 16),
parseInt(result[2], 16),
parseInt(result[3], 16)
] : null;
}
// Inverse of the above
function rgb2hex(rgb) {
return '#' + ((1 << 24) + (rgb[0] << 16) + (rgb[1] << 8) + rgb[2]).toString(16).slice(1);
}
// Interpolates two [r,g,b] colors and returns an [r,g,b] of the result
// Taken from the awesome ROT.js roguelike dev library at
// https://github.com/ondras/rot.js
function _interpolateRgb(color1, color2, factor) {
if (arguments.length < 3) { factor = 0.5; }
let result = color1.slice();
for (let i=0;i<3;i++) {
result[i] = Math.round(result[i] + factor*(color2[i]-color1[i]));
}
return result;
}
function rgb2hsl(color) {
const r = color[0]/255;
const g = color[1]/255;
const b = color[2]/255;
const max = Math.max(r, g, b), min = Math.min(r, g, b);
let h, s, l = (max + min) / 2;
if (max == min) {
h = s = 0; // achromatic
} else {
let d = max - min;
s = (l > 0.5 ? d / (2 - max - min) : d / (max + min));
switch(max) {
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6;
}
return [h, s, l];
}
function hue2rgb(p, q, t) {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1/6) return p + (q - p) * 6 * t;
if (t < 1/2) return q;
if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
return p;
}
function hsl2rgb(color) {
let l = color[2];
if (color[1] == 0) {
l = Math.round(l*255);
return [l, l, l];
} else {
let s = color[1];
let q = (l < 0.5 ? l * (1 + s) : l + s - l * s);
let p = 2 * l - q;
let r = hue2rgb(p, q, color[0] + 1/3);
let g = hue2rgb(p, q, color[0]);
let b = hue2rgb(p, q, color[0] - 1/3);
return [Math.round(r*255), Math.round(g*255), Math.round(b*255)];
}
}
function _interpolateHsl(color1, color2, factor) {
if (arguments.length < 3) { factor = 0.5; }
let hsl1 = rgb2hsl(color1);
let hsl2 = rgb2hsl(color2);
for (let i=0;i<3;i++) {
hsl1[i] += factor*(hsl2[i]-hsl1[i]);
}
return hsl2rgb(hsl1);
}
function generateGradient(color1, color2, total, interpolation) {
const colorStart = typeof color1 === 'string' ? hex2rgb(color1) : color1;
const colorEnd = typeof color2 === 'string' ? hex2rgb(color2) : color2;
// will the gradient be via RGB or HSL
switch(interpolation) {
case 'rgb':
return colorsToGradientRgb(colorStart, colorEnd, total);
case 'hsl':
return colorsToGradientHsl(colorStart, colorEnd, total);
default:
return false;
}
}
function colorsToGradientRgb(startColor, endColor, steps) {
// returns array of hex values for color, since rgb would be an array of arrays and not strings, easier to handle hex strings
let arrReturnColors = [];
let interimColorRGB;
let interimColorHex;
const totalColors = steps;
const factorStep = 1 / (totalColors - 1);
for (let idx = 0; idx < totalColors; idx++) {
interimColorRGB = _interpolateRgb(startColor, endColor, factorStep * idx);
interimColorHex = rgb2hex(interimColorRGB);
arrReturnColors.push(interimColorHex);
}
return arrReturnColors;
}
function colorsToGradientHsl(startColor, endColor, steps) {
// returns array of hex values for color, since rgb would be an array of arrays and not strings, easier to handle hex strings
let arrReturnColors = [];
let interimColorRGB;
let interimColorHex;
const totalColors = steps;
const factorStep = 1 / (totalColors - 1);
for (let idx = 0; idx < totalColors; idx++) {
interimColorRGB = _interpolateHsl(startColor, endColor, factorStep * idx);
interimColorHex = rgb2hex(interimColorRGB);
arrReturnColors.push(interimColorHex);
}
return arrReturnColors;
}
return {
generateGradient
};
}
Given 2 colors '#ded21e' and '#5ac553', you would call the function in this manner:
let arrBarGraphColors = color().generateGradient('#ded21e', '#5ac553', data.length, 'rgb');
Specify between 'rgb' and 'hsl'. The linked CodePens should give you an idea of the differences between the two.