JSXGraph: Applying a line transformation with applyOnce() - javascript

I'm trying to apply a one-time transformation to a Line in JSXGraph.
Based on the documentation, I'm trying to transform a Line like this:
var f = function(x) {
return x;
};
var l1 = board.create('functiongraph', [f], {
name: 'line 1',
withLabel: true,
strokeWidth: 2,
strokeColor: 'orange',
fixed: false
});
// Rotate about an intersection point with another line
var i = board.create('intersection', [l1, l2, 0], {
name: 'intersection',
fixed: true,
showInfobox: false
});
var rot = board.create(
'transform', [
function() {
// This gets the value from a slider
return s.Value();
}, i
], {
type:'rotate'
});
rot.applyOnce(l1);
board.update();
The full source is here: http://maldive.ccnmtl.columbia.edu/js/ncustom.js and you can see the error I'm describing here: http://maldive.ccnmtl.columbia.edu/js/functiongraph-rotation.html
I get the error: t[n].coords is undefined. In the full application that I'm trying this in, I get the error: TypeError: Cannot read property 'usrCoords' of undefined
So, anyways, has anyone else tried to transform a line like this?
Update: After looking at the source, it's obvious this method only works with points. So, I don't know if this will be possible with my functiongraph. I am just using a straight line here though, so it's possible I can do something with points.

Yes, applyOnce is implemented only for points, texts and images, yet. The alternative is to bind the transformation to the curve. Here is the full example (relevant is only the very last line):
var board = JXG.JSXGraph.initBoard('jxgbox', {
boundingbox: [-10, 10, 10, -10],
axis:true
});
var f = function(x) {
return x;
};
var l1 = board.create('functiongraph', [f], {
name: 'line 1', withLabel: true, fixed: false
});
var f2 = function(x) {
var alpha = 0.3;
return (1 - alpha) *
(1.4 *
1.6 ** alpha) *
(x ** -alpha);
};
var l2 = board.create('functiongraph', [f2], {
name: 'line 2', withLabel: true, fixed: false
});
// Rotate about an intersection point with another line
var intrsct = board.create('intersection', [l1, l2, 0], {
name: 'intersection', fixed: true,
});
var s = board.create(
'slider', [
[-1, -1],
[2, -1],
[0, 0, 2]
], { name:'angle'});
var rot = board.create(
'transform', [
function() {
// This gets the value from a slider
return s.Value();
}, intrsct
], { type:'rotate' });
rot.bindTo(l1);
Alternatively, in the upcoming version 0.99.7 (already available in the nightly builds), you can create a new curve which is the transformed curve of an original curve:
var l1a = board.create('curve', [l1, rot], {
name: 'line 1a',
withLabel: true,
strokeWidth: 2,
strokeColor: 'orange',
fixed: false
});

Related

Cesium polygon callback using javascript

I am trying to edit the change the edit or redraw the polygon. this is my code.
Error
An error occurred while rendering. Rendering has stopped.
TypeError: this._callback is not a function
TypeError: this._callback is not a function
using pickedObject.id i got the exect polygon i want to reposition, but call back issue.
var points = [-95.8079865631313, 30.24038650541154, -
60.10509002138564, 23.526593580490083, -59.06372427570612, 2.245934026097194, -
117.00668212362282, 3.938434130034481
];
function loadPoly(points) {
redPolygon = viewer.entities.add({
id: "myArray",
name: "myArray",
polygon: {
hierarchy: Cesium.Cartesian3.fromDegreesArray(points),
material: Cesium.Color.fromBytes(221, 240, 235, 160)
}
});
polygonCollection.push(redPolygon);
adding_billboard(-95.8079865631313, 30.24038650541154, "A", "-95.8079865631313, 30.24038650541154");
adding_billboard(-60.10509002138564, 23.526593580490083, "A", "-60.10509002138564, 23.526593580490083");
adding_billboard(-59.06372427570612, 2.245934026097194, "A", "-59.06372427570612, 2.245934026097194");
adding_billboard(-117.00668212362282, 3.938434130034481, "A", "-117.00668212362282, 3.938434130034481");
viewer.flyTo(redPolygon);
}
function adding_billboard(lon, lat, name, popup) {
var entity = viewer.entities.add({
name: name,
position: Cesium.Cartesian3.fromDegrees(lon, lat, 2000),
billboard: {
image: 'https://cdn0.iconfinder.com/data/icons/small-n-flat/24/678111-map-marker-512.png',
show: true, // default
pixelOffset: new Cesium.Cartesian2(0, -20), // default: (0, 0)
eyeOffset: new Cesium.Cartesian3(0.0, 0.0, 0.0), // default
horizontalOrigin: Cesium.HorizontalOrigin.bottom, // default
alignedAxis: Cesium.Cartesian3.ZERO, // default
width: 20, // default: undefined
height: 25, // default: undefined
//disableDepthTestDistance: Number.POSITIVE_INFINITY, // draws the label in front of terrain
// on ground show
},
label: {
text: popup,
font: "7pt sans-serif",
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
horizontalOrigin: Cesium.HorizontalOrigin.LEFT,
verticalOrigin: Cesium.VerticalOrigin.BASELINE,
fillColor: Cesium.Color.BLACK,
showBackground: true,
backgroundColor: new Cesium.Color(1, 1, 1, 0.7),
backgroundPadding: new Cesium.Cartesian2(8, 4),
disableDepthTestDistance: Number
.POSITIVE_INFINITY, // draws the label in front of terrain
},
});
pointsCollection.push(entity);
}
var coordinates = [76.82071632075994, 33.4134542888633, 77.83750798568438, 33.39276536442791, 77.32892923803021,
32.93547457354476
];
var handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
handler.setInputAction(function(click) {
var pickedObject = scene.pick(click.position);
if (Cesium.defined(pickedObject)) {
console.log("Second ");
console.log("pickedObject.id.id ", pickedObject.id.id);
console.log("pickedObject.id.name ", pickedObject.id.name);
console.log("pickedObject.id..polygon.hierarchy ", pickedObject.id.polygon.hierarchy.valueOf());
var data = pickedObject.id.polygon.hierarchy.valueOf();
console.log("data ", data.positions.valueOf());
pickedObject.id.polygon = {
hierarchy: new Cesium.CallbackProperty(new Cesium.Cartesian3.fromDegreesArray(coordinates),
false),
material: Cesium.Color.fromBytes(221, 240, 235, 160)
//pickedObject.id = redPolygon;// tried this but dailed due to same id then i removed it.
if (pickedObject.id.name == 'C') {
// $('#modal-activity').modal('show');
}
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
i want to shift polygon to some other coordiante but unable to use call back properly can some one guild me how can I do ?
i did some google searches which are given below but my issues not solved.
here i was trying to make polygon points dynamic but line disappers in tarrains. fist time it was ok after moving point it disappers.
https://sandcastle.cesium.com/?#c=zVTRbpswFP2VK14gEjMhWTaJ0Whd0odpnVpl0vZQ+uDCTWvN2Mg2yVjVf5/BkKRZ1VV9mnjhHp9zfH2uYUMVbBhuUcEJCNzCAjWrS/K9wwI/78qFFIYygcoffchE+2ysDoVhpomt0DmQDmCoCS2K4D4TAKxIwP+8jP2wrQQtESywwgLOOGeVRpACdK3WNEfHqaS2HlIkMLSyoMrYNyqmZK1kucRbhaiDN3E8I+MQpu/JeNRLmTAJdBvbiv1C/o39xgSm49BhueRSJTvjtiKrs2W/KmvD7SEXT5A+nZ8uvjym/WCFuUsgJrMWfsjEg8tmn8zkBclMXpPMP4N52wXz7v8Lpl1/LpVK8qbl7JvtD62Tw9t52aOXSlaoTHOqFG2CKyeBQ+YK16hQ5DhQg6O9w/5+whX4w2Y+XMMofLXb5Am3wex677t1Oc12QEkNKkb50VFdIhcu3K89Z9fA/aB+foQvHuLxGCdujHaQo8NxeqGXatNwnLvVj6yspDJQKx4QEhksK25b1dFNnf9EQ3KtW1kaDaK0YBv7EZxk3tEvJvMg51Rru7KueXdRM2+eRpb/SMYlLZi4vdig4rRpKXfx/NyBhJA0suXfKiMlv6HqwPEP
second :Dynamically change polygon position in cesium
it also gives error because i don't know where to use callback.
please guild me. thank you.
Here's Sandcastle link.
const {
Cartesian3,
CallbackProperty,
Color,
defined,
ScreenSpaceEventHandler,
ScreenSpaceEventType,
Viewer
} = window.Cesium;
const viewer = new Viewer("cesiumContainer");
let redPolygon;
const polygonCollection = [];
const pointsCollection = [];
const polygonId = "myArray";
let polygonPoints = [
-95.8079865631313, 30.24038650541154, -60.10509002138564, 23.526593580490083, -59.06372427570612,
2.245934026097194, -117.00668212362282, 3.938434130034481
];
function loadPoly() {
redPolygon = viewer.entities.add({
id: polygonId,
name: "myArray",
polygon: {
hierarchy: new CallbackProperty(() => {
return {
positions: Cartesian3.fromDegreesArray(polygonPoints)
};
}, false),
material: Color.fromBytes(221, 240, 235, 160)
}
});
polygonCollection.push(redPolygon);
adding_billboard(-95.8079865631313, 30.24038650541154, "A", "-95.8079865631313, 30.24038650541154");
adding_billboard(-60.10509002138564, 23.526593580490083, "A", "-60.10509002138564, 23.526593580490083");
adding_billboard(-59.06372427570612, 2.245934026097194, "A", "-59.06372427570612, 2.245934026097194");
adding_billboard(-117.00668212362282, 3.938434130034481, "A", "-117.00668212362282, 3.938434130034481");
viewer.flyTo(redPolygon);
}
function adding_billboard(lon, lat, name, popup) {
const entity = viewer.entities.add({
name: name,
position: Cartesian3.fromDegrees(lon, lat, 2000),
billboard: {
image: "https://cdn0.iconfinder.com/data/icons/small-n-flat/24/678111-map-marker-512.png",
show: true, // default
pixelOffset: new Cesium.Cartesian2(0, -20), // default: (0, 0)
eyeOffset: new Cartesian3(0.0, 0.0, 0.0), // default
horizontalOrigin: Cesium.HorizontalOrigin.bottom, // default
alignedAxis: Cesium.Cartesian3.ZERO, // default
width: 20, // default: undefined
height: 25 // default: undefined
//disableDepthTestDistance: Number.POSITIVE_INFINITY, // draws the label in front of terrain
// on ground show
},
label: {
text: popup,
font: "7pt sans-serif",
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
horizontalOrigin: Cesium.HorizontalOrigin.LEFT,
verticalOrigin: Cesium.VerticalOrigin.BASELINE,
fillColor: Color.BLACK,
showBackground: true,
backgroundColor: new Color(1, 1, 1, 0.7),
backgroundPadding: new Cesium.Cartesian2(8, 4),
disableDepthTestDistance: Number.POSITIVE_INFINITY // draws the label in front of terrain
}
});
pointsCollection.push(entity);
}
loadPoly();
const scene = viewer.scene;
const handler = new ScreenSpaceEventHandler(scene.canvas);
handler.setInputAction(function (click) {
const pickedObject = scene.pick(click.position);
if (defined(pickedObject) && pickedObject.id && pickedObject.id.id === polygonId) {
const newPolygonPoints = [
76.82071632075994, 33.4134542888633, 77.83750798568438, 33.39276536442791, 77.32892923803021,
32.93547457354476
];
polygonPoints = newPolygonPoints;
viewer.camera.flyTo({
destination: Cartesian3.fromDegrees(76.82071632075994, 33.4134542888633, 1000)
});
}
}, ScreenSpaceEventType.LEFT_CLICK);

Plotly.js : Overlaying two different graphs with same x-axis and different y-axis scales

I have a scenario in my application while using Plotly.js where I need to overlay two different line graphs in the same plane, with the same x-axis and different y-axis scales, stacked on top of each other as shown in the image below. I imagine it to look something like this :
How can I do this?
You can create a secondary yaxis, then set the range of the primary and secondary yaxes differently, and also set which tickmarks are displayed for each of the yaxes. To make things a bit more generlizeable, I included a function that creates linearly spaced arrays that you can use for tickmarks, and some scaling factors for the min and max of the yaxis ranges.
You can view the codepen here.
function linspace(start, stop, num, endpoint = true) {
const div = endpoint ? (num - 1) : num;
const step = (stop - start) / div;
return Array.from({length: num}, (_, i) => start + step * i);
}
var yaxis_data = [40, 50, 60];
var yaxis2_data = [4,5,6];
var yaxis_data_min = Math.min(...yaxis_data);
var yaxis_data_max = Math.max(...yaxis_data);
var yaxis2_data_min = Math.min(...yaxis2_data);
var yaxis2_data_max = Math.max(...yaxis2_data);
var yaxis_data_range = [0.5*yaxis_data_min, yaxis_data_max];
var yaxis2_data_range = [yaxis2_data_min, 1.5*yaxis2_data_max];
var yaxis_ticks = linspace(yaxis_data_min, yaxis_data_max, 3)
var yaxis2_ticks = linspace(yaxis2_data_min, yaxis2_data_max, 3)
var trace1 = {
x: [1, 2, 3],
y: yaxis_data,
name: 'yaxis data',
type: 'scatter'
};
var trace2 = {
x: [2, 3, 4],
y: yaxis2_data,
name: 'yaxis2 data',
yaxis: 'y2',
type: 'scatter'
};
var data = [trace1, trace2];
var layout = {
title: 'Double Y Axis Example',
yaxis: {
title: 'yaxis title',
range: yaxis_data_range,
tickvals: yaxis_ticks
},
yaxis2: {
title: 'yaxis2 title',
titlefont: {color: 'rgb(148, 103, 189)'},
tickfont: {color: 'rgb(148, 103, 189)'},
overlaying: 'y',
side: 'right',
range: yaxis2_data_range,
tickvals: yaxis2_ticks
}
};
Plotly.newPlot('myDiv', data, layout);

Code efficiency using VectorGrid in Leaflet

I have about 7 000 polygons in a GeoJSON file using VectorGrid, all is fine using one layer but I need to split this layer into 10 LayerGroups (10 regions with their own polygons). How can this be done without rewriting the code 10 times? That seems to be lots of waste, there must be a smarter way and I can't figure it out. This is the code Im testing with, the highlight has to be working with all 11 layers...
var all_regions = new L.layerGroup();
var region_1 = new L.layerGroup();
var region_2 = new L.layerGroup();
var region_3 = new L.layerGroup();
/* snip */
var region_10 = new L.layerGroup();
var highlight_polygon;
var clearHighlight = function () {
if (highlight_polygon) {
vectorGrid.resetFeatureStyle(highlight_polygon);
}
highlight_polygon = null;
};
var vectorTileOptions_allRegions = {
rendererFactory: L.canvas.tile,
maxNativeZoom: 13,
zIndex: 6,
vectorTileLayerStyles: {
sliced: {
weight: 2,
color: "gray",
opacity: 1,
fill: false,
//fillColor: 'white',
//stroke: true,
fillOpacity: 0,
},
},
interactive: true,
getFeatureId: function (f) {
return f.properties.id;
},
};
var vectorTileOptions_region_1 = {
rendererFactory: L.canvas.tile,
maxNativeZoom: 13,
zIndex: 6,
vectorTileLayerStyles: {
sliced: function (properties, zoom) {
var region = properties.region;
if (region === "region one") {
return {
weight: 2,
color: "gray",
opacity: 1,
fill: false,
//fillColor: 'white',
//stroke: true,
fillOpacity: 0,
};
} else {
return {
weight: 0,
opacity: 0,
fill: false,
stroke: false,
fillOpacity: 0,
interactive: false,
};
}
},
},
interactive: true,
getFeatureId: function (f) {
return f.properties.id;
},
};
// Next vectorTileOptions until all 11 of them....
$.getJSON("/data/regions.geojson", function (json) {
//Not sure this is the correct way doing it...
var vectorGrid = L.vectorGrid
.slicer(json, vectorTileOptions_allRegions, vectorTileOptions_region_1)
.on("click", function (e) {
var properties = e.layer.properties;
L.popup()
.setContent(
"<b>Name</b>: " +
properties.region_name +
"<br><b>Date</b>: " +
"<i>" +
properties.date +
"</i>"
)
.setLatLng(e.latlng)
.openOn(map);
clearHighlight();
highlight_polygon = e.layer.properties.id;
vectorGrid.setFeatureStyle(highlight_polygon, {
weight: 3,
color: "gray",
opacity: 1,
fillColor: "#ff9999",
fill: true,
radius: 6,
fillOpacity: 0.3,
});
L.DomEvent.stop(e);
});
var clearHighlight = function () {
if (highlight_polygon) {
vectorGrid.resetFeatureStyle(highlight_polygon);
}
highlight_polygon = null;
map.on("popupclose", clearHighlight);
};
//This will not work....
vectorGrid.addTo(all_regions);
vectorGrid.addTo(region_1);
});
You probably want to do something like...
var regions = []; // An array that will hold instances of VectorGrid
var vectorGridOptions = {
rendererFactory: L.canvas.tile,
maxNativeZoom: 13,
zIndex: 6,
vectorTileLayerStyles: {
sliced: {}, // Empty, because it shall be overwritten later.
},
};
var defaultStyle = {
stroke: true,
weight: 2,
};
var regionStyles = [];
regionStyles[0] = {
weight: 2,
color: "gray",
};
regionStyles[1] = {
weight: 1,
color: "red",
};
/* ...etc, up to regionStyles[9] */
fetch("/data/regions.geojson")
.then(function (response) { return response.json(); })
.then(function (json) {
// For each number between 0 and 9...
for (var i = 0; i <= 9; i++) {
// Assuming that the GeoJSON data holds a FeatureCollection,
// create a copy of said GeoJSON FeatureCollection, but holding only
// the wanted features.
// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
var filteredGeoJSON = {
type: "FeatureCollection",
features: json.features.filter(function (feature) {
// This assumes that each Feature has a "regionID" property with a
// numeric value between 0 and 9.
return feature.properties.regionID === i;
}),
};
// Build up the options for the i-th VectorGrid by merging stuff together.
// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
var fullRegionStyle = Object.assign({}, defaultStyle, regionStyles[i]);
// Overwrite some stuff in vectorGridOptions. Note that this changes the value of
// a piece of vectorGridOptions at each pass of the loop.
vectorGridOptions.vectorTileLayerStyles.sliced = fullRegionStyle;
regions[i] = L.vectorGrid.slicer(filteredGeoJSON, vectorTileOptions);
regions[i].addTo(map);
}
});
The key points here are:
Use a loop to iterate from 1 through 10
Keep things in numbered arrays instead of similarly-named variables
Filter the FeatureCollection, so each VectorGrid works with less data. Drawing invisible polygons/polylines would take as much computing time as drawing visible ones.
Refactor as much as possible, then build up concrete data structures (Object.assign, clone objects if needed)

Echart: How to set mark area to fill sections in xAxis

I have a problem with marking area: i need to be able to select a bar area based on xAxis, for example from 0 to 1, from 1 to 2, etc. But when i try to provide options for bar like
[{xAxis: 0, itemStyle: {color: red}},{xAxis: 1}]
it marks an area from a middle of xAxis area with an index of 0 to a middle of xAxis area with an index of 1. Is there a way to make it mark from start of an area to an end. Currently i managed to do so only with x option in pixels:
https://codesandbox.io/s/react-echart-markarea-ksj31?file=/src/index.js:714-726
Is there a better way to do it?
I can't imagine a method that would cover your requirements. It seems there is no such but nothing prevents to do it ourselves, see below.
When call function with join = true markedArea will calc as range from first to last.
calcMarkAreaByBarIndex(myChart, join = true, [4, 9])
When call function with join = false markedArea will calc for each bar.
calcMarkAreaByBarIndex(myChart, join = true, [4, 5, 6, 9])
var myChart = echarts.init(document.getElementById('main'));
var option = {
tooltip: {},
xAxis: {
data: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
},
yAxis: {},
series: [
{
id: 'myBar',
name: 'Series',
type: 'bar',
data: [11, 11, 11, 11, 12, 13, 110, 123, 113, 134, 93, 109],
markArea: {
data: [
[{x: 184},{x: 216}],
[{x: 224},{x: 256}],
]
},
},
]
};
myChart.setOption(option);
function calcMarkAreaByBarIndex(chartInstance, join = false, barIdx){
var series = chartInstance.getModel().getSeriesByType('bar');
var seriesData = series.map((s, idx) => s.getData())[0];
var barNum = seriesData.count();
var barCoors = [];
var layout = idx => seriesData.getItemLayout(idx);
for(var i = 0; i < barNum; i++){
if(!barIdx.includes(i)) continue;
barCoors.push([
{ x: layout(i).x },
{ x: layout(i).x + layout(i).width },
])
}
if(join){
return [
[
{ x: barCoors[0][0].x },
{ x: barCoors[barCoors.length - 1][1].x }
]
]
} else {
return barCoors
}
}
var markedAreas = {
series: {
id: 'myBar',
markArea: {
data: calcMarkAreaByBarIndex(myChart, join = true, [4,9])
}
}
};
myChart.setOption(markedAreas);
<script src="https://cdn.jsdelivr.net/npm/echarts#4.7.0/dist/echarts.min.js"></script>
<div id="main" style="width: 600px;height:400px;"></div>
I found a solution, that worked for me:
Basically, you need to manually set yAxis's max props, add another xAxis, make it invisible, create a custom series with type 'bar' and set xAxisIndex to 1:
data: [maxYaxisValue,maxYaxisValue...], //length === xAxis.data.length
type: 'bar',
barWidth: '100%',
color: transparent,
xAxisIndex: 1,
And style a bar by index with background color and borderWidth
You can check the working example here
https://codesandbox.io/s/react-echart-markarea-m0mgq?file=/src/index.js

How to shade outside a circle in JSXgraph

I'm currently trying to shade inside and outside a circle in JSXgraph, similar to an inequality.
My current code to create a circle:
var A = board.create('point', [h, k], { name: '', size: 0, fixed: true}),
B = board.create('point', [h, k+r], { name: '', size: 0, fixed: true}),
graph = board.create('circle', [A, B], { id: field, size: 0, fixed: true });
graph.on('down', function (e, i) {
showMaster(this.id);
});
graphMap.set(field, graph);
inequality(">", field, graph, color);
I have found that you can shade inside using these object proprieties:
{strokeWidth: 2, dash: 2, fillColor: 'red', fillOpacity: 0.3}
However, nothing in shading outside.
Any suggestions ?

Categories

Resources