Equation Parser for Graphing in Javascript or Jquery - parsing

I want an Equation Parser so that it can solve for x as well as for y to get an array of points (i.e. x and y).
Example:
Let us assume a user enter the expression:
var expression ="x + y = 1";
Now let us say I know the domain and ranges:
var xMin = -10, yMin = -10, xMax = 10 ,yMax = 10;
So what I want is the plotting points between these ranges and domain.
Means I want an array or two dimensional array holding the value of x coordinates and y coordinates.
Please can anybody suggest me how to get up to here using any algorithm or a program.
Thanks in advance!

After parsing the equation to standard form, you could substitute different values depending on number of points required from the given range for one unknown variable i.e. for this example, say x and get corresponding y values.

Try this. "parser.js" can be downloaded from here
https://github.com/silentmatt/js-expression-eval/tree/master
Take a look at this as well,might be helpful
http://silentmatt.com/javascript-function-plotter/
<html>
<head>
<script src="parser.js"></script>
<script src="http://code.jquery.com/jquery-2.1.4.min.js"></script>
<script>
$( document ).ready(function() {
var xMin = -10, yMin = -10, xMax = 10 ,yMax = 10;
var rangeIncrement=1;
var equation="";
var points=[];
$( "#btnDraw" ).click(function() {
points=[];
equation=$("#txtequation").val()
expr = Parser.parse(equation);
i=0;
for(i=xMin ;i<=xMax ;i+=rangeIncrement)
{
result=expr.evaluate({ x: i});
points.push([i, result]);
}
$( "#resultPoints" ).empty();
$.each(points, function( index, value ) {
$( "#resultPoints" ).append( "<p>X="+value[0] +", Y="+ value[1]+"</p>" );
});
});
});
</script>
</head>
<body>
var xMin = -10, yMin = -10, xMax = 10 ,yMax = 10;
<br>
var rangeIncrement=1;
<br>
Y= <input type="text" id="txtequation" value="x+1" /><button id="btnDraw">Draw</button>
<br>
<div id="resultPoints"></div>
</body>
</html>

Related

Pattern Repeat on object in KonvaJS

Is there any way to repeat a pattern in KonvaJS through a user input? I have this (DEMO). However,I am having difficulties wrapping my head around this next step. Is it possible?
Edit: I would like to programmatically clone/repeat the arc's peaks per span based on the user input and tile it along the x axis.
You can just do this:
const lines = [];
for (var i = 0; i < numArchPeaks; i++) {
const single = [0, 0, 90, -50, 180, 0];
const perSpan = single.map((x) => x / numArchPeaks);
lines.push(
<Line x={x + i * 180 / numArchPeaks} y={y} points={perSpan} tension={1} stroke="black" />
);
}
// then in render:
<Layer>{lines}</Layer>
https://codesandbox.io/s/stupefied-fermi-vz9z7?file=/src/KonvaExample.js

How to add line which runs through origin (from positive to negative) on a scatterplot - highchart

I am trying to create a reference line that runs through the origin and passes from negative to positive. See an example of what i am trying to achieve - see the threshold line. This threshold line must run through all three x, y coordinates (-1,-45,000), (0.0), (1, 45,000).
enter image description here
Below is my work so far.
http://jsfiddle.net/catio6/rhf6yre5/1/
I've looked at this for reference but have had had no luck after several hours of attempts of replicating this with all three x, y coordinates (-1,-45,000), (0.0), (1, 45,000): http://jsfiddle.net/phpdeveloperrahul/XvjfL/
$(function () {
$('#container').highcharts({
xAxis: {
categories: ['Jan', 'Feb', 'Mar']
},
series: [{
data: [29.9, 71.5, 256]
}]
}, function(chart) { // on complete
console.log("chart = ");
console.log(chart);
//chart.renderer.path(['M', 0, 0, 'L', 100, 100, 200, 50, 300, 100])
chart.renderer.path(['M', 75, 223.5,'L', 259, 47])//M 75 223.5 L 593 223.5
.attr({
'stroke-width': 2,
stroke: 'red'
})
.add();
});
});
So Highcharts doesn't have, as far as I know, a way to define a line that goes from/to infinity.
One idea I had to solve this issue for you is dynamically calculate the values for the line series based on your data. The idea is simple: Given the maximum values for X and Y you want to plot, we just need to limit the axis to a certain value that makes sense and calculate the values for the asymptote series in order to make it seems infinite. My algorithm looks like this:
// Get all your other data in a well formated way
let yourData = [
{x: 0.57, y: 72484},
{x: 0.57, y: 10000}
];
// Find which are the maximum x and y values
let maxX = yourData.reduce((max, v) => max > v.x ? max : v.x, -999999999);
let maxY = yourData.reduce((max, v) => max > v.y ? max : v.y, -999999999);
// Now you will limit you X and Y axis to a value that makes sense due the maximum values
// Here I will limit it to 10K above or lower on Y and 2 above or lower on X
let maxXAxis = maxX + 2;
let minXAxis = - (maxX + 2);
let maxYAxis = maxY + 10000;
let minYAxis = -(maxY + 10000);
// Now you need to calculate the values for the Willingness to pay series
let fn = (x) => 45000 * x; // This is the function that defines the Willingness to pay line
// Calculate the series values
let willingnessSeries = [];
for(let i = Math.floor(minXAxis); i <= Math.ceil(maxXAxis); i++) {
willingnessSeries.push([i, fn(i)]);
}
Here is a working fiddle: http://jsfiddle.net/n5xg1970/
I tested with several values for your data and all of them seem to be working ok.
Hope it helps
Regards

d3.symbols being cut off by ClipPath area

Still in the process of improving my competence about D3, I got stuck with a problem where I'm trying to plot a zoomable curve in a SVG element with margins (so that I need a clipPath rect to avoid that plot invades margins when zoomed) but the clipPath margins cut the display of d3.symbols off the plot.
This is the relevant code for the plot
var margin = {top: 20, right: 60, bottom: 30, left: 30},
w = 960 - margin.left - margin.right,
h = 500 - margin.top - margin.bottom;
var svg = d3.select("body").append("svg")
.attr("width", w + margin.left + margin.right)
.attr("height", h + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", w)
.attr("height", h);
// The curve I want to plot: y=x^2
var my_curve = d3.range(10).map(function(d) { var my_y = d * d; return { "x" : d, "y" : my_y }; });
var x_range_min = d3.min(my_curve, function(d) { return d.x; });
var x_range_max = d3.max(my_curve, function(d) { return d.x; });
var y_range_min = d3.min(my_curve, function(d) { return d.y; });
var y_range_max = d3.max(my_curve, function(d) { return d.y; });
var xScale = d3.scaleLinear().domain([x_range_min, x_range_max]).range([0, w]);
var yScale = d3.scaleLinear().domain([y_range_max, y_range_min]).range([0, h]);
var xAxis = d3.axisBottom().scale(xScale);
var yAxis = d3.axisLeft().scale(yScale);
// symbols
svg.selectAll(".my_pts").data(my_curve).enter().append("path")
.attr("class", "my_pts")
.attr("d", d3.symbol().type(d3.symbolTriangle).size(200))
.attr("transform", function(d) { return "translate(" + xScale(d.x) + "," + yScale(d.y) + ")"; })
// with this zoomed line does not enter margin area
.attr("clip-path", "url(#clip)");
...as you can see only part of the triangle symbol is depicted, I guess because the path is drawn at 0,0 and cut by the clipPath before the translation can be performed.
I have also posted this fiddle https://jsfiddle.net/fabio_p/988c1sjv/
where you can find a more complete version of the code, with the brush & zoom function, so that you can see why the clipPath is needed (if you have never encountered the issue with margins before)
My question is the following: is there a workaround to this problem? I was hoping to find a way to directly draw the symbol in the right place without the need of a later translation (possibly with a "custom symbol type"), but it seems it goes beyond my current skills, since I was unable to produce any actual solution.
Any suggestion would be welcome. Thanks in advance.
Create a group with the clip path:
var clipping = svg.append("g")
.attr("clip-path", "url(#clip)");
And append both the line and the symbols to the group:
clipping.append("path")
.data([my_curve])
//etc...
Here is your updated fiddle: https://jsfiddle.net/cvtvrL2q/

How can we render an OpenLayers 3 feature to a canvas using a style but not using a map?

QUESTION:
How can we render a feature to a canvas using a style but not using a map?
BACKGROUND:
I have a sample which renders a geometry to a canvas honoring the ol3 style but it only runs with the unbuilt version of openlayers (ol-debug.js) and because it makes use of private functions (ol.vec.Mat4).
works when using ol-debug.js
fails when using ol.js
One alternative is to create a map, add a vector layer, set the style on the feature, add the feature to the layer and remove all the events/controls from the map so it looks like a canvas.
A second is to use goog.vec.Mat4.
let scale = Math.min(canvas.width / ol.extent.getWidth(extent), canvas.height / ol.extent.getHeight(extent));
console.log("scale", scale);
let transform = Mat4.makeTransform2D(identity,
canvas.width / 2, canvas.height / 2, // translate to origin
scale, -scale, //scale
0, // rotation
-center[0], -center[1] // translate back
);
console.log("transform", transform);
let renderer = new ol.render.canvas.Immediate(ctx, 1, extent, transform, 1);
renderer.drawFeature(feature, style);
A third is similar to the second in that I take on the responsibility of transforming the geometry into pixel coordinates before using ol.render.toContext, as demonstrated in this example.
I think that about exhausts it? Or is there another way?
Doh! Found an example right on the openlayers site!
In that sample coordinates are already pixels:
<!DOCTYPE html>
<html>
<head>
<title>Render geometries to a canvas</title>
<link rel="stylesheet" href="http://openlayers.org/en/v3.17.1/css/ol.css" type="text/css">
<script src="http://openlayers.org/en/v3.17.1/build/ol.js"></script>
</head>
<body>
<canvas id="canvas"></canvas>
<script>
var canvas = document.getElementById('canvas');
var vectorContext = ol.render.toContext(canvas.getContext('2d'), {size: [100, 100]});
var fill = new ol.style.Fill({color: 'blue'});
var stroke = new ol.style.Stroke({color: 'black'});
var style = new ol.style.Style({
fill: fill,
stroke: stroke,
image: new ol.style.Circle({
radius: 10,
fill: fill,
stroke: stroke
})
});
vectorContext.setStyle(style);
vectorContext.drawGeometry(new ol.geom.LineString([[10, 10], [90, 90]]));
vectorContext.drawGeometry(new ol.geom.Polygon([[[2, 2], [98, 2], [2, 98], [2, 2]]]));
vectorContext.drawGeometry(new ol.geom.Point([88, 88]));
</script>
</body>
</html>
But as the question indicates, translation -> scale -> translation transforms the data:
function render(canvas: HTMLCanvasElement, line: ol.Coordinate[], style: ol.style.Style) {
let extent = ol.extent.boundingExtent(line);
let [dx, dy] = ol.extent.getCenter(extent);
let [sx, sy] = [canvas.width / ol.extent.getWidth(extent), canvas.height / ol.extent.getHeight(extent)];
line= translate(line, [-dx, -dy]);
line= scale(line, [Math.min(sx, sy), -Math.min(sx, sy)]);
line= translate(line, [canvas.width / 2, canvas.height / 2]);
let feature = new ol.Feature({
geometry: new ol.geom.Polygon([line]),
style: style
});
let vtx = ol.render.toContext(canvas.getContext("2d"));
vtx.drawFeature(feature, style);
}
Here is my TRS logic:
function translate(points: number[][], vector: number[]) {
return points.map(p => vector.map((v, i) => v + p[i]));
}
function rotate(points: number[][], a: number) {
return points.map(p => {
let [x, y, cos, sin] = [p[0], p[1], Math.cos(a), Math.sin(a)];
return [
x * cos - y * sin,
x * sin + y * cos
];
});
}
function scale(points: number[][], vector: number[]) {
return points.map(p => vector.map((v, i) => v * p[i]));
}

Webgl Buffer Values not working

i am learning WebGL right now and i saw this WebGL example from this site
http://webglfundamentals.org/webgl/webgl-3d-perspective-matrix.html ,
where he has the same matrix and the same shader calculation as me, but i cant use his vertex data to draw the same object. Also i can only use negative z values between -1 and -2000, while he uses positive z values in his vertex data.
Why he can use positive z values ?
When i am using positive z values, then i see no triangle drawn.
Sorry for my bad English.
Here is my code:
var canvas = document.getElementById("canvas");
var gl = canvas.getContext("webgl");
var fs_str = " void main() { \n "
+ "gl_FragColor = vec4(1.0,0.0,0.0,1.0);\n"
+ "} \n";
var vs_str = "attribute vec3 a_position;\n"
+ "uniform mat4 u_matrix;\n"
+ " void main() { \n "
+ "vec4 position = u_matrix * vec4(a_position,1.0);\n"
+ "gl_Position = position;\n"
+ "}";
gl.clearColor(0.0,0.0,0.0,1.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.viewport(0,0,canvas.clientWidth,canvas.clientHeight);
var program = gl.createProgram();
var fs = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fs,fs_str);
gl.compileShader(fs);
gl.attachShader(program,fs);
var vs = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vs,vs_str);
gl.compileShader(vs);
gl.attachShader(program,vs);
gl.linkProgram(program);
gl.useProgram(program);
var vertices = [-1.0, -1.0, -1.0,
1.0, 1.0, -1.0,
1.0, -1.0, -1.0
];
var matrix = mat4.create();
mat4.perspective(matrix, (60 * Math.PI/ 180), canvas.clientWidth/canvas.clientHeight, 1, 2000);
var matrixLocation = gl.getUniformLocation(program,"u_matrix");
gl.uniformMatrix4fv(matrixLocation,false,matrix);
var vbo = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
var positionLocation = gl.getAttribLocation(program,"a_position");
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation,3,gl.FLOAT,false,0,0);
gl.drawArrays(gl.TRIANGLES, 0, 3);
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/2.3.2/gl-matrix-min.js"></script>
</head>
<body>
<canvas id="canvas" width="400" height="300"></canvas>
<script src="index.js"></script>
</body>
</html>
Your point of view is at z = 0, looking towards the negatives. Setting a z in the positive will put the object behind you. On the website you linked, the Z value of the slider also can't go in the positives.
Also, because the last parameter of mat4.perspective is 2000, you won't be able to see anything that is more than 2000 units away from you. That is why -2000 is the maximum here.
I'm not entirely sure what you want to do, for me your code is working as attended.
I made a fiddle including the "F" from the tutorial you are following :
https://jsfiddle.net/g69cdeza/1/
I added the line mat4.translate(matrix, matrix, [5, 0, -500]); to move the object.
Is there something more you are not managing to do?

Resources