我正在谈论的内容的完整演示在这里: https://ggodfrey.github.io/ComplexColor/index.html
我正在尝试创建一个可以尝试使用颜色绘制复值函数的网站。使用复数答案的角度确定色调,并且通过取复数答案的大小的对数然后找到小数部分来确定亮度。从那里,我使用一个函数将HSL转换为RGB,然后将其放入我绘制到画布上的Image
对象中,允许我在每个像素上绘制。
如上页所示,亮度“级别”在对数从一个整数变为另一个整数的位置之间具有“粗糙”边缘。它应该看起来更像this。这个问题与我实际计算亮度的方式或使用javascript画布有关吗?
window.onload = function(){
var EQUATION = '';
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext('2d');
var x_min = -3;
var x_max = 3;
var y_min = -3;
var y_max = 3;
var image = ctx.createImageData(canvas.width, canvas.height);
Complex = function(re, im){
this.re = re;
this.im = im;
}
Complex.prototype.add = function(other){
return new Complex(this.re+other.re, this.im+other.im);
}
Complex.prototype.multiply = function(other){
return new Complex(this.re*other.re-other.im*this.im, this.re*other.im+this.im*other.re);
}
Complex.prototype.power = function(num){
var r = this.magnitude();
var theta = this.angle();
var a = Math.pow(r, num)*Math.cos(num*theta);
var b = Math.pow(r, num)*Math.sin(num*theta);
return new Complex(a, b);
}
Complex.prototype.magnitude = function(){
return Math.pow(Math.pow(this.re, 2) + Math.pow(this.im, 2), 0.5);
}
Complex.prototype.angle = function(){
return Math.atan2(this.im, this.re);
}
Complex.prototype.divide = function(other){
x = new Complex(this.re, this.im);
y = new Complex(other.re, other.im);
x = x.multiply(new Complex(other.re, -other.im));
y = y.multiply(new Complex(other.re, -other.im));
x = new Complex(x.re/y.re, x.im/y.re);
return x;
}
function hslToRgb(h, s, l){ //NOT MY CODE
var r, g, b;
if(s == 0){
r = g = b = l; // achromatic
} else {
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;
}
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
var p = 2 * l - q;
r = hue2rgb(p, q, h + 1/3.0);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1/3.0);
}
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
}
function evaluate(i, j){
var z = new Complex(x_min+j*(x_max-x_min)/canvas.width, y_min+i*(y_max-y_min)/canvas.height);
var num = z.power(2).add(new Complex(-1, 0)).multiply(z.add(new Complex(-2, -1)).power(2));
var den = z.power(2).add(new Complex(2, 4));
var end = num.divide(den);
var color = end.angle()/(2*Math.PI);
var brightness = end.magnitude();
brightness = Math.log(brightness)/Math.log(2) % 1;
return [color, brightness];
}
function main(){
var data = image.data;
if(EQUATION !== null){
var count = 0;
for(var i=0;i<canvas.height;i++){
for(var j=0;j<canvas.width;j++){
var c = evaluate(i, j);
rgb = hslToRgb(c[0], 1, 0.4+c[1]/5);
var r = rgb[0];
var g = rgb[1];
var b = rgb[2];
var c = count*4;
data[c] = r;
data[c+1] = g;
data[c+2] = b;
data[c+3] = 255;
count++;
}
}
image.data = data;
ctx.putImageData(image, 0, 0);
}
}
main();
function getMousePos(canvas, evt){
var rect = canvas.getBoundingClientRect();
return {x: (evt.clientX-rect.left)/(rect.right-rect.left)*canvas.width,
y: (evt.clientY-rect.top)/(rect.bottom-rect.top)*canvas.height};
}
document.getElementById("submit").addEventListener("mousedown", function(event){
EQUATION = document.getElementById("equation").innerHTML;
var x = main();
})
document.getElementById("canvas").addEventListener("mousemove", function(event){
var loc = getMousePos(canvas, event);
document.getElementById('x').innerHTML = Math.round(loc.x*100)/100;
document.getElementById('y').innerHTML = Math.round(loc.y*100)/100;
document.getElementById('brightness').innerHTML = evaluate(loc.y, loc.x)[1];
})
}
<head>
<title>Complex Color</title>
<meta charset="utf-8"></head>
<body>
<input id="equation" type="text">Type Equation</input><button id="submit">Submit</button><br>
<canvas id="canvas" style="width:500px;height:500px"></canvas><p> <span id="x"></span>, <span id="y"></span>, <span id="brightness"></span></p>
</body>
答案 0 :(得分:2)
假设公式是正确的:
增加画布的bitmap resolution 并使用较小的CSS大小来引入平滑 - 或 - 实现手动消除锯齿。这是因为您逐个像素地写入,绕过了抗锯齿。
将饱和度降低至约80%:rgb = hslToRgb(c[0], 0.8, 0.4 + c[1] / 5);
。 100%通常会在屏幕上产生过饱和的外观图像。打印虽然使用100%。
var EQUATION = '';
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext('2d');
var x_min = -3;
var x_max = 3;
var y_min = -3;
var y_max = 3;
var image = ctx.createImageData(canvas.width, canvas.height);
Complex = function(re, im) {
this.re = re;
this.im = im;
}
Complex.prototype.add = function(other) {
return new Complex(this.re + other.re, this.im + other.im);
}
Complex.prototype.multiply = function(other) {
return new Complex(this.re * other.re - other.im * this.im, this.re * other.im + this.im * other.re);
}
Complex.prototype.power = function(num) {
var r = this.magnitude();
var theta = this.angle();
var a = Math.pow(r, num) * Math.cos(num * theta);
var b = Math.pow(r, num) * Math.sin(num * theta);
return new Complex(a, b);
}
Complex.prototype.magnitude = function() {
return Math.pow(Math.pow(this.re, 2) + Math.pow(this.im, 2), 0.5);
}
Complex.prototype.angle = function() {
return Math.atan2(this.im, this.re);
}
Complex.prototype.divide = function(other) {
x = new Complex(this.re, this.im);
y = new Complex(other.re, other.im);
x = x.multiply(new Complex(other.re, -other.im));
y = y.multiply(new Complex(other.re, -other.im));
x = new Complex(x.re / y.re, x.im / y.re);
return x;
}
function hslToRgb(h, s, l) { //NOT MY CODE
var r, g, b;
if (s == 0) {
r = g = b = l; // achromatic
} else {
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;
}
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
var p = 2 * l - q;
r = hue2rgb(p, q, h + 1 / 3.0);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1 / 3.0);
}
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
}
function evaluate(i, j) {
var z = new Complex(x_min + j * (x_max - x_min) / canvas.width, y_min + i * (y_max - y_min) / canvas.height);
var num = z.power(2).add(new Complex(-1, 0)).multiply(z.add(new Complex(-2, -1)).power(2));
var den = z.power(2).add(new Complex(2, 4));
var end = num.divide(den);
var color = end.angle() / (2 * Math.PI);
var brightness = end.magnitude();
brightness = Math.log(brightness) / Math.log(2) % 1;
return [color, brightness];
}
function main() {
var data = image.data;
if (EQUATION !== null) {
var count = 0;
for (var i = 0; i < canvas.height; i++) {
for (var j = 0; j < canvas.width; j++) {
var c = evaluate(i, j);
rgb = hslToRgb(c[0], 0.8, 0.4 + c[1] / 5);
var r = rgb[0];
var g = rgb[1];
var b = rgb[2];
var c = count * 4;
data[c] = r;
data[c + 1] = g;
data[c + 2] = b;
data[c + 3] = 255;
count++;
}
}
image.data = data;
ctx.putImageData(image, 0, 0);
}
}
main();
#canvas {width:500px;height:500px}
<canvas id="canvas" width=1000 height=1000></canvas>
答案 1 :(得分:0)
CSS'width
和height
与同名的canvas元素的属性不同 - 它们只是将画布拉伸到给定的大小(另请参阅this answer) 。因此,canvas.width === 300
和canvas.height === 150
是默认值。这种低分辨率会立即产生问题。这是你的相同代码,只是画布'属性设置正确,而不是使用不正确的CSS:
window.onload = function(){
var EQUATION = '';
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext('2d');
var x_min = -3;
var x_max = 3;
var y_min = -3;
var y_max = 3;
var image = ctx.createImageData(canvas.width, canvas.height);
Complex = function(re, im){
this.re = re;
this.im = im;
}
Complex.prototype.add = function(other){
return new Complex(this.re+other.re, this.im+other.im);
}
Complex.prototype.multiply = function(other){
return new Complex(this.re*other.re-other.im*this.im, this.re*other.im+this.im*other.re);
}
Complex.prototype.power = function(num){
var r = this.magnitude();
var theta = this.angle();
var a = Math.pow(r, num)*Math.cos(num*theta);
var b = Math.pow(r, num)*Math.sin(num*theta);
return new Complex(a, b);
}
Complex.prototype.magnitude = function(){
return Math.pow(Math.pow(this.re, 2) + Math.pow(this.im, 2), 0.5);
}
Complex.prototype.angle = function(){
return Math.atan2(this.im, this.re);
}
Complex.prototype.divide = function(other){
x = new Complex(this.re, this.im);
y = new Complex(other.re, other.im);
x = x.multiply(new Complex(other.re, -other.im));
y = y.multiply(new Complex(other.re, -other.im));
x = new Complex(x.re/y.re, x.im/y.re);
return x;
}
function hslToRgb(h, s, l){ //NOT MY CODE
var r, g, b;
if(s == 0){
r = g = b = l; // achromatic
} else {
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;
}
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
var p = 2 * l - q;
r = hue2rgb(p, q, h + 1/3.0);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1/3.0);
}
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
}
function evaluate(i, j){
var z = new Complex(x_min+j*(x_max-x_min)/canvas.width, y_min+i*(y_max-y_min)/canvas.height);
var num = z.power(2).add(new Complex(-1, 0)).multiply(z.add(new Complex(-2, -1)).power(2));
var den = z.power(2).add(new Complex(2, 4));
var end = num.divide(den);
var color = end.angle()/(2*Math.PI);
var brightness = end.magnitude();
brightness = Math.log(brightness)/Math.log(2) % 1;
return [color, brightness];
}
function main(){
var data = image.data;
if(EQUATION !== null){
var count = 0;
for(var i=0;i<canvas.height;i++){
for(var j=0;j<canvas.width;j++){
var c = evaluate(i, j);
rgb = hslToRgb(c[0], 1, 0.4+c[1]/5);
var r = rgb[0];
var g = rgb[1];
var b = rgb[2];
var c = count*4;
data[c] = r;
data[c+1] = g;
data[c+2] = b;
data[c+3] = 255;
count++;
}
}
image.data = data;
ctx.putImageData(image, 0, 0);
}
}
main();
function getMousePos(canvas, evt){
var rect = canvas.getBoundingClientRect();
return {x: (evt.clientX-rect.left)/(rect.right-rect.left)*canvas.width,
y: (evt.clientY-rect.top)/(rect.bottom-rect.top)*canvas.height};
}
document.getElementById("submit").addEventListener("mousedown", function(event){
EQUATION = document.getElementById("equation").innerHTML;
var x = main();
})
document.getElementById("canvas").addEventListener("mousemove", function(event){
var loc = getMousePos(canvas, event);
document.getElementById('x').innerHTML = Math.round(loc.x*100)/100;
document.getElementById('y').innerHTML = Math.round(loc.y*100)/100;
document.getElementById('brightness').innerHTML = evaluate(loc.y, loc.x)[1];
})
}
<input id="equation" type="text">Type Equation</input>
<canvas id="canvas" width="500" height="500"></canvas>
<button id="submit">Submit</button><br><span id="x"></span>, <span id="y"></span>, <span id="brightness"></span></p>
之后,如另一个答案所述,提高分辨率和“拉伸更小”(一种超级采样)有助于进一步,但不是核心问题。