ArcGIS JS API: make circle not zoom - arcgis

I have a ArcGIS JavaScript API map. On map click I want to display a circle and highlight all the points within that circle.
However, when I create the circle and zoom in the map, the circle zooms in as well. How can I get the circle to stay the same pixel radius no matter what the zoom level of the map?
<script>
require([
"esri/Map",
"esri/layers/GeoJSONLayer",
"esri/views/MapView",
"esri/widgets/Zoom",
"esri/core/watchUtils",
"esri/geometry/geometryEngine"
], function (Map, GeoJSONLayer, MapView, Zoom, watchUtils, {buffer}) {
const url =
"https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_month.geojson";
const template = {
title: "Earthquake Info",
content: "Magnitude {mag} {type} hit {place} on {time}",
fieldInfos: [
{
fieldName: "time",
format: {
dateFormat: "short-date-short-time"
}
}
]
};
const renderer = {
type: "simple",
field: "mag",
symbol: {
type: "simple-marker",
color: "orange",
outline: {
color: "white"
}
},
visualVariables: [
{
type: "size",
field: "mag",
stops: [
{
value: 2.5,
size: "4px"
},
{
value: 8,
size: "40px"
}
]
}
]
};
const geojsonLayer = new GeoJSONLayer({
url: url,
copyright: "USGS Earthquakes",
popupTemplate: template,
renderer: renderer //optional
});
const map = new Map({
basemap: "gray",
layers: [geojsonLayer]
});
const view = new MapView({
container: "viewDiv",
center: [-168, 46],
zoom: 3,
map: map
});
let csvLayerView;
let highlight;
let resultFeatures;
view.whenLayerView(geojsonLayer).then(layerView => {
csvLayerView = layerView;
});
view.on("click", ({mapPoint}) => {
const geom = buffer(mapPoint, 500, "miles");
view.graphics.removeAll();
view.graphics.add({
geometry: geom,
symbol: {
type: "simple-fill",
color: [51, 51, 204, 0.2],
style: "solid",
outline: {
color: "white",
width: 1
}
}
});
const query = geojsonLayer.createQuery();
query.geometry = geom;
csvLayerView.queryObjectIds(query).then(oids => {
if (highlight) {
highlight.remove();
}
highlight = csvLayerView.highlight(oids);
return csvLayerView.queryFeatures(query);
}).then(({features}) => {
resultFeatures = features;
});
});
});
</script>

The circle that you create, using a 500 miles buffer of the click point, is a polygon. So naturally will be the same one no matter what zoom level you have. In other words, represent a geographic area so it can not change based on the zoom level.
On contrary, in the same example you have the points that represent the earthquakes, that are represented with a orange circle. Because it is a symbol that represents a geographic place, it keeps the size in pixels for all zoom levels.
Resuming, you can not make the 500 miles buffer area, represented by the polygon, to change with the zoom levels, because it is an area.

Related

Nativebase how to customize Button color in theme without using colorScheme?

I really struggle with this simple thing.
By default the button color is primary.600 which is not the real primary color. So I just want it to be primary.400 (the real primary).
As there is nearly no documentation on this and to my regret no IDE auto-completion with typescript, I am asking your lights on how to solve the problem
Here is what I have tried so far:
export const theme = extendTheme({
components: {
Button: {
// I tried this after checking directly in ts file for extendTheme implementation
baseStyle: () => ({
bg: 'red.500',
backgroundColor: 'red.500',
})
// as well as
baseStyle: {
bg: 'red.500',
backgroundColor: 'red.500',
}
// also tried with hex colors with no success
},
// Also tried the code in this example: https://github.com/GeekyAnts/NativeBase/blob/v3.1.0/src/theme/components/button.ts#L72 with no success
variants: {
solid(props: Dict) {
const { colorScheme: c } = props;
let bg = `${c}.400`
bg = mode(bg, `${c}.400`)(props);
if (props.isDisabled) {
bg = mode(`muted.300`, `muted.500`)(props);
}
const styleObject = {
_web: {
outlineWidth: 0,
},
bg,
_hover: {
bg: mode(`${c}.600`, `${c}.500`)(props),
},
_pressed: {
bg: mode(`${c}.700`, `${c}.600`)(props),
},
};
return styleObject;
}
}
});
Also tried the code in this example: https://github.com/GeekyAnts/NativeBase/blob/v3.1.0/src/theme/components/button.ts#L72 with no success
As far as I can tell, there is no way to define the specific color, only a colorScheme. This may be because the button as designed in NativeBase relies on a set of colors, not a single one (normal, disabled, hovering, pressed, etc.).
That being said I can see two approaches to achieving your goal.
define a custom color scene and connect it to the button in the theme configuration:
const theme = extendTheme({
colors: {
custom: {
50: '#ecfeff',
100: '#67e8f9',
200: '#22d3ee',
300: '#06b6d4',
400: '#0891b2',
500: '#0e7490',
600: '#155e75',
700: '#164e63',
800: '#174e63',
900: '#184e63',
},
},
components: {
Button: {
defaultProps: {
colorScheme: 'custom',
},
},
},
});
Simply override the primary theme (this could of course have side effects if you use the primary color in other components)
const theme = extendTheme({
colors: {
primary: {
50: '#ecfeff',
100: '#67e8f9',
200: '#22d3ee',
300: '#06b6d4',
400: '#0891b2',
500: '#0e7490',
600: '#155e75',
700: '#164e63',
800: '#174e63',
900: '#184e63',
},
},
});
baseStyle: {
rounded: 'md',
bg: '#ffcc00',
backgroundColor: '#fc0',
},
Using bg and backgroundColor seems to work

Get current state of graph after elements are added dynamically

I am using Cytoscape.js and the context menus extension within a React app through react-cytoscape.js. Right now, I can dynamically add nodes through an onClickFunction as a menu item. I would like to get the current state of the graph - that is, all the nodes that have been added as well as the ones it started with.
How can I do this? So far, I've tried cy.json(), but that only returns the initial state of the graph.
Below is all of my cytoscape code.
class MyApp extends React.Component {
constructor(props){
super(props);
}
render(){
const elements = [ // Nodes and edges to be added initially
{ data: { id: 'one', label: 'Node 1' }, position: { x: 250, y: 250 } },
{ data: { id: 'two', label: 'Node 2' }, position: { x: 300, y: 250 } },
{ data: { source: 'one', target: 'two', label: 'Edge from Node1 to Node2' } }
];
return <CytoscapeComponent
cy = {cy => { // Extensions and their options
cy.contextMenus({
menuItems: [
{ // Adds the ability to add nodes from the right-click menu
id: 'add-node',
content: 'add node',
tooltipText: 'add node',
image: {src: "./node_modules/cytoscape-context-menus/assets/add.svg", width: 12, height: 12, x: 6, y: 4},
coreAsWell: true,
// When we move adding nodes to a sidebar, probably use this as reference
onClickFunction: function (event) {
var data = {
group: 'nodes'
};
var pos = event.position || event.cyPosition;
cy.add({
data: data,
position: {
x: pos.x,
y: pos.y
}
});
}
}
]
})
}}
elements={elements}
style={ { width: '100%', height: '40vmax'} } />;
}
}

HTML5 canvas artifacts

I have created a Vue component that loads an image into a canvas and allows the user to zoom-in and zoom-out with the mouse wheel. The image resolution is 1260x1800, the canvas resolution is 427x610 (the aspect ratio is preserved).
<template>
<canvas
ref="canvas"
:width="width"
:height="height"
#mousedown.prevent.stop="onMouseDown"
#mousemove.prevent.stop="onMouseMove"
#mouseup.prevent.stop="onMouseUp"
#mouseout.prevent.stop="onMouseOut"
#mousewheel.prevent.stop="onMouseWheel"
/>
</template>
<script>
export default {
name: 'MyZoomingCanvas',
props: {
src: {
type: String,
required: true
},
zoom: {
type: Object,
required: true,
validator: zoom =>
zoom &&
zoom.hasOwnProperty('min') &&
zoom.hasOwnProperty('max') &&
zoom.hasOwnProperty('step') &&
zoom.hasOwnProperty('scale')
}
},
data() {
return {
img: null,
isMouseDown: false,
startX: null,
startY: null,
dx: 0,
dy: 0,
width: 427,
height: 610
}
},
watch: {
'zoom.scale'() {
this.draw()
}
},
methods: {
draw() {
const canvas = this.$refs.canvas
const ctx = canvas.getContext('2d')
ctx.clearRect(0, 0, this.width, this.height)
ctx.setTransform(
this.zoom.scale,
0,
0,
this.zoom.scale,
((1 - this.zoom.scale) * this.width) / 2,
((1 - this.zoom.scale) * this.height) / 2
)
ctx.drawImage(this.img, 0, 0, this.width, this.height)
},
loadImage(src) {
return new Promise((resolve, reject) => {
const img = new Image()
img.addEventListener('load', () => resolve(img))
img.addEventListener('error', err => reject(err))
img.src = src
})
},
onMouseDown({ clientX, clientY }) {
this.startX = clientX
this.startY = clientY
this.isMouseDown = true
},
onMouseMove({ clientX, clientY }) {
if (this.isMouseDown) {
this.dx += clientX - this.startX
this.dy += clientY - this.startY
this.draw()
this.startX = clientX
this.startY = clientY
}
},
onMouseUp() {
this.isMouseDown = false
this.dx = 0
this.dy = 0
},
onMouseOut() {
this.isMouseDown = false
},
onMouseWheel({ offsetX, offsetY, deltaY }) {
this.dx = -offsetX
this.dy = -offsetY
this.$emit(
'scale-change',
Math.min(this.zoom.max, Math.max(this.zoom.min, this.zoom.scale - deltaY * this.zoom.step))
)
}
},
mounted() {
this.loadImage(this.src).then(img => {
this.img = img
this.$nextTick(() => {
this.draw()
})
})
}
}
</script>
I noticed that in some cases the images are affected by strange artifacts, take a look at this example: https://jsfiddle.net/lmartini/b3hLr5ej/latest/
In the example, while zooming-in, I can clearly see a bunch of horizontal bands along the whole fabric height that disappear after a certain zoom level.
By googling I believe that these artifacts are caused by the resolution mismatch between the canvas and the image (the so called pixel-perfect problem) and, hence, by the internal browser downsampling algorithm.
I tried to improve the image smoothing quality of the canvas by adding the following lines but they didn't make any difference at all (my target browser is Chrome):
// ctx is the canvas context
ctx.imageSmoothingEnabled = true
ctx.imageSmoothingQuality = 'high'
How can I get rid of these artifacts?

Highchart gauge not displaying min/max value in Vue.js

I have a weird issue. I am displaying data from a neo4j database onto the highcharts. I am able to retrieve the data, but when i try to put it onto the charts, some of it doesnt display. Here is my gauge code
CustomGauge.vue
<template>
<highcharts :options="chartOptions"></highcharts>
</template>
<script>
import { Chart } from "highcharts-vue";
export default {
name: "CustomGuage",
components: {
highcharts: Chart
},
props: ["data", "title", "range1", "range2", "min", "max"],
data() {
return {
chartOptions: {
chart: {
type: "gauge",
// plotBackgroundColor: null,
// plotBackgroundImage: null,
// plotBorderWidth: 0,
// plotShadow: false,
//marginBottom: 170,
},
credits: {
enabled: false
},
title: {
text: this.title,
align: "left"
},
pane: {
startAngle: -150,
endAngle: 150,
size: 200,
background: {
borderWidth: 0
}
},
// the value axis
yAxis: {
min: this.min,
max: this.max,
// tickPixelInterval: 30,
// tickWidth: 2,
// tickColor: "#666",
plotBands: [
{
from: 0,
to: this.range1,
color: "#55BF3B" // green
},
{
from: this.range1,
to: this.range2,
color: "#DDDF0D" // yellow
},
{
from: this.range2,
to: 1000,
color: "#DF5353" // red
}
]
},
series: [
{
data: this.data
// tooltip: {
// valueSuffix: " km/h"
// }
},
// // {
// // data: this.target,
// // dataLabels: {
// // enabled: true,
// // format: "Target: {y}%",
// // verticalAlign: "bottom",
// // borderWidth: 0
// // //useHTML: true,
// // },
// }
]
}
};
},
watch: {
data(newVal) {
this.chartOptions.series[0].data = newVal;
}
}
};
I define my chart like this
<CustomGuage :title="gaugeTitle1" :data="gaugeData1" :min="gauge1min" :max="gauge1max" :range1="gauge1Range1" :range2="gauge1Range2" />
I initialize it in data() like this -
gaugeTitle1: [],
gaugeData1: [],
gauge1Range1: [],
gauge1Range2: [],
gauge1min: [],
gauge1max: [],
Using the neo4j-vuejs connector, i retrieve the data like this -
const session19 = this.$neo4j.getSession();
// KPI 1
session19
.run(
"match (n:proj) where exists(n.min) return n.name as title,n.min as min,n.max as max,n.range1
as range1,n.range2 as range2,n.target AS target, n.current as data"
)
.then((res) => {
// KPI 1-------------------------
this.data1 = res.records[0].get("data");
var a = JSON.parse(this.data1);
this.gaugeData1.push(a);
console.log(a)
this.min1 = res.records[0].get("min");
var b = JSON.parse(this.min1);
this.gauge1min = b;
console.log(this.gauge1min)
this.max1 = res.records[0].get("max");
var c = JSON.parse(this.max1);
this.gauge1max = c;
console.log(this.gauge1max)
this.title1 = res.records[0].get("title");
this.gaugeTitle1.push(this.title1)
console.log(this.gaugeTitle1);
})
.then(() => {
session.close();
});
The retrieval of data works fine, i checked in the console.The weird part is if i comment/uncomment or change something in CustomGauge.vue, the charts displays perfectly, displays everything perfectly from the database.But once i refresh the page, it is gone. Could someone help me out. thanks for your help in advance
Probably a reactivity issue.
Instead of
this.chartOptions.series[0].data = newVal;
Try
this.$set(this.chartOptions.series[0], 'data', newVal)

Ext.map markers are not loading in Sencha touch 2

I use following code to add markers to map which is not showing me the marker in Ext.map
{
xtype: 'map',
id :'geomap',
width: '70%',
height: '100%',
layout: 'fit',
useCurrentLocation: false,
flex: 3,
mapOptions: {
zoom: 15,
mapTypeId: google.maps.MapTypeId.ROADMAP,
mapTypeControl : false,
navigationControl : false,
streetViewControl : false,
backgroundColor: 'transparent',
disableDoubleClickZoom: true,
draggable: true,
keyboardShortcuts: false,
scrollwheel: true,
},
initialize: function() {
var gMap = this.getMap();
// drop map marker
var marker = new google.maps.Marker({
map: gMap,
animation: google.maps.Animation.DROP,
position: new google.maps.LatLng (12.82787,80.219722),
title:"Hello World!"
});
var geo = Ext.create('Ext.util.Geolocation', {
autoUpdate: true,
listeners: {
locationupdate: function (geo) {
var center = new google.maps.LatLng(geo.getLatitude(), geo.getLongitude());
Ext.getCmp('geomap').update(center);
//To place the marker
var marker = new google.maps.Marker({
position: center,
map: Ext.getCmp('geomap').map
});
Ext.msg.alert('New latitude: ' + geo.getLatitude());
},
locationerror: function (geo, bTimeout, bPermissionDenied, bLocationUnavailable, message) {
if (bTimeout) {
Ext.msg.alert('Timeout occurred.');
} else {
Ext.msg.alert('Error occurred.');
}
}
}
});
geo.updateLocation();
}
}
which is not showing markers . Please help .
The initialize method is not the appropriate place to play with the map because you can't be sure it has been rendered yet in there. You need to put your code in a maprender event handler.
Then, in order to find your first marker easily, you should initially center the map on it (like in this example).
Finally, you've got some small errors in your Geolocation handler's code. See my comments in the code.
Here's a fixed version of your code. For me, it works for both markers with Touch 2.2.1. I've not tested the Geolocation part, though, since it is not available in my browser...
{
xtype: 'map',
id :'geomap',
width: '70%',
height: '100%',
layout: 'fit',
useCurrentLocation: false,
flex: 3,
mapOptions: {
zoom: 15,
mapTypeId: google.maps.MapTypeId.ROADMAP,
mapTypeControl : false,
navigationControl : false,
streetViewControl : false,
backgroundColor: 'transparent',
disableDoubleClickZoom: true,
draggable: true,
keyboardShortcuts: false,
scrollwheel: true
// Center your map to see your first marker ;)
,center: new google.maps.LatLng (12.82787,80.219722)
}
,listeners: {
maprender: function() {
// Get a ref to the google map object (should be provided
// as an argument to the listener but apparently there is
// a bug...)
var gMap = this.getMap();
new google.maps.Marker({
map: gMap,
animation: google.maps.Animation.DROP,
position: new google.maps.LatLng (12.82787,80.219722),
title:"Hello World!"
});
var geo = Ext.create('Ext.util.Geolocation', {
autoUpdate: true,
listeners: {
locationupdate: function (geo) {
var center = new google.maps.LatLng(geo.getLatitude(), geo.getLongitude());
// This is deprecated
// Ext.getCmp('geomap').update(center);
Ext.getCmp('geomap').setMapCenter(center);
//To place the marker
var marker = new google.maps.Marker({
position: center,
// This won't work
// map: Ext.getCmp('geomap').map
//
// Use the ref we already have:
map: gMap
//
// Or you could get it this way:
// map: Ext.getCmp('geomap').getMap()
});
Ext.msg.alert('New latitude: ' + geo.getLatitude());
},
locationerror: function (geo, bTimeout, bPermissionDenied, bLocationUnavailable, message) {
if (bTimeout) {
Ext.Msg.alert('Timeout occurred.');
} else {
Ext.Msg.alert('Error occurred.');
}
}
}
});
geo.updateLocation();
}
}
}