I'm using a XAML-MapControl in a UWP-project.
When you create a MapIcon, the image is floating a fixed offset above the desired location on the map, instead of directly on the map, with a black line connecting the icon with the map, as you can see in this image:
I can't find a way to remove this line, or reduce its size.
And none of the other MapElement-types seem to do what I want, I want the exact behavior of the MapIcon, but without this line.
Is there a way to do that?
Edit:
Here's how I create the MapIcons:
var icon = new MapIcon
{
NormalizedAnchorPoint = new Point(0.5, 1),
Image = image,
Visible = true,
};
MapControl.MapElements.Add(icon);
Edit2:
I tried to set the stylysheet, but it does not work for me, probably because it's only supported in a version newer than the one I target:
MapControl.StyleSheet = MapStyleSheet.ParseFromJson("{ \"version\": \"1.*\", \"settings\": { }, \"elements\": { \"userPoint\": { \"stemAnchorRadiusScale\": 0, \"stemHeightScale\": 0 }}}");
You need to set the stemAnchorRadiusScale and stemHeightScale properties of userPoint to 0 in the map style sheet. See this topic for how to work with style sheets:
https://learn.microsoft.com/en-us/windows/uwp/maps-and-location/elements-of-map-style-sheet.
For example:
{
"version": "1.*",
"settings": {
},
"elements": {
"userPoint": {
"stemAnchorRadiusScale": 0,
"stemHeightScale": 0
}
}
}
Related
In Google Sheets API, when using a chart shape, how can I colour a given datapoint a custom RGB? In the image below I have changed the color of 3 random datapoints. Is this possible?
It is possible to change the color and use a custom RGB color. If you already have the chart created, all you need to do is to use the batchUpdate method, and when creating the request include updateChartSpecRequest, then you'll need to select the type of chart that you are updating. In your case, based on the screenshot it would be basicChart, then from the chart, you want to update the series since those are the ones that generate the columns, and you can modify the color parameter there according to the official documentation.
Depending on what you want to end up doing, the structure of the request may end up being similar to this:
Request:
'request' : [
{
"updateChartSpec": {
"chartId": integer,
"spec": {
"basicChart": {
"series": [
{
"color": {
{
"red": number,
"green": number,
"blue": number,
"alpha": number
}
},
}
]
},
}
},
}
]
Note:
If you want to do it upon creation, instead of using updateChartSpec you would want to use addChart.
References:
updateChartSpecRequest
Color
BasicChartSeries
BasicChartSpec
addChart
You've seen this on other sliders, where along with the nav arrows you'd have some label/title indicating the contents of the next/previous slide.
Hopefully someone has already done this, so I can copy and adapt the code. Failing that I guess I'll experiment with different events listeners, pulling the text from sibling slides, and changing the content of active slide's nav divs.
Though maybe it's better to save the label text as data attributes? I don't know. Just brainstorming the approach here...
I figured it out. Instead of tracking the active slide, I'm adding labels when the swiper is initialised. Sharing it here, in case anyone here has a similar question.
let homeSwiper = new Swiper('.home-swiper', {
loop: true,
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev',
},
on: {
init: function () {
addLabels();
},
},
});
Each slide has a hidden span that I use as its label. I then just pull those labels from the surrounding slides:
function addLabels() {
let homeSlides = document.querySelectorAll('.home-slider .swiper-slide');
homeSlides.forEach((slide, i) => {
let labelPrev, labelNext;
if (i === 0) {
labelPrev = homeSlides[homeSlides.length - 1].querySelector('span.label').textContent;
labelNext = homeSlides[i + 1].querySelector('span.label').textContent;
} else if (i === homeSlides.length - 1) {
labelPrev = homeSlides[i - 1].querySelector('span.label').textContent;
labelNext = homeSlides[0].querySelector('span.label').textContent;
} else {
labelPrev = homeSlides[i - 1].querySelector('span.label').textContent;
labelNext = homeSlides[i + 1].querySelector('span.label').textContent;
}
slide.querySelector('.slide-nav-label--prev').textContent = labelPrev;
slide.querySelector('.slide-nav-label--next').textContent = labelNext;
})
}
I want to limit map extent to the initial extent of the map and limit user from panning more than certain extent.
I tried following but nothing has changed:
map = new Map( "map" , {
basemap: "gray",
center: [-85.416, 49.000],
zoom : 6,
logo: false,
sliderStyle: "small"
});
dojo.connect(map, "onExtentChange", function (){
var initExtent = map.extent;
var extent = map.extent.getCenter();
if(initExtent.contains(extent)){}
else{map.setExtent(initExtent)}
});
Just to flesh out Simon's answer somewhat, and give an example. Ideally you need two variables at the same scope as map:
initExtent to store the boundary of your valid extent, and
validExtent to store the last valid extent found while panning, so that you can bounce back to it.
I've used the newer dojo.on event syntax as well for this example, it's probably a good idea to move to this as per the documentation's recommendation - I assume ESRI will discontinue the older style at some point.
var map;
var validExtent;
var initExtent;
[...]
require(['dojo/on'], function(on) {
on(map, 'pan', function(evt) {
if ( !initExtent.contains(evt.extent) ) {
console.log('Outside bounds!');
} else {
console.log('Updated extent');
validExtent = evt.extent;
}
});
on(map, 'pan-end', function(evt) {
if ( !initExtent.contains(evt.extent) ) {
map.setExtent(validExtent);
}
});
});
You can do the same with the zoom events, or use extent-change if you want to trap everything. Up to you.
It looks like your extent changed function is setting the initial extent variable to the maps current extent and then checking if that extent contains the current extents centre point - which of course it always will.
Instead, declare initExtent at the same scope of the map variable. Then, change the on load event to set this global scope variable rather than a local variable. In the extent changed function, don't update the value of initExtent, simply check the initExtent contains the entire of the current extent.
Alternatively you could compare each bound of the current extent to each bound of the initExtent, e.g. is initExtent.xmin < map.extent.xmin and if any are, create a new extent setting any exceeded bounds to the initExtent values.
The only problem is these techniques will allow the initExtent to be exceeded briefly, but will then snap the extent back once the extent changed function fires and catches up.
I originally posted this solution on gis.stackexchange in answer to this question: https://gis.stackexchange.com/a/199366
Here's a code sample from that post:
//This function limits the extent of the map to prevent users from scrolling
//far away from the initial extent.
function limitMapExtent(map) {
var initialExtent = map.extent;
map.on('extent-change', function(event) {
//If the map has moved to the point where it's center is
//outside the initial boundaries, then move it back to the
//edge where it moved out
var currentCenter = map.extent.getCenter();
if (!initialExtent.contains(currentCenter) &&
event.delta.x !== 0 && event.delta.y !== 0) {
var newCenter = map.extent.getCenter();
//check each side of the initial extent and if the
//current center is outside that extent,
//set the new center to be on the edge that it went out on
if (currentCenter.x < initialExtent.xmin) {
newCenter.x = initialExtent.xmin;
}
if (currentCenter.x > initialExtent.xmax) {
newCenter.x = initialExtent.xmax;
}
if (currentCenter.y < initialExtent.ymin) {
newCenter.y = initialExtent.ymin;
}
if (currentCenter.y > initialExtent.ymax) {
newCenter.y = initialExtent.ymax;
}
map.centerAt(newCenter);
}
});
}
And here's a working jsFiddle example: http://jsfiddle.net/sirhcybe/aL1p24xy/
I am using a chart to visualize data in a TimeboxScopedApp, and I want to update the data when scope changes. The more brute-force approach of using remove() then redrawing the chart as described here leaves me with an overlaid "Loading..." mask, but otherwise works. The natural approach of using the Highchart native redraw() method would be my preference, only I don't know how to access the actual Highchart object and not the App SDK wrapper.
Here's the relevant part of the code:
var chart = Ext.getCmp('componentQualityChart');
if (chart) {
var chartCfg = chart.getChartConfig();
chartCfg.xAxis.categories = components;
chart.setChartConfig(chartCfg);
chart.setChartData(data);
chart.redraw(); // this doesn't work with the wrapper object
} else { // draw chart for the first time
How do I go about redrawing the chart with the new data?
Assuming chart (componentQualityChart) is an instance of Rally.ui.chart.Chart, you can access the HighCharts instance like this:
var highcharts = chart.down('highchart').chart;
// Now you have access to the normal highcharts interface, so
// you could change the xAxis
highcharts.xAxis[0].setCategories([...], true);
// Or you could change the series data
highcharts.series[0].data.push({ ... }); //Add a new data point
// Or pretty much anything else highcharts lets you do
Using _unmask() removes the overlaid "Loading.." mask
if (this.down('#myChart')) {
this.remove('myChart');
}
this.add(
{
xtype: 'rallychart',
height: 400,
itemId: 'myChart',
chartConfig: {
//....
},
chartData: {
categories: scheduleStateGroups,
series: [
{
//...
}
]
}
}
);
this.down('#myChart')._unmask();
I have a bar chart and i want each bar to render in different color. So i tried using thems,
sample code is:
Ext.define('Ext.chart.theme.FancyTheme',{
extend : 'Ext.chart.theme.Base',
constructor : function(config){
this.callParent([Ext.apply({
colors : ['#9CC5C9','#D5544F','#D5544F','#5288DB']
},config)])
}
});
and my chart code is:
var tc = Ext.create('Ext.chart.Chart',{
renderTo: Ext.getBody(),
width: 500,
height: 300,
animate : true,
insetPadding : 20,
theme: 'FancyTheme',
But all the bar colors are changing to same color i.e, to '#9cc5c9' in above example.
But i want bars to render in differnt colors as mentioned in theme. One more thing i dont want to use render function to render coloirs.
So wat is the soln to get different colors. Can anyone help me out!!
Sorry, but using a renderer is the correct solution. The colors property is used for successive series in a chart, such as multiple areas in the same plot space.
I don't understand why you don't want to use a renderer, but here's all you would need to do:
renderer: function(sprite, record, attr, index, store) {
var colors = ['#9CC5C9','#D5544F','#D5544F','#5288DB'];
return Ext.apply(attr, {
fill: colors[index % colors.length]
});
}
You can also extend Ext.chart.series.Bar. For example:
Ext.define('Ext.chart.series.MyBar', {
extend: 'Ext.chart.series.Bar',
//type: 'mybar',
alias: 'series.mybar',
getPaths: function() {
this.callParent(arguments);
var items = this.items,
i, iLen = items.length,
colors = this.colorArrayStyle,
colorsLength = colors && colors.length || 0;
for (var i = 0; i < iLen; ++i) {
items[i].attr.fill = colors[i % colorsLength];
}
}
});
Then in series you should use mybar instead of bar.