Ace Editor: Can't get rid of Marker - javascript

I am writing a simple widget that simulates a simple 8-bit CPU. For that I am abusing the Ace Editor, as you can see at the center of the image, as my "RAM"-view.
I want to highlight the line that corresponds to the value of the program counter and I am using addMarker() to do so.
However, I can't seem to get rid of that marker once I have set it. _marker is a private member that holds the value of the last marker set. But for some reason removeMarker(_marker) has no effect:
/**
*
*/
setMarker: function(position) {
//if(_marker != null) {
window.cpuRamView.session.removeMarker(_marker);
//}
_marker = new window.Range(position, 0, position, _content[position].length);
window.cpuRamView.session.addMarker(
_marker, "programCounterLocation", "fullLine"
);
}
What am I doing wrong here? :/

add marker returns an id, and removeMarker requires that id, so you can do something like
var Range = require("ace/range").Range // not the window Range!!
var _range
setMarker = function(position) {
if(_range != null) {
window.cpuRamView.session.removeMarker(_range.id);
}
_range = new Range(position, 0, position, _content[position].length);
_range.id = window.cpuRamView.session.addMarker(
_range, "programCounterLocation", "fullLine"
);
}

if(this.marker) {
this.editor.getSession().removeMarker(this.marker);
}
this.marker = this.editor.getSession().addMarker(
new Range(prop('errorLine')(formulaError), prop('errorPosition')(formulaError), prop('errorLine')(formulaError), prop('errorPosition')(formulaError) + 5), style.errorMarker, 'text');
}

set a variable marker to receive the return value, just like this:
marker=editor.session.addMarker(range, "myMarker", "fullLine");
and then remove this marker, like this:
editor.session.removeMarker(marker);

Related

How to add a marker to Mapbox on click event?

I'm a french student in computering and I have to use Mapbox but since I create a class I'm stuck by this error.When I wasn't in a class it worked perfectly but now it's fully broken.And I saw on some topics it could come from safari but I already tested it on Mozilla and it still broken.
This is my class.
constructor() {
//Temporary array of currentMarkers
let currentMarkers=[];
let type ="";
//Create the map
mapboxgl.accessToken = 'private data';
this.mapbox = new mapboxgl.Map({
container: 'map', // container id
style: 'mapbox://styles/mapbox/streets-v11',
center: [-74.5, 40], // starting position
zoom: 9 // starting zoom
});
//Add search bar from a plugin
let geocoder = new MapboxGeocoder({
accessToken: mapboxgl.accessToken,
placeholder: 'Saissisez une adresse', // Placeholder text for the search bar
marker: {
color: 'orange'
},
mapboxgl: mapboxgl
});
this.mapbox.addControl(geocoder);
const mbox = this;
this.mapbox.on("click",function(){
this.getcoordonates();
});
//Allow us to create marker just with a research
geocoder.on('result', function(e) {
//Deleting all current markers
if (currentMarkers!==null) {
for (let i = currentMarkers.length - 1; i >= 0; i--) {
currentMarkers[i].remove();
}
}
//Add the markers who come with the research
this.addMarker(e.result.center[0],e.result.center[1]);
// Delete the last marker who got placed
//currentMarkers[currentMarkers.length - 1].remove();
});
this.addPoint(2.333333 ,48.866667 ,"supervisor");
}
//split the JSON.stringify(e.lngLat.wrap()) to get the coordinates
async mysplit(m){
let z = m.split(',');
let x = z[0].replace("{\"lng\":","");
let g = z[1].replace("\"lat\":","");
let y = g.replace("}","");
await addMarker(x,y);
}
//Add a marker on click after the excution of mysplit() function
async addMarker(x,y) {
// tmp marker
let oneMarker= new mapboxgl.Marker()
.setLngLat([x,y])
.addTo(this.mbox);
currentMarkers.push(oneMarker);
}
// Get the coordinates and send it to split function
getcoordonates(){
mbox.on('click',function(e){
let m = JSON.stringify(e.lngLat.wrap());
this.mbox.mysplit(m);
});
}
addPoint(y,x,type)
{
let color ="";
let t = type;
if(t == "supervisor")
{
color = "grey";
}else if (t =="fieldworker") {
color = "red";
}else if (t == "intervention") {
color = "blue";
}else alert("Nous ne pouvons pas ajouter votre marker\nLatitude : "+x+"\nLongitude :"+y+"\n car "+t+" n'est pas un type reconnu" );
let myMarker = new mapboxgl.Marker({"color": color})
.setLngLat([y,x])
.addTo(this.mbox);
}
}
Thanks for help and have a good day :) ! Sorry if my English isn't that good.
As the first step, the
this.mapbox.on("click", function(e){
this.getcoordonates();
});
was called outside of any method of the Map class. It would most probably belong to the constructor (as discussed above in the question's comments section).
Next, the callback changes the scope of this, so it is not anymore pointing to a Map instance. A common solution to this issue is to store/backup this before, something like:
constructor() {
...
const thisObject = this;
this.mapbox.on("click", function(e) {
thisObject.getcoordonates();
});
}
Update:
The logic of code in its current form tries to add a new click event listener every time the map is clicked. Which is not desired. This getcoordonates() function is not really needed. Instead this should work (never tested it, it is based on your code):
constructor() {
...
const mbox = this;
this.mapbox.on("click", function(e) {
let m = JSON.stringify(e.lngLat.wrap());
mbox.mysplit(m);
});
}
Remarks:
There is no real logic behind JSON-encoding the lngLat object before calling mysplit just to decode it there.
You won't need it here, but the reverse of the JSON.stringify() is JSON.parse(). There is no need to work with it on a string level, like the current mysplit() method does.
Instead, the mysplit() method should be called directly with the e.lngLat object as its argument.
Going further, since there is no "splitting" (decoding) really needed, the mysplit() method isn't really needed either.
In the end, something like this should work:
constructor() {
...
const mbox = this;
this.mapbox.on("click", function(e) {
await mbox.addMarker(e.lngLat.lng, e.lngLat.lat);
});
}

Getting Data into the JSON

I am trying to visulize Coordinates on the map . Data is Coming form json.
I am getting and error Push is undefined. I am passing the Array but getting error
Here is the Code
var testCtrl = this;
testCtrl.allOrgUnits = response.organisationUnits;
console.log(testCtrl.allOrgUnits)
for (i = 0; i < testCtrl.allOrgUnits.length; i++) {
if(testCtrl.allOrgUnits[i].coordinates != undefined && testCtrl.allOrgUnits[i].coordinates.length < 200) {
testCtrl.geoCoords.push(new Array(testCtrl.allOrgUnits[i].name, testCtrl.allOrgUnits[i].coordinates.substring(1,testCtrl.allOrgUnits[i].coordinates.length-1).split(",")));
}
}
// Add the coordinates to the map.
addMarkers(testCtrl.geoCoords);
});
JSON Data is like
organization units [{ "name":david , "coordinates""[ 10.24 ,23.80] { "name":phil , "coordinates""[ 35.80 ,23.80]
Here is the Function addMarkers
function addMarkers(coordinates) {
var marker;
markers = [];
for (i = 0; i < coordinates.length; i++) {
// Create and add a new marker per coordinate.
marker = new google.maps.Marker({
position: new google.maps.LatLng(coordinates[i][1][1], coordinates[i][1][0]),
map: map,
title: coordinates[i][0],
icon: blueMarker,
current: false,
});
markers.push(marker);
// Add a listener to each marker, so that they will display the name of the facility when clicked.
google.maps.event.addListener(marker, 'click', (function(marker, i) {
return function() {
infowindow.setContent("<div class='info'><h4>" + coordinates[i][0] + "</h4>Facility</div>");
infowindow.open(map, marker);
}
})(marker, i));
}
You probably need to initialize geoCords to be an array before trying to push something.
testCtrl.geoCoords = [];
You are trying to call push method on undefined
You are doing this
testCtrl.geoCoords.push()
where testCtrl has no property geoCoords, so first initialize this property like
testCtrl.geoCoords = []
Now it is an empty array , you can use push method on this
You could transform your json into Object, it might be easier after that.
private ObjectMapper mapper = new ObjectMapper();
listPersonCoordinates = mapper.readValue(query_result, new TypeReference<ArrayList<PersonCoordinate>>(){})
for (PersonCoordinate pc : listPersonCoordinate) {
pc.getName();
pc.getCoordinate();
// Do your stuff here
}
and
public Class PersonCoordinate {
String name;
ArrayList<double> coordinate;
// getters + setters + constructor
}
Hope this help :)
Edit : Your JSON looks strangely formatted. misses some "

How to get the area string from a polygon using leaflet.draw

I am trying to get the area measurements of polygons so I can list them in a table to the side of the map, next to the name of the polygon. This is what I have tried with no success:
$("#polygon").on("click", function (){
createPolygon = new L.Draw.Polygon(map, drawControl.options.polygon);
createPolygon.enable();
}
var polygon = new L.featureGroup();
map.on('draw:created', function (e) {
var type = e.layerType,
layer = e.layer;
if (type === 'polygon') {
polygons.addLayer(layer);
}
var seeArea = createPolygon._getMeasurementString();
console.log(seeArea); //Returns null
}
Any help on this would be appreciated!
You can access the geometry utility library provided with Leaflet.
var area = L.GeometryUtil.geodesicArea(layer.getLatLngs());
In your example, you are trying to access a control itself, which is what the variable createPolygon is assigned to. Instead, you want to take the area of the layer that got drawn.
map.on('draw:created', function (e) {
var type = e.layerType,
layer = e.layer;
if (type === 'polygon') {
polygons.addLayer(layer);
var seeArea = L.GeometryUtil.geodesicArea(layer.getLatLngs());
console.log(seeArea);
}
}
Once you verify you are getting the area, you can just assign it to the variables that populate the table next to the map.
Note: area will be in squareMeters by default
I found that none of the above answers worked for calculating the area of non-contiguous polygons. Here's an example polygon where the above functions returned an area of 0:
For anyone who needs to do that, here is the code that worked for me (using the L.GeometryUtil function from Leaflet.draw):
var poly = // Your polygon layer here; may or may not be contiguous
var area = 0;
for (island of poly.getLatLngs()) {
// If the polygon is non-contiguous, access the island
if (island.length < 2) {
island = island[0]
}
// Sum the area within each "island"
area += L.GeometryUtil.geodesicArea(island);
}
L.GeometryUtil.geodesicArea(layer.getLatLngs())[0] should get you the area.
But I ended up using leaflet-geoman-free to do the drawing and use turf.js to get the area.
map.pm.enableDraw('Polygon', {
snappable: true,
snapDistance: 20,
});
map.on('pm:create', e => {
const layer = e.layer
alert(turf.area(layer.toGeoJSON()))
});
add corrections:
var seeArea = L.GeometryUtil.geodesicArea(layer.getLatLngs()[0]);
console.log(seeArea);

Erase a path in paper.js?

I basically want to create a new path with the canvas globalCompositeOperation set to 'destination-out'. Is this possible? If so, how?
I noticed that Item has a blendMode property: http://paperjs.org/reference/item#blendmode, but trying the different values does not provide the desired effect.
http://jsfiddle.net/D8vMG/12/
In light of your recent comment, you would need to create layers, as described here:
http://paperjs.org/tutorials/project-items/project-hierarchy/#removing-items-and-children
and then you can add your paths to a layer and do something like this:
//add image to project as background
// ... your code here ...
var secondLayer = new Layer();
Whenever you create a new Layer, it becomes the active layer of the project, and then you can draw on top of the second layer all you want.
if you want a simple 'undo' button you can do:
function onMouseDown(event) {
if (window.mode == "drawing") {
myPath = new Path();
myPath.strokeColor = 'black';
}
else if (window.mode == "undo") {
myPath.opacity = '0'; //this makes the last path used completely see through
// or myPath.remove(); // this removes the path.
//if you're intent on something that writes and erases, you could do
}
}
But what you are looking for is something like this:
function onMouseDrag(event) {
if (window.mode == "drawing") {
myPath.add(event.point);
}
else if (window.mode == "erasing") {
myPath.removeSegment(0);
}
}
this erases the segments of the path from beginning to end. For the full functionality, you need something that identifies a path on click, (layer.getChildren() ? then select child). Then using the point on mouse move you need to identify the segment index and remove it from the path using .removeSegment(index).
http://paperjs.org/reference/path#removesegment-index
Well, the simple solution would be to just create a path which is white. http://jsfiddle.net/D8vMG/11/
function onMouseDown(event) {
if (window.mode == "drawing") {
myPath = new Path();
myPath.strokeColor = 'black';
}
else if (window.mode == "erasing") {
myPath = new Path();
myPath.strokeColor = 'white';
myPath.strokeWidth = 10;
}
}

In Graphiti, how to put an editor on a label attached to a Figure

I was trying to create an editable label like the one in the example connection_labeledit_inplace.
The problem I have is that I want to attach the label to a custom VectorFigure in place of a Connection. When doing that the label is just part of the figure and don't launch the editor.
ivr.shape.menu.MenuItem = graphiti.VectorFigure.extend({
NAME:"ivr.shape.menu.MenuItem",
MyOutputPortLocator : graphiti.layout.locator.Locator.extend({
init: function(parent)
{
this._super(parent);
},
relocate:function(index, figure){
var w = figure.getParent().getWidth();
var h = figure.getParent().getHeight();
figure.setPosition(w, h/2);
}
}),
/**
* #constructor
* Creates a new figure element which are not assigned to any canvas.
*
*/
init: function( width, height) {
this._super();
this.setBackgroundColor( new graphiti.util.Color(200,200,200));
this.setColor(new graphiti.util.Color(50,50,50));
// set some good defaults
//
if(typeof width === "undefined"){
this.setDimension(100, 15);
}
else{
this.setDimension(width, height);
}
// add port
var outputLocator = new this.MyOutputPortLocator(this);
this.createPort("output",outputLocator);
this.label = new graphiti.shape.basic.Label("I'm a Label");
this.label.setColor("#0d0d0d");
this.label.setFontColor("#0d0d0d");
this.addFigure(this.label, new graphiti.layout.locator.LeftLocator(this));
this.label.installEditor(new graphiti.ui.LabelInplaceEditor());
},
repaint : function(attributes)
{
if(this.repaintBlocked===true || this.shape===null){
return;
}
if (typeof attributes === "undefined") {
attributes = {};
}
var box = this.getBoundingBox();
var center = box.getCenter();
var path = ["M",box.x,",",box.y];
path.push("l", box.w-10, ",0");
path.push("l10,", box.h/2);
path.push("l-10,", box.h/2);
path.push("L",box.x,",", box.getBottomLeft().y);
path.push("Z");
var strPath = path.join("");
attributes.path = strPath;
this._super(attributes);
},
/**
* #method
* Called by the framework. Don't call them manually.
*
* #private
**/
createShapeElement:function()
{
// create dummy line
return this.canvas.paper.path("M0 0L1 1");
}
});
For this example I put the label on the left of the Figure but obviously I'll make a Locator that puts the label ON the figure (just in case it changes something)
Up to me the issue is coming from the way the 'graphiti.Canvas.getBestFigure()' works. The function check only over elements directly attached to the 'graphity.Canvas' Also, the function is missing some recursion to propagates the event on the children.
Graphiti provides a CenterLocator.
All events like dblClick can be catched by the figure.
....did youuse thelatest version?

Categories

Resources