Select only specific polygon of the feature, OpenLayers - openlayers-3

A Feature is made of several parts, how do i select just one of them on mouse click in openLayers?
By default the whole feature gets selected.

I think you would need to create a new source containing features with single polygon geometry. Give them a parent property if you need to access the original feature. For example
mainSource.on('addfeature', function(event) {
var geometry = event.feature.getGeometry();
if (geometry.getType() == 'MultiPolygon') {
geometry.getPolygons().forEach(function(polygon) {
splitSource.addFeature(new Feature({
geometry: polygon,
parent: event.feature
});
} else {
splitSource.addFeature(event.feature);
}
});

Related

Linking shapes to slides using text search in Google Slides script

Trying to link shapes to slides the same way it's done with images.
.
.
Reason for this request is linking images seems much harder in terms of locating the exact one to be linked.
Have realized it might be best to link shapes through match/search text then insert the images after.
Codes attempted though please ignore if completely irrelevent.
function myFunction(){
var searchText = "IMAGE1";
var presentation = SlidesApp.getActivePresentation();
var slide = presentation.getSlides()[4];
// 2. Replace the shape which has the text of "searchText" with the image of "imageUrl".
slide.getShapes().forEach(s => {
if (s.getText().asString().toLocaleUpperCase().includes(searchText.toLocaleUpperCase())) {
s.setLinkSlide('INSERT_SLIDE_LINK');
}
}
)
}
Slides Example
Thank you
I believe your goal is as follows.
You want to link the shape to a slide by searching the text in the shape on Google Slides.
You want to achieve this using Google Apps Script.
setLinkSlide can use Slides Object. I thought that this might be able to be used.
Sample script:
function myFunction() {
const obj = { text1: 3, text2: 3, text3: 4, text4: 5, text5: 4, text6: 3 }; // This is from your showing sample image.
const slides = SlidesApp.getActivePresentation().getSlides();
slides.forEach(s => {
s.getShapes().forEach(shape => {
const t = obj[shape.getText().asString().toLowerCase().trim()];
if (t) {
shape.setLinkSlide(slides[t - 1]);
}
});
});
}
Note:
This sample script is for your provided sample Google Slides. When you change this, please modify obj. Please be careful about this.
Reference:
setLinkSlide(slide)
SUGGESTION
If I've understood your post correctly, these are your goals:
Check the text on each of the shapes in your slides
See if the current text shape matches the current searchText value
If true, link a dedicated slide to the current shape.
Sample Tweaked Script
function sample() {
var presentation = SlidesApp.getActivePresentation();
var slide = presentation.getSlides();
//Define the 'searchText' value & it's dedicated slide to be linked
var find = {
search: [["Text1", slide[1]],
["Text2", slide[2]],
["Text3", slide[3]]]
};
find.search.forEach(d => {
let searchText = d[0];
let linkSlide = d[1];
slide[0].getShapes().forEach(s => {
s.getText().asString().trim().toLowerCase() === searchText.toLowerCase() ? s.setLinkSlide(linkSlide) : null;
});
})
}

Coloring a region programmatically based by user selection with Highmaps

I have an application where user can select a region by clicking. Then the map rewrites itself and zoomsTo() to the selected area. So far everything else works, but I haven't get any idea how to color the selected area programmatically. The area (or different statistics) may also be selected from a drop-down list, so I have to redraw the map in any case.
var mapChart=$('#mapcontainer').highcharts();
mapChart.get(jQuery( "#selected-region" ).val()).zoomTo();
mapChart.mapZoom(5);
I have tried things along the line:
mapChart.get(jQuery( "#selected-region" ).val()).color="rgb(255,0,0)";
but so far no breakthrough :/
Any ideas?
hank
Using jquery to select point is not the best solution. Highcharts provides point events like click where you have an access to clicked point instance, or you can select a point using the chart.get() method by point id.
To change the selected area color you have to define color property when a point (area) is selected:
series: [{
states: {
select: {
color: '#a4edba'
}
}
}]
Now you have to invoke select() method on the clicked or selected point, as well as you invoked zoomTo() method:
series: [{
point: {
events: {
click: function() {
var point = this;
point.zoomTo();
point.select();
}
}
},
states: {
select: {
color: '#a4edba'
}
}
}]
});
Demo:
https://jsfiddle.net/wchmiel/yzco1023/

Draggable with Vue.js, not being able to return to original position

I'm attempting to have an element's draggable functionality depend on a click event. I'm using jquery-ui's draggable method (within a vue.js instance).
In my Vue instance I have these two data properties: isVisible and a isDraggable. They assume a truthy or falsy value each time the user clicks a button. On my methods object I have the following:
methods: {
toggleBox: function() {
this.IsVisible = !this.IsVisible;
this.isDraggable = !this.isDraggable;
}
}
I'm using the destroy method in order to have the targeted element return to its original position (documentation here). However, I am not getting the intended result, as can be seen in the jsfiddle below. The following is one of many (unsuccessful) attemtps to tackle this issue:
ready: function() {
this.$nextTick(function() {
if (this.isDraggable == true) {
$('.box').draggable({
containment: "window"
})
} else if (this.isDraggable == false) {
$('.box').draggable(
"destroy"
)
}
})
}
Jsfiddle here. I wonder what I'm doing wrong here? Any hint appreciated.
The ready function only gets called once, during initialization of the vm element. Whenever you click on the "toggle" button, there's nothing that tells the nextTick method to execute. I'm not at all familiar with the vue api, so there probably will be a way to do what you want using the nextTick method.
Given my lack of knowledge regarding the api, I came up with a solution that seemed the most straightforward for your requirements i.e. updating the toggleBox method to check the isDraggable property and resetting the position of the box according to its value.
If you introduce other elements, you'd need to implement a solution that takes into account all of the default positions and re-apply them when you click the "toggle" button.
toggleBox: function() {
this.IsVisible = !this.IsVisible;
this.isDraggable = !this.isDraggable;
if (this.isDraggable) {
$('.box').draggable({
containment: "window"
})
} else if (!this.isDraggable) {
$('.box').offset({ top: 8, left: 8});
}
}
Fiddle example
Adding to #Yass's answer above, if instead of hard-coding the offset's top position of the element .box , you wanted to calculate it, here's one way to do it (which is useful in those cases where the browser's window changes size for instance):
toggleBox: function() {
this.IsVisible = !this.IsVisible;
this.isDraggable = !this.isDraggable;
var body = document.body.getBoundingClientRect();
var element = document.querySelector('.box').getBoundingClientRect();
var topPos = body.height - element.height;
if (this.isDraggable) {
$('.box').draggable({
containment: "window"
})
}
else if (!this.isDraggable) {
$('.box').offset({
top: this.topPos,
left: 8});
}
}

Different URL for each GeoJSOn feature

I have a map which loads a GeoJSON file with multiple line features. When I click a line, the map performs some action (in this case, it's changing the bounds and adds some text underneath it).
var trails = new L.GeoJSON.AJAX('https://googledrive.com/host/0B55_4P6vMjhITEU4Ym9iVG8yZUU/trasee.geojson', {
onEachFeature: function(feature, layer){
layer.on({
click: function() {
map.fitBounds(this.getBounds());
$('#description').html('some text ' + feature.properties.id);
}
});
}
}).addTo(map);
Is it possible to have a different URL for every line, so I can access a particular feature directly (for example, https://websiteurl.com#thisfeatureid)? The link would load the map with the bounds and description of the selected feature.
Here's a JSFiddle of the map:
http://jsfiddle.net/pufanalexandru/qxbuwaeg/
Given a url for a trail such as https://websiteurl.com#5, here's one approach.
When the document is ready (leaflet loaded, geojson loaded, map initialized), but before you set the map bounds, use javascript or a URI parser to check for the param for trail id from the url. Simple example:
var trail_id = document.URL.split('#')[1];
If you get an id, search the trails features for a match on that id, and zoom to the bounds, just as you already are on click
trails.eachLayer(function(layer) {
if (layer.feature.properties.id == trail_id) {
map.fitBounds(this.getBounds());
$('#description').html('some text ' + feature.properties.id);
return;
}
}

Two bar graphs in the same place, controlled by one slider D3.js

I am attempting to create a bar graph that when independent sliders are moved they change two bar graph svg heights at the same time and they are stacked, they are different colors show it shows two separate values in the same graph, basically showing growth vs the current. I am using jquery-ui and D3.js. Currently it only moves the one svg elements instead of both at the same time, Id like them both to move at the same time.
HTML
<div id="slider" class="slider">
<label for="amount">Age</label>
<input type="text" id="amount1" style="border:0; font-weight:bold;">
</div>
<div id="slider1" class="slider">
<label for="amount2">Retirement Age</label>
<input type="text" id="amount2" style="border:0; font-weight:bold;">
</div>
JS
//initialize sliders
jQuery(document).ready(function($) {
$("#slider").slider({
max: 100
});
$("#slider").slider({
min: 18
});
$("#slider1").slider({
max: 100
});
$("#slider1").slider({
min: 18
});
//slider actions
$("#slider, #slider1").slider({
value: 10,
animate: "fast" ,
slide: function (event, ui) {
//capture the value of the specified slider
var selection = $("#slider").slider("value");
var selection1 = $("#slider1").slider("value");
//fill the input box with the slider value
$( "#amount1" ).val( selection );
$( "#amount2" ).val( selection1 );
//set width and height, actually I'm a little confused what this is for
var w = 200;
var h = 200;
//data arrays for svgs
var dataset = [];
var dataset1 = [];
//fill the data arrays with slider values
dataset.push(selection);
dataset.push(selection1 + selection);
//draw rectangle on the page
var rectangle = svg.selectAll("rect")
.classed("collapse", true)
.data(dataset);
**
THIS IS WHERE IT CONFUSES ME
**
//I draw the second rectangle here, however I choose the same svg element,
//Im not sure what other way to get it to appear in the same space but
//I am sure this is what is causing my issues
var rectangle1 = svg.selectAll("rect")
.classed("collapse", true)
.data(dataset1);
//not sure what this does
rectangle.enter().append("rect");
rectangle1.enter().append("rect");
rectangle.attr("width", 200).transition().attr("fill", "#A02222").attr("height", function (d) { console.log('d is ' + d);
return d;
}).attr("x", function (d) {
return 40; //I dont know why I return 40?
}).attr("y", function (d) {
return 40; //Same here dont know why I return 40?
});
rectangle1.attr("width", 200).transition().attr("height", function (d) { console.log('d is ' + d);
return d;
}).attr("x", function (d) {
return 40; //I dont know why I return 40?
}).attr("y", function (d) {
return 40; //Same here dont know why I return 40?
});
}
// slider actions ends here
});
//Create SVG element
var svg = d3.select(".svgContain").append("svg").attr("width", 125).attr("height", 300);
});
For starters, you may want to follow this tutorial: http://bl.ocks.org/mbostock/3886208
The "return 40;" that you are wondering about are actually what will specify the position and dimensions of the rect's you're appending to the svg. Those shouldn't just be 40, they should be bound to values in the data set, or based on the index of the bar's series in the set of series or something more meaningful than 40.
There is a stacked bar chart data processor that will take a set of series and spit out a new set of series coordinate definitions that make it easier to calculate how rect's will stack in svg coordinate space: https://github.com/mbostock/d3/wiki/Stack-Layout
Then, there's the more general issue of how to deal with these "nested" data sets where you have series, and in the series there are values and you don't want to have to manually track and select individual series. There are several ways to handle this sort of situation. If you know you will only ever have two series, and you really want fine-grained control over each independently, you could assign the top level object an id and then start the data join for each of the plots by selecting that top level object by id... eg:
var container1 = d3.select("#myContainer1);
container1.selectAll("rect").data(myData1).append("rect");
var container2 = d3.select("#myContainer2);
container2.selectAll("rect").data(myData2).append("rect");
If you do something like that, the first select basically sets the context of the subsequent selects. So, only the rects inside of the "#myContainer1" or "#myContainer2" will get selected by each "selectAll" based on which context you're in.
The other approach is to use nested selections. Nested selections are a little more complicated to wrap your head around, but 90% of the time, this is the approach I use. With nested selections, you would restructure your data slightly and then apply nested selects/joins to bind each series to a dom element and then the values of each series to subelements of each of the series dom elements.
First, read this: http://bost.ocks.org/mike/nest/
and then try making your data something more like this:
data = [
{ key: "series1", values: [...]},
{ key: "series2", values: [...]}
];
Then, you will want to do a nested selection where you start with a selection of the "data" array and bind it to whatever svg or html element you have that wraps each of the two series.
var series = d3.select("svg").selectAll("g.series")
.data(data, function(d){return d.key; });
series.enter().append("g").attr("class", "series");
At this point, d3 will have added a "g" element to your svg element for each series and bound the series object (including the key and values array) to the appended elements. Next, you can make a nested selection to add series-specific elements to the g element... ie:
var rect = series.selectAll("rect").data(function(d) { return d.values });
rect.enter().append("rect");
Note that we used a function in our ".data(...)" call. That's because the values we want passed to the join actually depend on which specific series is being processed by D3.
Now, you'd have a rect added to the g element for each value in each series. Since you used d3 to do the data binding and you used the key function in the first select (".data(data, function(d){return d.key;}"), future selects done in the same nested/keyed manner will update the right g and rect elements.
Here's a Fiddle that demonstrates the concept:
http://jsfiddle.net/reblace/bWp8L/2/
A key takeaway is that you can update the data (including adding additional series) and the whole thing will redraw correctly according to the new nested join.

Resources