How can I move camera in matter.js - matter.js

How can I move the camera to a specific position in matter.js?
I want the camera to follow my main character.
I tried this tutorial: http://brm.io/matter-js/demo/#views
but truth be told, I did not understand it.

I found how to make it: http://codepen.io/vanuatu/pen/VeQMpp
We need to control render bounds, like this:
//
hero = bubbleBall
// Follow Hero at X-axis
engine.render.bounds.min.x = centerX + hero.bounds.min.x
engine.render.bounds.max.x = centerX + hero.bounds.min.x + initialEngineBoundsMaxX
// Follow Hero at Y-axis
engine.render.bounds.min.y = centerY + hero.bounds.min.y
engine.render.bounds.max.y = centerY + hero.bounds.min.y + initialEngineBoundsMaxY
// Update Mouse
Mouse.setOffset(mouseConstraint.mouse, engine.render.bounds.min);
I hope that can help someone

An easier way to do it:
Render.lookAt(render, player, {
x: 1080,
y: 1920
});
x and y are the width and height of the render bounds.

First, let's start with this simple example :
// module aliases
var Engine = Matter.Engine,
Render = Matter.Render,
World = Matter.World,
Runner = Matter.Runner,
Bodies = Matter.Bodies;
var engine = Engine.create();
var runner = Runner.create();
// create a renderer
var render = Render.create({
element: document.body,
engine: engine,
runner: runner,
options: {
width: 1280,
height: 720
}
});
var vertices = [{ x : 50, y : 0},
{ x : 63, y : 38},
{ x : 100, y : 38},
{ x : 69, y : 59},
{ x : 82, y : 100},
{ x : 50, y : 75},
{ x : 18, y : 100},
{ x : 31, y : 59},
{ x : 0, y : 38},
{ x : 37, y : 38} ];
// add a star at center
var star = Matter.Vertices.create(vertices);
var starBody = Bodies.fromVertices(640, 360, star, {isStatic: true}, true);
// add all of the bodies to the world
World.add(engine.world, [ starBody]);
Render.run(render);
Runner.run(runner, engine);
You should see a little star at center, if you want to move the camera, your render needs to have bounds, modify the render instanciation as follow :
<pre><code>
var render = Render.create({
element: document.body,
engine: engine,
runner: runner,
options: {
width: 1280,
height: 720,
<b>hasBounds : true</b>
}
});
And use the Bounds module alias :
var Engine = Matter.Engine,
Render = Matter.Render,
World = Matter.World,
Runner = Matter.Runner,
Bodies = Matter.Bodies,
Bounds = Matter.Bounds;
Now you can translate the bounds of your render to move your camera :
let translate = {x : -100, y : -100}
Bounds.translate(render.bounds, translate);
What it does in fact is something like this :
function moveMatterJSCamera(offsetX, offsetY) {
render.bounds.min.x += offsetX;
render.bounds.max.x += offsetX;
render.bounds.min.y += offsetY;
render.bounds.max.y += offsetY;
}

I found that translating everything works too. like transX=-player.position.x and then doing Matter.Body.translate(body,{x:transX,y:0}) with all your bodies including the player

function track(){
Render.lookAt(render, player, {
x: 500,
y: 500
});
}
function repeatOften() {
track()
requestAnimationFrame(repeatOften);
}
requestAnimationFrame(repeatOften);

Related

Increase size of one of the series in R highchart

I'm trying to show a line and % changes in a single highchart plot, but the changes are very little and It can't be seen in the plot. I made a simplified code to show my problem:
a <- c(300,200, 400, 10, 40, 80)
b <- c(0.8, 2, -2, -1.5, -1.1, 2)
d<-cbind(a,b)
dt <- seq(as.Date("2018-01-01"), as.Date("2018-01-06"), by = "days")
ts <- xts(d, dt )
highchart(type="stock") %>%
hc_add_series(ts$a,
type = "line",
color="black") %>%
hc_add_series(ts$b,
type = "lollipop",
color="red")
I need to increase the size of "ts$b" in the plot, how can I do it? I also tried with two axis, but It seems doesn't solve the problem.
I see two solutions to achieve that.
The first you mentioned - using two yAxis and manipulating their height and top distance.
Example JS code:
yAxis: [{
height: '90%',
opposite: false
},
{
visible: false,
top: '83%',
height: '15%',
}
]
Demo:
https://jsfiddle.net/BlackLabel/0826r7sh/
Another way is using a modified logarithmic axis. Negative values can't be plotted on a log axis, because by nature, the axis will only show positive values. In that case you need to use a custom extension according to the following thread:
Highcharts negative logarithmic scale solution stopped working
(function(H) {
H.addEvent(H.Axis, 'afterInit', function() {
const logarithmic = this.logarithmic;
if (logarithmic && this.options.custom.allowNegativeLog) {
// Avoid errors on negative numbers on a log axis
this.positiveValuesOnly = false;
// Override the converter functions
logarithmic.log2lin = num => {
const isNegative = num < 0;
let adjustedNum = Math.abs(num);
if (adjustedNum < 10) {
adjustedNum += (10 - adjustedNum) / 10;
}
const result = Math.log(adjustedNum) / Math.LN10;
return isNegative ? -result : result;
};
logarithmic.lin2log = num => {
const isNegative = num < 0;
let result = Math.pow(10, Math.abs(num));
if (result < 10) {
result = (10 * (result - 1)) / (10 - 1);
}
return isNegative ? -result : result;
};
}
});
}(Highcharts));
.
yAxis: {
type: 'logarithmic',
custom: {
allowNegativeLog: true
}
},
Demo
https://jsfiddle.net/BlackLabel/nw6osucm/

scale konva image from the center and hold position on redraw

Hey guys I have a slight problem here I have a Konva.js app which is working pretty well. I have this function called SET_STAGE_DATA that is supposed to save the images current position on the canvas so it can be redrawn when the canvas disapears. It works but when you scale the image from the left the image shifts. I am not sure how to fix this. I thought I may be able to fix it with offset but to no avail.
Heres my SET_STAGE_DATA function
[SET_STAGE_DATA](state){
const isStage = state.stage;
if(isStage){
const groups = state.stage.find("Group");
const stageData = [];
for (let x = 0; x < groups.length; x++) {
let g = groups[x];;
let i = g.findOne("Image").getAttrs();
let position = g.findOne("Image").position();
console.log("this is position", position);
let group = { x: g.getX(), y: g.getY() };
let image = { x: i.width, y: i.height, position };
let obj = { image, group };
stageData.push(obj);
}
I use the stageData just before I build the image like so
let groupPos;
let imagePos;
if(state.stageData){
console.log(true);
for(let i =0; i<state.stageData.length; i++){
imageObj.width = state.stageData[i].image.x;
imageObj.height = state.stageData[i].image.y;
imagePos = state.stageData[i].position;
groupPos = state.stageData[i].group;
}
} else {
groupPos = {
x: state.stage.width() / 2 - imageObj.width / 2,
y: state.stage.height() / 2 - imageObj.height / 2
};
}
console.log("data", {groupPos, image: {width: imageObj.width, height: imageObj.height}});
const image = new Konva.Image({
image: imageObj,
width: imageObj.width,
height: imageObj.height,
strokeWidth: 10,
stroke: "blue",
strokeEnabled: false
});
if(imagePos){
image.position(imagePos)
}
const group = new Konva.Group({
draggable: true,
x: groupPos.x,
y: groupPos.y
});
I also have the typical update function found in the documentation:
function update(activeAnchor) {
const group = activeAnchor.getParent();
let topLeft = group.get(".topLeft")[0];
let topRight = group.get(".topRight")[0];
let bottomRight = group.get(".bottomRight")[0];
let bottomLeft = group.get(".bottomLeft")[0];
let image = group.get("Image")[0];
let anchorX = activeAnchor.getX();
let anchorY = activeAnchor.getY();
// update anchor positions
switch (activeAnchor.getName()) {
case "topLeft":
topRight.y(anchorY);
bottomLeft.x(anchorX);
break;
case "topRight":
topLeft.y(anchorY);
bottomRight.x(anchorX);
break;
case "bottomRight":
bottomLeft.y(anchorY);
topRight.x(anchorX);
break;
case "bottomLeft":
bottomRight.y(anchorY);
topLeft.x(anchorX);
break;
}
// image.position(topLeft.position());
let width = topRight.getX() - topLeft.getX();
let height = bottomLeft.getY() - topLeft.getY();
if (width && height) {
image.width(width);
image.height(height);
}
}
function addAnchor(group, x, y, name) {
let anchor = new Konva.Circle({
x: x,
y: y,
stroke: "#666",
fill: "#ddd",
strokeWidth: 2,
radius: 8,
name: name,
draggable: true,
dragOnTop: false
});
anchor.on("dragmove", function() {
update(this);
state.layer.draw();
});
anchor.on("mousedown touchstart", function() {
group.draggable(false);
this.moveToTop();
});
anchor.on("dragend", function(evt) {
group.draggable(true);
commit(SET_STAGE_DATA);
dispatch(UPDATE_ANIMATION, state.selectedNode);
state.layer.draw();
});
// add hover styling
anchor.on("mouseover", function() {
document.body.style.cursor = "pointer";
this.strokeWidth(4);
state.layer.draw();
});
anchor.on("mouseout", function() {
document.body.style.cursor = "default";
this.strokeWidth(2);
state.layer.draw();
});
group.add(anchor);
}
state.layer.draw();
},
when I scale to the left the image goes outside of the anchors on redraw. I know I can fix this visually as long as I don't redraw the image by doing image.position(topLeft.position()); as you can see is commented out but it always acts as if positioning isn't set if you drag from the left. If I scale from the bottom right everything is fine. it acts as though it goes back to the previous position of the images left top corrner but from what I understand using stage.find() will give you the current stage. I'm at a totally loss.
See in the image how it does not stay in the box. Any help here would be great thanks.
[1]: https://i.stack.imgur.com/HEfHP.jpg
Update the SET_STAGE_DATA function to look like this
[SET_STAGE_DATA](state){
const isStage = state.stage;
const isEditorMode = state.editorMode;
if(isStage && !isEditorMode){
const groups = state.stage.find("Group");
const stageData = [];
for (let x = 0; x < groups.length; x++) {
let g = groups[x];
let i = g.findOne("Image").getAttrs();
let group = {x: g.getX() + i.x, y: g.getY() + i.y };
let image = i;
let obj = { image, group };
stageData.push(obj);
}
state.stageData = stageData;
} else {
state.stageData = null;
}
}
group.x and y don't update on scale but image.x and y do. On move image x and y are 0 and if you add them to the group.x and y it will put the anchors where you need them to be.

Detect if Lines Intersect in Google Charts or Plot.ly

I have seen scripts that claim to enter coordinates and it'll tell you if they intersect, but I have an array of X,Y values for a couple of "lines" but how do I cycle through the points to find out if they intersect?
I've included a photo of my graph and as you see, eventually my plots cross over, I just want to know if my values ever cross over (intersect).
How do I run through this to find out if any intersection ever occurs?
var Test = {
x: [8043, 10695, 13292, 17163, 20716, 25270],
y: [1000, 274, 100, 27.4, 10, 2.74],
fill: 'tozeroy',
type: 'scatter',
name: 'Test'
};
var Test2 = {
x: [8043, 10063, 12491, 16081, 19408, 23763],
y: [1000, 274, 100, 27.4, 10, 2.74],
fill: 'tozeroy',
type: 'scatter',
name: 'Test2'
};
var Test3 = {
x: [4700, 5943, 7143, 8841, 10366, 13452],
y: [1000, 274, 100, 27.4, 10, 2.74],
fill: 'tozeroy',
type: 'scatter',
name: 'Test3'
};
var data = [Test, Test2, Test3];
var layout = {
width: 700,
height: 700,
xaxis: {
type: 'log',
range: [3,5]
},
yaxis: {
type: 'log',
range: [-2,3]
}
};
Plotly.newPlot('myDiv', data,layout);
Path intercepts
This answer is a follow on from my answer to your most resent question.
The code snippet below will find the intercepts of the paths in the tables as structured in this questions example data using a modified intercept function from the answer link in may comment from aforementioned answer.
Note I am assuming that each table eg Test in your example data represents a curve (Path as a set of line segments) and that intercepts are not expected within a table but rather between tables.
Basic solution
It does this by checking each line segment in one table against each line segment in the other and storing all intercepts in an array.
Note that if a intercept is found at the start or end point of a line it may appear in the array of intercepts twice as the intercept test includes these points.
Note lines that are parallel, even if they have matching start and or end points will not count as intercepts.
The example is run against the example data and has a verbose console output to guide, if needed, you working through what ever data sets you are wrangling. The console logs can be removed without ill effect.
var Test = {
x: [8043, 10695, 13292, 17163, 20716, 25270],
y: [1000, 274, 100, 27.4, 10, 2.74],
fill: 'tozeroy',
type: 'scatter',
name: 'Test'
};
var Test2 = {
x: [8043, 10063, 12491, 16081, 19408, 23763],
y: [1000, 274, 100, 27.4, 10, 2.74],
fill: 'tozeroy',
type: 'scatter',
name: 'Test2'
};
var Test3 = {
x: [4700, 5943, 7143, 8841, 10366, 13452],
y: [1000, 274, 100, 27.4, 10, 2.74],
fill: 'tozeroy',
type: 'scatter',
name: 'Test3'
};
// Copy from here to end comment and place into you page (code base)
// lines outputting to the console eg console.log are just there to help you out
// and can be removed
const lineIntercepts = (() => {
const Point = (x, y) => ({x, y});
const Line = (p1, p2) => ({p1, p2});
const Vector = line => Point(line.p2.x - line.p1.x, line.p2.y - line.p1.y);
function interceptSegs(line1, line2) {
const a = Vector(line1), b = Vector(line2);
const c = a.x * b.y - a.y * b.x;
if (c) {
const e = Point(line1.p1.x - line2.p1.x, line1.p1.y - line2.p1.y);
const u = (a.x * e.y - a.y * e.x) / c;
if (u >= 0 && u <= 1) {
const u = (b.x * e.y - b.y * e.x) / c;
if (u >= 0 && u <= 1) {
return Point(line1.p1.x + a.x * u, line1.p1.y + a.y * u);
}
}
}
}
const PointFromTable = (t, idx) => Point(t.x[idx], t.y[idx]);
const LineFromTable = (t, idx) => Line(PointFromTable(t, idx++), PointFromTable(t, idx));
return function (table1, table2) {
const results = [];
var i = 0, j;
while (i < table1.x.length - 1) {
const line1 = LineFromTable(table1, i);
j = 0;
while (j < table2.x.length - 1) {
const line2 = LineFromTable(table2, j);
const point = interceptSegs(line1, line2);
if (point) {
results.push({
description: `'${table1.name}' line seg index ${i}-${i+1} intercepts '${table2.name}' line seg index ${j} - ${j+1}`,
// The description (line above) can be replaced
// with relevant data as follows
/* remove this line to include additional info per intercept
tableName1: table1.name,
tableName2: table2.name,
table_1_PointStartIdx: i,
table_1_PointEndIdx: i + 1,
table_2_PointStartIdx: j,
table_2_PointEndIdx: j + 1,
and remove this line */
x: point.x,
y: point.y,
});
}
j ++;
}
i++;
}
if (results.length) {
console.log("Found " + results.length + " intercepts for '" + table1.name + "' and '" + table2.name + "'");
console.log(results);
return results;
}
console.log("No intercepts found for '" + table1.name + "' and '" + table2.name + "'");
}
})();
// end of code
// Test and example code only from here down.
var res1 = lineIntercepts(Test, Test2);
var res2 = lineIntercepts(Test, Test3);
var res3 = lineIntercepts(Test2, Test3);
Using the above function
This bit of code illustrates how you extract intercepts from the function results
// find all the intercepts for the paths in tabels Test and Test2
const results = lineIntercepts(Test, Test2); // pass two tables
// If results not undefined then intercepts have been found
if (results) { // results is an array of found intercepts
// to get the point/s as there could be several
for (const intercept of results) { // loop over every intercept
// a single intercept coordinate
const x = intercept.x; // get x
const y = intercept.y; // get y
}
}
Better solutions
The paths look very much like they are a plot of some function thus there are even simpler solutions.
Rather than list out lines of code, I will direct you towards graphing calculators in case you are unaware of such useful time savers. They would have solved your problem in the time it takes to enter the data (by copy&paste thats not very long)
Online graphing calculators example apps Geogebra and Desmos and many more.

Group an Array of Vectors according to certain Floors in Three.js

I have a list of Vectors which represent points on three different floors in three.js.
I am trying to group these vectors according to the floor they belong to. Is there a good formula to do this? Perhaps find height from on vector or something. Not sure how to go about this. Any help would be appreciated.
Thanks,
Rob
As Wilt said... Can't really help you without more info.
Still, if your floors are even and all stand on the xz plane (in my example), You may indeed check the points' height (position.y) against the floors'.
var container, renderer, scene, camera, controls;
var floors = [];
var points = [], materials = [], heights = [];
init();
animate();
function init() {
// renderer
renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
container = document.createElement('div');
document.body.appendChild(container);
container.appendChild(renderer.domElement);
// scene
scene = new THREE.Scene();
// camera + controls
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.set(0, 50, 750);
camera.lookAt(scene.position);
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.autoRotate = true;
//floors
for(i=0; i<3; i++) {
var planeGeometry = new THREE.BoxGeometry(500, 500, 10, 10);
var planeMaterial = new THREE.MeshBasicMaterial({
color: 0xffffff * Math.random(),
side: THREE.DoubleSide,
transparent: true,
opacity : 0.3,
depthWrite : false //get rid of coplanar glitches wall/floor
});
materials.push(planeMaterial);
var plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.rotation.x = Math.PI / 2;
//plane.rotation.y = Math.PI / 8; //Uncomment to see this doesn't work if the floors move, i.e. changing rotation/position. If this is what you need, just raycast from point to floor in the animation loop and count how many floors the ray goes through (intersects.length)
plane.position.y = 75*i;
heights.push(plane.position.y);
floors.push(plane);
scene.add(plane);
}
//wall
var height = heights[2];
var planeGeometry = new THREE.BoxGeometry(500, height+100, 10, 10);
var planeMaterial = new THREE.MeshBasicMaterial({
color: 0xffffff * Math.random(),
side: THREE.DoubleSide,
transparent: true,
opacity:0.3,
depthWrite : false //get rid of coplanar glitches wall/floor
});
materials.push(planeMaterial);
var plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.position.y = heights[1]+45;
plane.position.z = -510/2;
scene.add(plane);
// points
for (i=0; i<200; i++) {
var sphereGeometry = new THREE.SphereGeometry(3, 32, 16);
var sphere = new THREE.Mesh(sphereGeometry);
sphere.position.x = Math.random() * 500 - 250;
sphere.position.y = Math.random() * 300 - 100;
sphere.position.z = Math.random() * 500 - 250;
scene.add(sphere);
points.push(sphere);
}
// events
window.addEventListener('resize', onWindowResize, false);
}
function onWindowResize(event) {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function addSpheres() {
//addSpheres
for (i=0;i<200;i++) {
var that = points[i].position.y;
points[i].position.y = ( that < heights[0] ) ? 200 : that - 0.5;
if ( that > heights[0] && that < heights[1] ) points[i].material = materials[0];
if ( that < heights[2] && that > heights[1] ) points[i].material = materials[1];
if ( that > heights[2] ) points[i].material = materials[2];
points[i].material.needsUpdate = true;
}
}
function animate() {
controls.update();
addSpheres();
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
<script src="http://threejs.org/build/three.min.js"></script>
<script src="http://threejs.org/examples/js/controls/OrbitControls.js"></script>
Now, feel free to "group" these points according to your needs.
Please note that "vectors" are different from "points". Read more about the difference.
Raycasting would be the way to go if you had a more complex scene (moving floors/different planes, points moving in different directions).

How to put a infowindow on polyline in Google Maps v3?

I want to know how to show infowindow on polyline in using Google Maps Api V3? and to appear in the middle of the polyline ?!
Firstly you will need to calculate the middle/center of the polyline. This has been discussed and answered here;
https://stackoverflow.com/a/9090409/787921
Then you will have to open the infowindow;
var infowindow = new google.maps.InfoWindow({
content: "infowindow text content"});
infowindow.setPosition(midLatLng);
infowindow.open(map);
find the middle point and set your custom view .
func showPath(polyStr :String){
polyline?.map = nil
mapView1.reloadInputViews()
pathDraw = GMSPath(fromEncodedPath: polyStr)!
polyline = GMSPolyline(path: pathDraw)
polyline?.strokeWidth = 4.0
polyline?.strokeColor = UIColor.init(red: 247/255.0, green: 55/255.0, blue: 76/255.0, alpha: 1.0)
polyline?.map = mapView1
let poinsCount = pathDraw.count()
let midpoint = pathDraw.coordinate(at: poinsCount)
DispatchQueue.main.async
{
self.addMarkerPin(corrdinate: midCordinate, distance: "10 min")
}
}
func addMarkerPin(corrdinate:CLLocationCoordinate2D, distance: String)
{
let marker = GMSMarker()
marker.position = corrdinate
PathTimeView = PathInfoView.loadFromNib() //here i am load Xib file, you can use your custom view
let DynamicView=PathTimeView
DynamicView.timelbl.text = distance
UIGraphicsBeginImageContextWithOptions(DynamicView.frame.size, false, UIScreen.main.scale)
DynamicView.layer.render(in: UIGraphicsGetCurrentContext()!)
let imageConverted: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
marker.icon = imageConverted
marker.map = self.mapView1
marker.infoWindowAnchor = CGPoint(x: -1900 , y: -2000)
}
First you should got center/middle of polyline and this what works for me
private fun centerPos(points: MutableList<LatLng>): LatLng {
val middleDistance = SphericalUtil.computeLength(points).div(2)
return extrapolate(points, points.first(), middleDistance.toFloat()) ?: points[0]
}
private fun extrapolate(path: List<LatLng>, origin: LatLng, distance: Float): LatLng? {
var extrapolated: LatLng? = null
if (!PolyUtil.isLocationOnPath(
origin,
path,
false,
1.0
)
) { // If the location is not on path non geodesic, 1 meter tolerance
return null
}
var accDistance = 0f
var foundStart = false
val segment: MutableList<LatLng> = ArrayList()
for (i in 0 until path.size - 1) {
val segmentStart = path[i]
val segmentEnd = path[i + 1]
segment.clear()
segment.add(segmentStart)
segment.add(segmentEnd)
var currentDistance = 0.0
if (!foundStart) {
if (PolyUtil.isLocationOnPath(origin, segment, false, 1.0)) {
foundStart = true
currentDistance = SphericalUtil.computeDistanceBetween(origin, segmentEnd)
if (currentDistance > distance) {
val heading = SphericalUtil.computeHeading(origin, segmentEnd)
extrapolated = SphericalUtil.computeOffset(
origin,
(distance - accDistance).toDouble(),
heading
)
break
}
}
} else {
currentDistance = SphericalUtil.computeDistanceBetween(segmentStart, segmentEnd)
if (currentDistance + accDistance > distance) {
val heading = SphericalUtil.computeHeading(segmentStart, segmentEnd)
extrapolated = SphericalUtil.computeOffset(
segmentStart,
(distance - accDistance).toDouble(),
heading
)
break
}
}
accDistance += currentDistance.toFloat()
}
return extrapolated
}
then You can add infoWindow with normal way with your platform at it is differ from each platform

Resources