Skip to content

Commit

Permalink
gradient color range skips first color (#33)
Browse files Browse the repository at this point in the history
  • Loading branch information
Adrinlol authored Jul 2, 2024
1 parent a23aac3 commit 7ac18fd
Show file tree
Hide file tree
Showing 4 changed files with 232 additions and 196 deletions.
30 changes: 24 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,18 @@ Using 2 colors and default (10) midpoints to generate an array of hex color valu
import Gradient from "javascript-color-gradient";

const gradientArray = new Gradient()
.setColorGradient("#3F2CAF", "e9446a")
.setColorGradient("#3F2CAF", "#e9446a")
.getColors();

console.log(gradientArray);
// ["#502ea8", "#6131a1", "#72339a", "#833693", "#94388d", "#a53a86", "#b63d7f", "#c73f78", "#d84271", "#e9446a"]

[
'#3f2caf', '#522fa7',
'#6531a0', '#783498',
'#8b3790', '#9d3989',
'#b03c81', '#c33f79',
'#d64172', '#e9446a'
]
```

Using 4 colors and 20 midpoints to generate an array of hex color values :
Expand All @@ -64,7 +71,18 @@ const gradientArray = new Gradient()
.getColors();

console.log(gradientArray);
// ["#5930a5", "#72339a", "#8c3790", "#a53a86", "#bf3e7b", "#d84271", "#e94b6c", "#ea5f70", "#ea7375", "#eb8779", …]

[
'#3f2caf', '#5a30a4',
'#753499', '#90378e',
'#aa3b83', '#c53f79',
'#e9526d', '#ea6772',
'#eb7c77', '#eb917b',
'#eca680', '#e6c588',
'#cfb989', '#b9ad89',
'#a3a18a', '#8d958a',
'#76898b', '#607D8B'
]
```

Using two colors and default (10) midpoints to return single hex color value corresponding to the provided index:
Expand All @@ -73,12 +91,12 @@ Using two colors and default (10) midpoints to return single hex color value cor
import Gradient from "javascript-color-gradient";

const colorAtIndexTwo = new Gradient()
.setColorGradient("#3F2CAF", "e9446a")
.setMidpoint(20)
.setColorGradient("#3F2CAF", "#e9446a")
.getColor(2);

console.log(colorAtIndexTwo);
// #5930a5

#6531a0
```

## Contributing
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "javascript-color-gradient",
"version": "2.4.4",
"version": "2.5.0",
"description": "javascript-color-gradient is a lightweight JavaScript library, used to generate an array of color gradients by providing start and finish colors, as well as the required number of midpoints. ",
"main": "src/index.js",
"scripts": {
Expand Down
282 changes: 134 additions & 148 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,159 +1,145 @@
class GradientColor {
constructor(startColor = "", endColor = "", minNum = 0, maxNum = 10) {
this.setColorGradient = (colorStart, colorEnd) => {
startColor = getHexColor(colorStart);
endColor = getHexColor(colorEnd);
};

this.setMidpoint = (minNumber, maxNumber) => {
minNum = minNumber;
maxNum = maxNumber;
};

this.getColor = (numberValue) => {
if (numberValue) {
return (
"#" +
generateHex(
numberValue,
startColor.substring(0, 2),
endColor.substring(0, 2)
) +
generateHex(
numberValue,
startColor.substring(2, 4),
endColor.substring(2, 4)
) +
generateHex(
numberValue,
startColor.substring(4, 6),
endColor.substring(4, 6)
)
);
}
};
constructor() {
this.minNum = 0;
this.maxNum = 10;
this.startHex = "";
this.endHex = "";
}

const generateHex = (number, start, end) => {
if (number < minNum) {
number = minNum;
} else if (number > maxNum) {
number = maxNum;
}
setColorGradient(colorStart, colorEnd) {
if (!colorStart.startsWith("#") || !colorEnd.startsWith("#")) {
throw new Error('Colors must be in hexadecimal format starting with "#"');
}

this.startHex = this.validateAndExpandHex(colorStart);
this.endHex = this.validateAndExpandHex(colorEnd);
}

validateAndExpandHex(hex) {
if (hex.length === 4) {
return "#" + hex[1] + hex[1] + hex[2] + hex[2] + hex[3] + hex[3];
} else if (hex.length === 7) {
return hex;
} else {
throw new Error(
"Invalid color format. Please use full hex color values (e.g., #3f2caf) instead of abbreviated formats",
);
}
}

setMidpoint(minNumber = 0, maxNumber = 10) {
this.minNum = minNumber;
this.maxNum = maxNumber;
}

getColor(numberValue) {
if (numberValue === undefined) return;

return (
"#" +
this.generateHex(
numberValue,
this.startHex.substring(1, 3),
this.endHex.substring(1, 3),
) +
this.generateHex(
numberValue,
this.startHex.substring(3, 5),
this.endHex.substring(3, 5),
) +
this.generateHex(
numberValue,
this.startHex.substring(5, 7),
this.endHex.substring(5, 7),
)
);
}

const midPoint = maxNum - minNum;
const startBase = parseInt(start, 16);
const endBase = parseInt(end, 16);
const average = (endBase - startBase) / midPoint;
const finalBase = Math.round(average * (number - minNum) + startBase);
const balancedFinalBase =
finalBase < 16 ? "0" + finalBase.toString(16) : finalBase.toString(16);
return balancedFinalBase;
};

const getHexColor = (color) => {
return color.substring(color.length - 6, color.length);
};
generateHex(number, start, end) {
if (number < this.minNum) number = this.minNum;
else if (number > this.maxNum) number = this.maxNum;

const midPoint = this.maxNum - this.minNum;
const startBase = parseInt(start, 16);
const endBase = parseInt(end, 16);
const average = (endBase - startBase) / midPoint;
const finalBase = Math.round(average * (number - this.minNum) + startBase);
return finalBase.toString(16).padStart(2, "0");
}
}

class Gradient {
constructor(
colorGradients = "",
maxNum = 10,
colors = ["", ""],
intervals = []
) {
const setColorGradient = (gradientColors) => {
if (gradientColors.length < 2) {
throw new Error(
`setColorGradient should have more than ${gradientColors.length} color`
);
} else {
const increment = maxNum / (gradientColors.length - 1);
const firstColorGradient = new GradientColor();
const lower = 0;
const upper = 0 + increment;
firstColorGradient.setColorGradient(
gradientColors[0],
gradientColors[1]
);
firstColorGradient.setMidpoint(lower, upper);
colorGradients = [firstColorGradient];
intervals = [
{
lower,
upper,
},
];

for (let i = 1; i < gradientColors.length - 1; i++) {
const gradientColor = new GradientColor();
const lower = 0 + increment * i;
const upper = 0 + increment * (i + 1);
gradientColor.setColorGradient(
gradientColors[i],
gradientColors[i + 1]
);
gradientColor.setMidpoint(lower, upper);
colorGradients[i] = gradientColor;
intervals[i] = {
lower,
upper,
};
}
colors = gradientColors;
}
};

this.setColorGradient = (...gradientColors) => {
setColorGradient(gradientColors);
return this;
};

this.getColors = () => {
const gradientColorsArray = [];
for (let j = 0; j < intervals.length; j++) {
const interval = intervals[j];
const start = interval.lower === 0 ? 1 : Math.ceil(interval.lower);
const end =
interval.upper === maxNum
? interval.upper + 1
: Math.ceil(interval.upper);
for (let i = start; i < end; i++) {
gradientColorsArray.push(colorGradients[j].getColor(i));
}
}
return gradientColorsArray;
};

this.getColor = (numberValue) => {
if (isNaN(numberValue)) {
throw new TypeError(`getColor should be a number`);
} else if (numberValue <= 0) {
throw new TypeError(`getColor should be greater than ${numberValue}`);
} else {
const toInsert = numberValue + 1;
const segment = (maxNum - 0) / colorGradients.length;
const index = Math.min(
Math.floor((Math.max(numberValue, 0) - 0) / segment),
colorGradients.length - 1
);
return colorGradients[index].getColor(toInsert);
}
};

this.setMidpoint = (maxNumber) => {
if (!isNaN(maxNumber) && maxNumber >= 0) {
maxNum = maxNumber;
setColorGradient(colors);
} else if (maxNumber <= 0) {
throw new RangeError(`midPoint should be greater than ${maxNumber}`);
} else {
throw new RangeError("midPoint should be a number");
constructor() {
this.maxNum = 10;
this.colors = [];
this.colorGradients = [];
this.intervals = [];
}

setColorGradient(...gradientColors) {
if (gradientColors.length < 2) {
throw new RangeError(`setColorGradient requires at least 2 colors`);
}

const increment = (this.maxNum - 1) / (gradientColors.length - 1);
this.colorGradients = [];
this.intervals = [];

for (let i = 0; i < gradientColors.length - 1; i++) {
const gradientColor = new GradientColor();
const lower = increment * i;
const upper = increment * (i + 1);
gradientColor.setColorGradient(gradientColors[i], gradientColors[i + 1]);
gradientColor.setMidpoint(lower, upper);
this.colorGradients.push(gradientColor);
this.intervals.push({ lower, upper });
}
this.colors = gradientColors;
return this;
}

getColors() {
const gradientColorsArray = [];
const numColors = this.maxNum + 1;

for (let j = 0; j < this.intervals.length; j++) {
const { lower, upper } = this.intervals[j];
const start = j === 0 ? 0 : Math.ceil(lower);
const end = j === this.intervals.length - 1 ? Math.ceil(upper) : Math.floor(upper);

for (let i = start; i < end; i++) {
gradientColorsArray.push(this.colorGradients[j].getColor(i));
}
return this;
};
}

gradientColorsArray.push(this.colors[this.colors.length - 1]);
return gradientColorsArray.slice(0, numColors);
}

getColor(numberValue) {
if (isNaN(numberValue)) {
throw new TypeError(`getColor requires a numeric value`);
}
if (numberValue <= 0) {
throw new RangeError(`getColor value should be greater than 0`);
}

const segment = (this.maxNum + 1) / this.colorGradients.length;
const index = Math.min(Math.floor(numberValue / segment), this.colorGradients.length - 1);
return this.colorGradients[index].getColor(numberValue);
}

setMidpoint(maxNumber = 10) {
if (isNaN(maxNumber) || maxNumber < this.colors.length) {
throw new RangeError(
`setMidpoint should be a number greater than or equal to the number of colors`,
);
}

this.maxNum = maxNumber ;
this.setColorGradient(...this.colors);
return this;
}
}

module.exports = Gradient;
module.exports = Gradient;
Loading

0 comments on commit 7ac18fd

Please sign in to comment.