Как динамически считывать значения слайдера в функцию в JSXGraph? - PullRequest
1 голос
/ 21 мая 2019

ОБНОВЛЕНИЕ с 22.5.2019

Я сделал более простой пример «не работающего» кода, а также имитировал «рабочий код», определяя K1 и KK локально при рисовании точек, но делал это внутри метода, чтобы они определялись только один раз и имели одинаковые определение для всех точек. Поскольку я хочу, чтобы точки рисовались на параболе, я теперь создаю точки, которые имеют фиксированный радиус от оси вращения и знак, чтобы я мог создать две точки на 180 градусов друг от друга, просто переключая знак с +1 на - 1 при рисовании параметризованных точек в плоскости xz. Тем не менее, ничто не обращается. Вот ссылка на то, что я хочу увидеть (но код уродлив).

Ниже новейшей попытки (с меньшим количеством нарисованных точек, просто чтобы увидеть, работает ли он вообще).

    const board = JXG.JSXGraph.initBoard('jxgbox', {
  boundingbox: [-10, 10, 10, -10],
  axis: true,
  showCopyright: true,
  showNavigation: true,
  pan: false,
  grid: false,

  zoom: {
    factorX: 1.25,
    factorY: 1.25,
    wheel: false
  }
});

//create z axis
var zAxis = board.create('axis', [
  [0, 0],
  [-1, -1]
], {
  ticks: {
    majorHeight: 10,
    drawLabels: false
  }
});

//create direction of view for projections
var cam = [4, 4, 30]; // [x,y,z]
var r = 6.0;
var origin = [0, 0, 0];

// Function for parallel projection
var project = function(crd, cam) {
  var d = -crd[2] / cam[2];
  return [1, crd[0] + d * cam[0], crd[1] + d * cam[1]];
};

//create slider for rotating the parabola
var sRadius = board.create('slider', [
  [1, -8.5],
  [6, -8.5],
  [-10, 0, 10]
], {
  name: 'angle',
  needsRegularUpdate: true
  //snapWidth: 1
});

//create slider for adjusting the angular speed
var sOmega = board.create('slider', [
  [1, -7.5],
  [6, -7.5],
  [0, 2, 10]
], {
  name: 'Omega',
  needsRegularUpdate: true
  //snapWidth: 1,
});

//fix parameters
const g = 9.81 //gravitational acceleration
const h0 = 5 //initial height of the water surface

//define radius from the y-axis for I3 and I4
const R34 = Math.sqrt(2);


// Function for parallel projection
var project = function(crd, cam) {
  var d = -crd[2] / cam[2];
  return [1, crd[0] + d * cam[0], crd[1] + d * cam[1]];
};


//function creates points for drawing conic sections
function PPoint2(radius,sign,namep,fixval) {
    this.R=radius;
  this.S=sign;
  this.Namep=namep;
  this.Fixval=fixval
}


//method for drawing each Point
PPoint2.prototype.draw = function(pp) {
    board.create('point', [function() {
    var K1 = sOmega.Value()*sOmega.Value()/g,
            KK = 1/4*sOmega.Value()*sOmega.Value()/g,
        v = sRadius.Value() * Math.PI * 0.5 / 10.0,
            c = [pp.sign*pp.R*Math.sin(v),K1/2*pp.R*pp.R-KK+h0,pp.sign*pp.R*Math.cos(v)];
    //debugger
    return project(c, cam);
  }
], {
  fixed: this.Fixval,
  name: this.Namep,
  visible: true
  })
}


//create and draw points

var p3 = new PPoint2(0,-1,'p_3','false');
var I_1 = new PPoint2(r,1,'I_1','false');

//debugger


p3.draw(p3)
I_1.draw(I_1)

Оригинальный вопрос ниже:

Я делаю иллюстрацию «аргумента ведра» (как вода принимает форму параболоида в вращающемся ведре) с использованием JSXGraph. я бы хотел А) Имейте форму параболы в зависимости от угловой скорости «Омега» ковша. B) Парабола должна проецироваться из 3D в 2D-изображение, и пользователь может поворачивать ее, используя ползунок.

Для А) мой код использует ползунок «Омега», а для Б) ползунок «Угол».

Значения ползунка считываются в глобальные переменные K1 (коэффициент члена второго порядка параболы) и KK (постоянный член параболы). Затем рисуются пять точек (p3 и I_1-I_4), и парабола должна проходить через эти точки. Точки рисуются с начальными значениями ползунка, но обновление (т.е. скольжение) ползунков не заставляет точки двигаться. Также парабола вообще не нарисована.

Как заставить точки корректировать свои положения в соответствии с текущими значениями ползунка? Функциональность, которую я хочу, реализована в этой скрипке https://jsfiddle.net/ync3pkx5/1/ (но код уродлив, и KK и K1 определены локально для каждой точки, но я хочу, чтобы они были глобальными).

HTML

<div id="jxgbox" class="jxgbox" style="width:500px; height:500px">
</div>

JS

    //create drawing board
const board = JXG.JSXGraph.initBoard('jxgbox', {
  boundingbox: [-10, 10, 10, -10],
  axis: true,
  showCopyright: true,
  showNavigation: true,
  pan: false,
  grid: false,

  zoom: {
    factorX: 1.25,
    factorY: 1.25,
    wheel: false
  }
});

//create z axis
var zAxis = board.create('axis', [
  [0, 0],
  [-1, -1]
], {
  ticks: {
    majorHeight: 10,
    drawLabels: false
  }
});

//create direction of view for projections
var cam = [4, 4, 30]; // [x,y,z]
var r = 6.0;
var origin = [0, 0, 0];

// Function for parallel projection
var project = function(crd, cam) {
  var d = -crd[2] / cam[2];
  return [1, crd[0] + d * cam[0], crd[1] + d * cam[1]];
};

//create slider for rotating the parabola
var sRadius = board.create('slider', [
  [1, -8.5],
  [6, -8.5],
  [-10, 0, 10]
], {
  name: 'angle',
  //snapWidth: 1
});

//create slider for adjusting the angular speed (inactive)
var sOmega = board.create('slider', [
  [1, -7.5],
  [6, -7.5],
  [0, 0, 10]
], {
  name: 'Omega',
  //snapWidth: 1,
});

//fix parameters
var g = 9.81 //gravitational acceleration
var h0 = 5 //initial height of the water surface
//peak coordinates of the fixed parabola
var KK = 1/4*sOmega.Value()*sOmega.Value()*r*r/g; //constant term in the equation of the parabola
var peak = [0, -KK+h0];
//point for mirroring
var pmirr = board.create('point', [0, h0/2], {
  visible: false
});
//define radius from the y-axis for I3 and I4
var R34 = Math.sqrt(2);

//function for projecting poomntson the parabola
var PProject = function(xx,yy,zz) {
    var K1 = sOmega.Value() * sOmega.Value() / g,
      v = sRadius.Value() * Math.PI * 0.5 / 10.0,
      KK = 1/4*sOmega.Value()*sOmega.Value()*r*r/g;
    return project([xx * Math.sin(v), K1/2 * yy * yy-KK+h0, zz * Math.cos(v)], cam);
  }


//p1-p3 are used for drawing the elliptical curves circ1 and prbl2
var p1 = board.create('point', [r, 0], {
  fixed: true,
  name: 'p_1',
  visible: false
});
var p2 = board.create('point', [-r, 0], {
  fixed: true,
  name: 'p_2',
  visible: false
});


var p3 = board.create('point', [
  function() {
    var KK = 1/4*sOmega.Value()*sOmega.Value()*r*r/g,
            c =[0,-KK+h0,0];
    //alert(KK);
    //alert(h0);
    return project(c, cam);
  }
], {
  visible: true,
  name: 'p3'
});

//divisor when drawing points A-C for ellipses and points A2-C2
var div = Math.sqrt(2)

//point variables for drawing circles   
var A = board.create('point', [
  function() {
    var c = [r / div, 0, r / div];
    return project(c, cam);
  }
], {
  name: 'A',
  visible: false
});


var B = board.create('point', [
  function() {
    var c = [-r / div, 0, r / div];
    return project(c, cam);
  }
], {
  name: 'B',
  visible: false
});


var C = board.create('point', [
  function() {
    var c = [r / div, 0, -r / div];
    return project(c, cam);
  }
], {
  name: 'C',
  visible: false
});


//I-I4 are points for drawing the rotating parabola
var I = board.create('point', [
  function() {
    var K1 = sOmega.Value() * sOmega.Value() / g,
      v = sRadius.Value() * Math.PI * 0.5 / 10.0,
      KK = 1/4*sOmega.Value()*sOmega.Value()*r*r/g;
    return project([r * Math.sin(v), K1/2 * r * r-KK+h0, r * Math.cos(v)], cam);
  }
], {
  visible: true,
  name: 'I'
});

var I2 = board.create('point', [
  function() {
    var K1 = sOmega.Value() * sOmega.Value() / g, 
            v = sRadius.Value() * Math.PI * 0.5 / 10.0,
        KK = 1/4*sOmega.Value()*sOmega.Value()*r*r/g;
    return project([-r * Math.sin(v), K1/2 * r * r-KK+h0, -r * Math.cos(v)], cam);
  }
], {
  visible: true,
  name: 'I_2'
});


var I3 = board.create('point', [
  function() {
    var K1 = sOmega.Value() * sOmega.Value() / g,
            v = sRadius.Value() * Math.PI * 0.5 / 10.0,
        KK = 1/4*sOmega.Value()*sOmega.Value()*r*r/g;
    return project([R34 * Math.sin(v), K1/2 * R34 * R34-KK+h0, R34 * Math.cos(v)], cam);
  }
], {
  visible: true,
  name: 'I_3'
});

var I4 = board.create('point', [
  function() {
    var K1 = sOmega.Value() * sOmega.Value() / g, 
            v = sRadius.Value() * Math.PI * 0.5 / 10.0,
        KK = 1/4*sOmega.Value()*sOmega.Value()*r*r/g;
    return project([-R34 * Math.sin(v), K1/2 * R34 * R34-KK+h0, -R34 * Math.cos(v)], cam);
  }
], {
  visible: true,
  name: 'I_4'
});


//draw circle on surface y=0
var circ1 = board.create('conic', [A, B, C, p2, p1]);
//draw a mirror circle of circ1 w.r.t. to pmirr and a small circle that delimits the parabolas
var circ2 = board.create('mirrorelement', [circ1, pmirr]);

//draw the rotating parabola
var prbl2 = board.create('conic', [I, I2, I3, I4, p3], {
  strokeColor: '#CA7291',
  strokeWidth: 2,
  //trace :true
});

debugger;

//add textbox
var txt1 = board.create('text', [3, 7, 'The blue lines delimit the volume of water when Omega = 0 and the red parabola delimits the volume without water as the bucket is rotating (surface h(r)). The water volume is constant, independent of Omega']);

Вот та скрипка, над которой я работаю и хотел бы приступить к работе https://jsfiddle.net/c8tr4dh3/2/

HTML

 <div id="jxgbox" class="jxgbox" style="width:500px; height:500px">
    </div>

JS

    const board = JXG.JSXGraph.initBoard('jxgbox', {
  boundingbox: [-10, 10, 10, -10],
  axis: true,
  showCopyright: true,
  showNavigation: true,
  pan: false,
  grid: false,

  zoom: {
    factorX: 1.25,
    factorY: 1.25,
    wheel: false
  }
});

//create z axis
var zAxis = board.create('axis', [
  [0, 0],
  [-1, -1]
], {
  ticks: {
    majorHeight: 10,
    drawLabels: false
  }
});

//create direction of view for projections
var cam = [4, 4, 30]; // [x,y,z]
var r = 6.0;
var origin = [0, 0, 0];

// Function for parallel projection
var project = function(crd, cam) {
  var d = -crd[2] / cam[2];
  return [1, crd[0] + d * cam[0], crd[1] + d * cam[1]];
};

//create slider for rotating the parabola
var sRadius = board.create('slider', [
  [1, -8.5],
  [6, -8.5],
  [-10, 0, 10]
], {
  name: 'angle',
  needsRegularUpdate: true
  //snapWidth: 1
});

//create slider for adjusting the angular speed (inactive)
var sOmega = board.create('slider', [
  [1, -7.5],
  [6, -7.5],
  [0, 0, 10]
], {
  name: 'Omega',
  needsRegularUpdate: true
  //snapWidth: 1,
});


//fix parameters
var g = 9.81 //gravitational acceleration
var h0 = 5 //initial height of the water surface
var K1 = sOmega.Value() * sOmega.Value() / g; //coeffficient of the quadratic term of the parabola
var KK = 1/4*sOmega.Value()*sOmega.Value()*r*r/g; //constant term in the equation of the parabola
//peak coordinates of the fixed parabola
var peak = [0, -KK+h0];
//slider auxiliary variable
var v = sRadius.Value() * Math.PI * 0.5 / 10.0;


//define radius from the y-axis for I3 and I4
var R34 = Math.sqrt(2);

// Function for parallel projection
var project = function(crd, cam) {
  var d = -crd[2] / cam[2];
  return [1, crd[0] + d * cam[0], crd[1] + d * cam[1]];
};


//function creates points for drawing conic sections
function PPoint(xx, yy,zz,namep,fixval) {
    this.XX=xx;
  this.YY=yy;
  this.ZZ=zz;
  this.Namep=namep;
  this.Fixval=fixval
}


//method for drawing each Point
PPoint.prototype.draw = function(pp) {
    board.create('point', [function() {
    var c = [pp.XX,pp.YY,pp.ZZ];
    //debugger
    return project(c, cam);
  }
], {
  fixed: this.Fixval,
  name: this.Namep,
  visible: true
  })
}

var div=Math.sqrt(2);

//create and draw points
var p3 = new PPoint(0,peak[1],0,'p_3','false');
//debugger
var I_1 = new PPoint(r*Math.sin(v),K1/2*r*r-KK+h0,r*Math.cos(v),'I_1','false');
var I_2 = new PPoint(-r*Math.sin(v),K1/2*r*r-KK+h0,-r*Math.cos(v),'I_2','false');
var I_3 = new PPoint(R34*Math.sin(v),K1/2*R34*R34-KK+h0,R34*Math.cos(v),'I_3','false');
var I_4 = new PPoint(-R34*Math.sin(v),K1/2*R34*R34-KK+h0,-R34*Math.cos(v),'I_4','false');

p3.draw(p3)
I_1.draw(I_1)
I_2.draw(I_2)
I_3.draw(I_3)
//debugger;
I_4.draw(I_4)



//draw the rotating parabola
var prbl = board.create('conic', [[I_1.XX,I_1.YY,I_1.ZZ], [I_2.XX,I_2.YY,I_2.ZZ], [I_3.XX,I_3.YY,I_3.ZZ], [I_4.XX,I_4.YY,I_4.ZZ],[p3.XX,p3.YY,p3.ZZ]], {
  strokeColor: '#CA7291',
  strokeWidth: 2,
  //trace :true
});


//debugger;
//add textbox
var txt1 = board.create('text', [3, 7, 'The blue lines delimit the volume of water when Omega = 0 and the red parabola delimits the volume without water as the bucket is rotating (surface h(r)). The water volume is constant, independent of Omega']);

Синие круги в первой скрипке не являются критическими, их можно добавить к другой позже.

После некоторой отладки у всех родителей параболы есть «isReal: true» в обеих скрипках, но в скрипте, которая не работает, у самой параболы есть «isReal: false», а у работающей скрипки есть «isReal». Правда для параболы. Не уверен, что это актуально.

В нерабочей скрипке я также попытался заключить весь код в "board.on ('mouse, function () {здесь весь код, начиная со строки 59 и далее {), чтобы получить перемещение точек, но это не помогло помощь, точки вообще не нарисованы, даже начальные позиции.

1 Ответ

1 голос
/ 23 мая 2019

Кажется, что в вашем обновленном коде, опубликованном выше, есть очень простая ошибка: значение sign хранится в свойстве pp.S, но вы пытаетесь получить к нему доступ как pp.sign.Я предлагаю использовать следующий код:

function PPoint2(radius,sign,namep,fixval) {
    this.R = radius;
    this.S = sign;
    this.Namep = namep;
    this.Fixval = fixval;
}


//method for drawing each Point
PPoint2.prototype.draw = function() {
    var pp = this;
    this.point = board.create('point', [function() {
        var K1 = sOmega.Value()*sOmega.Value()/g,
            KK = 1/4*sOmega.Value()*sOmega.Value()/g,
            v = sRadius.Value() * Math.PI * 0.5 / 10.0,
            c = [pp.S*pp.R*Math.sin(v),
                 K1/2*pp.R*pp.R-KK+h0,
                 pp.S*pp.R*Math.cos(v)];
        return project(c, cam);
        }], {
    fixed: this.Fixval,
    name: this.Namep,
    visible: true
    });
};

//create and draw points
var p3 = new PPoint2(0,-1,'p_3','false');
var I_1 = new PPoint2(r,1,'I_1','false');

p3.draw();
I_1.draw();
...