In the paper.js framework the following code performs a hit test on the point of a mouse coordinate.
function onMouseUp(event)
{
var hitOptions = {
stroke: false,
fill: true,
tolerance: 2
};
var hitResult = project.hitTest(event.point, hitOptions);
}
What I would like to do is to perform this test within a given radius of the event.point() but I haven't found a way yet.
Any ideas?
UPDATE
I think the way I was setting the options caused tolerance to be ignored. The following code works:
var hitOptions = {
fill: true,
stroke: true,
segments: true,
tolerance: 200
};
var hitResult = project.hitTest(event.point, hitOptions);
alert(hitResult);
It looks like the tolerance options isn't read due to a bug. You can manually change the tolerance by modifying line 3631 (in the nightly). For example, if you want a test radius of 200 points:
tolerance: paper.project.options.hitTolerance || 2
to:
tolerance: paper.project.options.hitTolerance || 200
Related
I have a path that draw a circle whose origin is in the "west" side, then I split by removing the top and bottom. Then I get three sub-paths:
Top-left 1/4 circle
Right half circle
Bottom-left 1/4 circle
But even visually 1 and 3 looks like a flipped 2, 1 and 3 are actually two sub-paths. How do I optimize this? I've tried smooth(), flatten() and simplify() and all not work.
Here is the sketch.
Based on your simplified case, you just have to build a new path composed of all your sub paths segments.
In order to optimize the resulting path a bit, you can skip the first segment of path B and only keep its handle out, since it's the same than path A last segment.
Depending on your use case, you could also, with the same logic, skip the last segment of path B since it's the same than path A first segment and make sure that the resulting path is set to closed.
Here is a sketch demonstrating a possible implementation.
const compoundPath = project.importJSON(
['CompoundPath', { 'applyMatrix': true, 'children': [['Path', { 'applyMatrix': true, 'segments': [[50, 700], [0, 700], [0, 600], [50, 600]] }], ['Path', { 'applyMatrix': true, 'segments': [[50, 600], [100, 600], [100, 700], [50, 700]] }]] }]
);
compoundPath.strokeColor = 'black';
project.activeLayer.addChild(compoundPath);
const subPaths = [];
compoundPath.children.forEach((child, i) => {
subPaths.push(
child
.clone()
.translate(0, 150)
.addTo(project.activeLayer)
);
});
const assembledPath = assembleSubPaths(subPaths);
assembledPath.strokeColor = 'black';
function assembleSubPaths(subPaths) {
const path = new Path();
subPaths.forEach((subPath) => {
subPath.segments.forEach((segment, segmentIndex) => {
const isFirstSegment = segmentIndex === 0;
if (path.segments.length === 0 || !isFirstSegment) {
path.add(segment);
} else {
path.lastSegment.handleOut = segment.handleOut;
}
});
subPath.remove();
});
return path;
}
I need to distinctly select a single Curve of a clicked Path, how can I do that?
For example, in this sketch we can select a whole path when clicked on it:
Currently I can detect the curve (not sure if it is the appropriate approach, anyway):
..onMouseDown = (event) ~>
hit = scope.project.hitTest event.point
if hit?item
# select only that specific segment
curves = hit.item.getCurves!
nearest = null
dist = null
for i, curve of curves
_dist = curve.getNearestPoint(event.point).getDistance(event.point)
if _dist < dist or not nearest?
nearest = i
dist = _dist
selected-curve = curves[nearest]
..selected = yes
But whole path is selected anyway:
What I want to achieve is something like this:
There is an easier way to achieve what you want.
You can know if hit was on a curve by checking its location property.
If it is set, you can easily get the curve points and manually draw your selection.
Here is a sketch demonstrating it.
var myline = new Path(new Point(100, 100));
myline.strokeColor = 'red';
myline.strokeWidth = 6;
myline.add(new Point(200, 100));
myline.add(new Point(260, 170));
myline.add(new Point(360, 170));
myline.add(new Point(420, 250));
function onMouseDown(event) {
hit = paper.project.hitTest(event.point);
// check if hit is on curve
if (hit && hit.location) {
// get curve
var curve = hit.location.curve;
// draw selection
var selection = new Group(
new Path.Line({
from: curve.point1,
to: curve.point2,
strokeColor: 'blue',
strokeWidth: 3
}),
new Path.Rectangle({
from: curve.point1 - 5,
to: curve.point1 + 5,
fillColor: 'blue'
}),
new Path.Rectangle({
from: curve.point2 - 5,
to: curve.point2 + 5,
fillColor: 'blue'
})
);
// make it automatically be removed on next down event
selection.removeOnDown();
}
}
Update
As an alternative, to avoid messing up with the exported drawing, you can simply select the line instead of applying it a stroke style.
See this sketch.
var selection = new Path.Line({
from: curve.point1,
to: curve.point2,
selected: true
});
There is no built-in way to do what you'd like AFAIK.
You basically need to walk through the segments, construct a line, and see if the hit is on that particular line. The line cannot be transparent or it's not considered a hit which is why I give it color and width to match the visible line; it's also why it's deleted after the test.
Here's the sketch solution that implements a bit more around this:
function onMouseDown(event){
if (!myline.hitTest(event.point)) {
return
}
c1.remove()
c2.remove()
// there's a hit so this should find it
let p = event.point
let segs = myline.segments
for (let i = 1; i < segs.length; i++) {
let line = new Path.Line(segs[i - 1].point, segs[i].point)
line.strokeWidth = 6
line.strokeColor = 'black'
if (line.hitTest(p)) {
c1 = new Path.Circle(segs[i-1].point, 6)
c2 = new Path.Circle(segs[i].point, 6)
c1.fillColor = 'black'
c2.fillColor = 'black'
line.remove()
return
}
line.remove()
}
throw new Error("could not find hit")
}
Here's what I draw:
I have some code to export an LS8 image to Drive using GEE. Somehow, the resolution of the image seems to be lower (larger pixels) than what I am able to see on the browser. How can I increase the resolution? This is the code I´ve been using, with two different options.
I attempted to use .resample() as a solution but it produced a single band image that did not look good.
geometry2 = /* color: #57d64b */ee.Geometry.Polygon(
[[[-78.2812086867645, 2.3386717366200585],
[-77.56984394067075, 2.3729749945579948],
[-77.72227924340513, 2.776314152654142],
[-78.20842426293638, 2.725560942159387]]]);
function maskL8sr(image)
{
// Bits 3 and 5 are cloud shadow and cloud, respectively.
var cloudShadowBitMask = ee.Number(2).pow(3).int();
var cloudsBitMask = ee.Number(2).pow(5).int();
// Get the pixel QA band.
var qa = image.select('pixel_qa');
// Both flags should be set to zero, indicating clear conditions.
var mask = qa.bitwiseAnd(cloudShadowBitMask).eq(0)
.and(qa.bitwiseAnd(cloudsBitMask).eq(0));
// Return the masked image, scaled to TOA reflectance, without the QA bands.
return image.updateMask(mask).divide(10000)
.select("B[0-9]*")
.copyProperties(image, ["system:time_start"]);
}
// Map the function over one year of data.
var collection = ee.ImageCollection('LANDSAT/LC08/C01/T1_SR')
.filterDate('2016-04-01', '2018-7-31')
.map(maskL8sr)
var composite = collection.median();
var VIS = {bands: ['B5', 'B6', 'B4'], min: 0, max: 0.47};
// Display the results.
Map.addLayer(composite,VIS ,"compt2");
var params ={
crs: 'EPSG:4326',
maxPixels: 1e12,
region:geometry2
}
Export.image(composite,'Guapi',params);
Export.image.toDrive({
image: composite,
description: 'Guapi',
scale: 30,
region: geometry2,
maxPixels: 1000000000
});
I am using Chart.js 2.0 version to draw graphs, i want to define minimum step size in bar graph
var myNewChart = new Chart(grapharea, {
type: 'bar',
data: barData,
options: {
responsive: true,
scales: {
yAxes: [
{
ticks: {
min: 0, // it is for ignoring negative step.
beginAtZero: true,
stepSize: 1 // if i use this it always set it '1', which look very awkward if it have high value e.g. '100'.
}
}
]
}
}
});
this time i am using
stepSize: 1
i am using this step size to ignore the point value e.g. '0.5', it shows when the max graph values id less e.g '2'.
if i use this it always set the step it '1', which look very awkward if it have high value e.g. '100'.
I am looking for such thing:
suggestedMin = 1
Is there any thing to define thie minimum step size which should not be fixed in higher value cases.
If you don't want to show point value (e.g. 0.5) labels you could write a callback function to filter the point value labels instead of using stepSize.
Like this:
ticks: {
min: 0, // it is for ignoring negative step.
beginAtZero: true,
callback: function(value, index, values) {
if (Math.floor(value) === value) {
return value;
}
}
}
Working fiddle here: https://jsfiddle.net/ma7h611L/
Update:
As noted by Atta H. and Lekoaf below, Chart.js added the precision property to ticks. It is available since version 2.7.3. See Lekoaf's answer how to use this.
ticks: {
precision: 0
}
This worked equally well as the callback function above and is much cleaner.
precision, if defined and stepSize is not specified, the step size will be rounded to this many decimal places.
https://www.chartjs.org/docs/latest/axes/cartesian/linear.html
Is it possible to create a single gravity / force point in matter.js that is at the center of x/y coordinates?
I have managed to do it with d3.js but wanted to enquire about matter.js as it has the ability to use multiple polyshapes.
http://bl.ocks.org/mbostock/1021841
The illustrious answer has arisen:
not sure if there is any interest in this. I'm a fan of what you have created. In my latest project, I used matter-js but I needed elements to gravitate to a specific point, rather than into a general direction. That was very easily accomplished. I was wondering if you are interested in that feature as well, it would not break anything.
All one has to do is setting engine.world.gravity.isPoint = true and then the gravity vector is used as point, rather than a direction. One might set:
engine.world.gravity.x = 355;
engine.world.gravity.y = 125;
engine.world.gravity.isPoint = true;
and all objects will gravitate to that point.
If this is not within the scope of this engine, I understand. Either way, thanks for the great work.
You can do this with the matter-attractors plugin. Here's their basic example:
Matter.use(
'matter-attractors' // PLUGIN_NAME
);
var Engine = Matter.Engine,
Events = Matter.Events,
Runner = Matter.Runner,
Render = Matter.Render,
World = Matter.World,
Body = Matter.Body,
Mouse = Matter.Mouse,
Common = Matter.Common,
Bodies = Matter.Bodies;
// create engine
var engine = Engine.create();
// create renderer
var render = Render.create({
element: document.body,
engine: engine,
options: {
width: Math.min(document.documentElement.clientWidth, 1024),
height: Math.min(document.documentElement.clientHeight, 1024),
wireframes: false
}
});
// create runner
var runner = Runner.create();
Runner.run(runner, engine);
Render.run(render);
// create demo scene
var world = engine.world;
world.gravity.scale = 0;
// create a body with an attractor
var attractiveBody = Bodies.circle(
render.options.width / 2,
render.options.height / 2,
50,
{
isStatic: true,
// example of an attractor function that
// returns a force vector that applies to bodyB
plugin: {
attractors: [
function(bodyA, bodyB) {
return {
x: (bodyA.position.x - bodyB.position.x) * 1e-6,
y: (bodyA.position.y - bodyB.position.y) * 1e-6,
};
}
]
}
});
World.add(world, attractiveBody);
// add some bodies that to be attracted
for (var i = 0; i < 150; i += 1) {
var body = Bodies.polygon(
Common.random(0, render.options.width),
Common.random(0, render.options.height),
Common.random(1, 5),
Common.random() > 0.9 ? Common.random(15, 25) : Common.random(5, 10)
);
World.add(world, body);
}
// add mouse control
var mouse = Mouse.create(render.canvas);
Events.on(engine, 'afterUpdate', function() {
if (!mouse.position.x) {
return;
}
// smoothly move the attractor body towards the mouse
Body.translate(attractiveBody, {
x: (mouse.position.x - attractiveBody.position.x) * 0.25,
y: (mouse.position.y - attractiveBody.position.y) * 0.25
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.12.0/matter.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/matter-attractors#0.1.6/build/matter-attractors.min.js"></script>
Historical note: the "gravity point" functionality was proposed as a feature in MJS as PR #132 but it was closed, with the author of MJS (liabru) offering the matter-attractors plugin as an alternate. At the time of writing, this answer misleadingly seems to indicate that functionality from the PR was in fact merged.
Unfortunately, the attractors library is 6 years outdated at the time of writing and raises a warning when using a newer version of MJS than 0.12.0. From discussion in issue #11, it sounds like it's OK to ignore the warning and use this plugin with, for example, 0.18.0. Here's the warning:
matter-js: Plugin.use: matter-attractors#0.1.4 is for matter-js#^0.12.0 but installed on matter-js#0.18.0.
Behavior seemed fine on cursory glance, but I'll keep 0.12.0 in the above example to silence it anyway. If you do update to a recent version, note that Matter.World is deprecated and should be replaced with Matter.Composite and engine.gravity.