UniqueValueRenderer with graphicsLayer - arcgis-js-api

graphicsLayer has a method: setRenderer(renderer)
How can I set certain graphic elements of graphicsLayer using UniqueValueRenderer?
Did not find anything like this on Google therefore opened this issue here.
Any example available?
Using: js arcgis 3.23
Is this actually supported in js arcgis version 3.x?
As far as I know it is not supported in js arcgis version 4.x

Did not find a solution on the web so I had no choice but to investigate it on my own.
The main question was: how to talk to each graphic element that belongs to a certain graphicsLayer using UniqueValueRenderer.
Could not figure out from the ESRI js arcgis 3.23 API and examples what could be the right interface and syntax to use.
After experimenting a lot with the code came to the following conclusions:
Symbols defined at the Graphic layer always override symbols
defined in a renderer. Therefore I instanced each Graphic using no
Symbol.
In order to communicate with each Graphic separately UniqueValueRenderer needs to find some attribute on each Graphic therefore I added an attribute to each Graphic.
Now I attempted to use the Graphic attribute name in the UniqueValueRenderer while using Graphic attribute value to let UniqueValueRenderer select custom symbol for each Graphic.
The syntax for UniqueValueRenderer integration with graphicsLayer was not clear from the available documentation and ESRI examples but I experimented with various options and possibilities intuitively and I managed to make it work!
You can see the solution in the attached code snippet.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no">
<title>Renderer</title>
<style>
html,
body,
#map {
height: 100%;
padding: 0;
margin: 0;
}
</style>
<link rel="stylesheet" href="https://js.arcgis.com/3.23/esri/css/esri.css">
<link rel="stylesheet" href="https://js.arcgis.com/3.23/dijit/themes/tundra/tundra.css">
<script src="https://js.arcgis.com/3.23/"></script>
<script>
var map;
require([
"esri/map",
"esri/renderers/Renderer",
"esri/renderers/SimpleRenderer",
"esri/renderers/UniqueValueRenderer",
"esri/layers/ArcGISTiledMapServiceLayer",
"esri/graphic",
"esri/layers/GraphicsLayer",
"esri/geometry/Point",
"esri/Color",
"esri/SpatialReference",
"esri/symbols/SimpleLineSymbol",
"esri/symbols/SimpleMarkerSymbol",
"esri/symbols/PictureMarkerSymbol",
"esri/InfoTemplate",
"dojo/domReady!"
],
function(Map, Renderer, SimpleRenderer, UniqueValueRenderer, ArcGISTiledMapServiceLayer, Graphic, GraphicsLayer, Point, Color, SpatialReference, SimpleLineSymbol, SimpleMarkerSymbol, PictureMarkerSymbol, InfoTemplate) {
map = new Map("map", {
basemap: "topo",
center: [34.9891877, 31.712805039],
zoom: 13,
logo: false
});
var locationGraphicsLayer = new GraphicsLayer();
var symbol1 = new SimpleMarkerSymbol().
setOffset(0, 0).
setColor([0, 255, 55, 0.33]).
setSize(40).
setStyle(SimpleMarkerSymbol.STYLE_PATH).
setPath("M16,3.5c-4.142,0-7.5,3.358-7.5,7.5c0,4.143,7.5,18.121,7.5,18.121S23.5,15.143,23.5,11C23.5,6.858,20.143,3.5,16,3.5z M16,14.584c-1.979,0-3.584-1.604-3.584-3.584S14.021,7.416,16,7.416S19.584,9.021,19.584,11S17.979,14.584,16,14.584z");
var symbol2 = new SimpleMarkerSymbol().
setOffset(0, 0).
setColor([55, 0, 255, 0.33]).
setSize(40).
setStyle(SimpleMarkerSymbol.STYLE_PATH).
setPath("M16,3.5c-4.142,0-7.5,3.358-7.5,7.5c0,4.143,7.5,18.121,7.5,18.121S23.5,15.143,23.5,11C23.5,6.858,20.143,3.5,16,3.5z M16,14.584c-1.979,0-3.584-1.604-3.584-3.584S14.021,7.416,16,7.416S19.584,9.021,19.584,11S17.979,14.584,16,14.584z");
var symbol3 = new SimpleMarkerSymbol().
setOffset(0, 0).
setColor([255, 0, 55, 0.33]).
setSize(40).
setStyle(SimpleMarkerSymbol.STYLE_PATH).
setPath("M16,3.5c-4.142,0-7.5,3.358-7.5,7.5c0,4.143,7.5,18.121,7.5,18.121S23.5,15.143,23.5,11C23.5,6.858,20.143,3.5,16,3.5z M16,14.584c-1.979,0-3.584-1.604-3.584-3.584S14.021,7.416,16,7.416S19.584,9.021,19.584,11S17.979,14.584,16,14.584z");
var attr1 = {
"MY_VALUE": 1
};
var attr2 = {
"MY_VALUE": 2
};
var attr3 = {
"MY_VALUE": 3
};
var attr4 = {
"MY_VALUE": 4
};
var attr5 = {
"MY_VALUE": 5
};
var attr6 = {
"MY_VALUE": 6
};
var attr7 = {
"MY_VALUE": 7
};
var attr8 = {
"MY_VALUE": 8
};
var point1 = new Point(34.9891417, 31.712785039);
var point2 = new Point(34.9863217, 31.712911039);
var point3 = new Point(34.95059216533203, 31.740442520689456);
var point4 = new Point(34.958138448443606, 31.719220882963626);
var point5 = new Point(34.993487748107846, 31.728375175600405);
var point6 = new Point(34.990054520568776, 31.73875923932111);
var point7 = new Point(34.978845102038576, 31.732417351316897);
var point8 = new Point(34.974815102038576, 31.735412351316897);
var graphic1 = new Graphic(point1);
var graphic2 = new Graphic(point2);
var graphic3 = new Graphic(point3);
var graphic4 = new Graphic(point4);
var graphic5 = new Graphic(point5);
var graphic6 = new Graphic(point6);
var graphic7 = new Graphic(point7);
var graphic8 = new Graphic(point8);
graphic1.setAttributes(attr1);
graphic2.setAttributes(attr2);
graphic3.setAttributes(attr3);
graphic4.setAttributes(attr4);
graphic5.setAttributes(attr5);
graphic6.setAttributes(attr6);
graphic7.setAttributes(attr7);
graphic8.setAttributes(attr8);
locationGraphicsLayer.add(graphic1);
locationGraphicsLayer.add(graphic2);
locationGraphicsLayer.add(graphic3);
locationGraphicsLayer.add(graphic4);
locationGraphicsLayer.add(graphic5);
locationGraphicsLayer.add(graphic6);
locationGraphicsLayer.add(graphic7);
locationGraphicsLayer.add(graphic8);
renderer = new UniqueValueRenderer(symbol2, "MY_VALUE");
renderer.addValue({
value: "6",
symbol: symbol1
});
renderer.addValue({
value: "3",
symbol: symbol3
});
locationGraphicsLayer.setRenderer(renderer);
map.addLayer(locationGraphicsLayer);
});
</script>
<title></title>
</head>
<body class="tundra">
<div id="map"></div>
</body>
</html>

Related

Using Self-Segmentation javascript of Mediapipe to pass user selfie as a texture on Networked-Aframe for multiplaying experiences

Well my target is to make a multiplaying 3D environment where the persons are represented by cubes that have as textures their selfie without the background. It is a kind of cheap virtual production without chroma key background. The background is removed with MediaPipe Selfie-Segmentation. The issue is that instead of having the other player texture on the cube (P1 should see P2, and P2 should see P1, each one sees his selfie. This means that P1 sees P1 and P2 sees P2 which is bad.
Live demo: https://vrodos-multiplaying.iti.gr/plain_aframe_mediapipe_testbed.html
Instructions: You should use two machines to test it Desktops, Laptops or Mobiles. Use only Chrome as Mediapipe is not working at other browsers. In case webpage jams, reload the webpage (Mediapipe is sometimes sticky). At least two machines should load the webpage in order to start the multiplaying environment.
Code:
<html>
<head>
<script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
<!-- Selfie Segmentation of Mediapipe -->
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/#mediapipe/control_utils#0.6/control_utils.css" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/#mediapipe/camera_utils#0.3/camera_utils.js" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/#mediapipe/control_utils#0.6/control_utils.js" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/#mediapipe/drawing_utils#0.3/drawing_utils.js" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/#mediapipe/selfie_segmentation#0.1/selfie_segmentation.js" crossorigin="anonymous"></script>
<!-- Networked A-frame -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.3.0/socket.io.slim.js"></script>
<script src="/easyrtc/easyrtc.js"></script>
<script src="https://unpkg.com/networked-aframe/dist/networked-aframe.min.js"></script>
</head>
<body>
<a-scene networked-scene="
adapter: easyrtc;
video: true;
debug: true;
connectOnLoad: true;">
<a-assets>
<template id="avatar-template">
<a-box material="alphaTest: 0.5; transparent: true; side: both;"
width="1"
height="1"
position="0 0 0" rotation="0 0 0"
networked-video-source-mediapiped></a-box>
</template>
</a-assets>
<a-entity id="player"
networked="template:#avatar-template;attachTemplateToLocal:false;"
camera wasd-controls look-controls>
</a-entity>
<a-plane position="0 -2 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4" ></a-plane>
<a-sky color="#777"></a-sky>
</a-scene>
</body>
<script>
// Networked Aframe : Register new component for streaming the Selfie-Segmentation video stream
AFRAME.registerComponent('networked-video-source-mediapiped', {
schema: {
},
dependencies: ['material'],
init: function () {
this.videoTexture = null;
this.video = null;
this.stream = null;
this._setMediaStream = this._setMediaStream.bind(this);
NAF.utils.getNetworkedEntity(this.el).then((networkedEl) => {
const ownerId = networkedEl.components.networked.data.owner;
if (ownerId) {
NAF.connection.adapter.getMediaStream(ownerId, "video")
.then(this._setMediaStream)
.catch((e) => NAF.log.error(`Error getting media stream for ${ownerId}`, e));
} else {
// Correctly configured local entity, perhaps do something here for enabling debug audio loopback
}
});
},
_setMediaStream(newStream) {
if(!this.video) {
this.setupVideo();
}
if(newStream != this.stream) {
if (this.stream) {
this._clearMediaStream();
}
if (newStream) {
this.video.srcObject = canvasElement.captureStream(30);
this.videoTexture = new THREE.VideoTexture(this.video);
this.videoTexture.format = THREE.RGBAFormat;
// Mesh to send
const mesh = this.el.getObject3D('mesh');
mesh.material.map = this.videoTexture;
mesh.material.needsUpdate = true;
}
this.stream = newStream;
}
},
_clearMediaStream() {
this.stream = null;
if (this.videoTexture) {
if (this.videoTexture.image instanceof HTMLVideoElement) {
// Note: this.videoTexture.image === this.video
const video = this.videoTexture.image;
video.pause();
video.srcObject = null;
video.load();
}
this.videoTexture.dispose();
this.videoTexture = null;
}
},
remove: function() {
this._clearMediaStream();
},
setupVideo: function() {
if (!this.video) {
const video = document.createElement('video');
video.setAttribute('autoplay', true);
video.setAttribute('playsinline', true);
video.setAttribute('muted', true);
this.video = video;
}
}
});
// ----- Mediapipe ------
const controls = window;
//const mpSelfieSegmentation = window;
const examples = {
images: [],
// {name: 'name', src: 'https://url.com'},
videos: [],
};
const fpsControl = new controls.FPS();
let activeEffect = 'background';
const controlsElement = document.createElement('control-panel');
var canvasElement = document.createElement('canvas');
canvasElement.height= 1000;
canvasElement.width = 1000;
var canvasCtx = canvasElement.getContext('2d');
// --------
function drawResults(results) {
canvasCtx.clearRect(0, 0, canvasElement.width, canvasElement.height);
canvasCtx.drawImage(results.segmentationMask, 0, 0, canvasElement.width, canvasElement.height);
canvasCtx.globalCompositeOperation = 'source-in';
canvasCtx.drawImage(results.image, 0, 0, canvasElement.width, canvasElement.height);
}
const selfieSegmentation = new SelfieSegmentation({
locateFile: (file) => {
console.log(file);
return `https://cdn.jsdelivr.net/npm/#mediapipe/selfie_segmentation#0.1/${file}`;
}
});
selfieSegmentation.onResults(drawResults);
// -------------
new controls
.ControlPanel(controlsElement, {
selfieMode: true,
modelSelection: 1,
effect: 'background',
})
.add([
new controls.StaticText({title: 'MediaPipe Selfie Segmentation'}),
fpsControl,
new controls.Toggle({title: 'Selfie Mode', field: 'selfieMode'}),
new controls.SourcePicker({
onSourceChanged: () => {
selfieSegmentation.reset();
},
onFrame: async (input, size) => {
const aspect = size.height / size.width;
let width, height;
if (window.innerWidth > window.innerHeight) {
height = window.innerHeight;
width = height / aspect;
} else {
width = window.innerWidth;
height = width * aspect;
}
canvasElement.width = width;
canvasElement.height = height;
await selfieSegmentation.send({image: input});
},
examples: examples
}),
new controls.Slider({
title: 'Model Selection',
field: 'modelSelection',
discrete: ['General', 'Landscape'],
}),
new controls.Slider({
title: 'Effect',
field: 'effect',
discrete: {'background': 'Background', 'mask': 'Foreground'},
}),
])
.on(x => {
const options = x;
//videoElement.classList.toggle('selfie', options.selfieMode);
activeEffect = x['effect'];
selfieSegmentation.setOptions(options);
});
</script>
</html>
Screenshot:
Here Player 1 sees Player 1 stream instead of Player 2 stream (Grrrrrr):
Well, I found it. The problem was that a MediaStream can have many video tracks. See my answer here:
https://github.com/networked-aframe/networked-aframe/issues/269
Unfortunately networked-aframe EasyRtcAdapter does not support many MediaStreams, but it is easy to add another video track and then get videotrack[1] instead of videotrack[0]. I should make a special EasyRtcAdapter to avoid having two video tracks and avoid overstressing bandwidth.

How do I Set Up Clustering on Google Maps Web API

I'm trying to add clustering to Google Maps web project, but so far no luck. Here is what is working:
Added a few markers
Requested user location (code removed).
markercluster.js is the library file downloaded from the GitHub project and saved in the public.html file.
I have removed the API key for security.
JavaScript Code in HTML Body
var userPosition;
var map;
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
//center: {lat: -34.928499, lng: 138.600746},
center: {lat: -33.86882, lng: 151.209296},
zoom: 13
});
var markers = [
{coords:{lat:-34.923885, lng:138.562042}, content:'<p><strong>British Raj</strong></p>'},
{coords:{lat:-34.924476, lng:138.561141}, content:'<p><strong>Subway (Torrensville)</strong></p>'},
{coords:{lat:-34.843645, lng:138.507653}, content:'<p>Banyan Hotel Port Adelaide</p>'},
{coords:{lat:-34.92366, lng:138.567063}, content:'<p>Abyssinian Restaurant</p>'},
{coords:{lat:-34.923927, lng:138.561959}, content:'<p>Burger Foundry (Torrensville)</p>'}
];
var gmarkers = [];
for(var i = 0; i < markers.length; i++){
//addMarker(markers[i]);
gmarkers.push(addMarker(markers[i]));
}
function addMarker(props){
var marker = new google.maps.Marker({
position:props.coords,
map:map,
icon:'Layer 1.png'
});
if (props.content){
var infoWindow = new google.maps.InfoWindow({
content:props.content
});
marker.addListener('click', function(){
infoWindow.open(map, marker);
});
}
}
}
var markerCluster = new MarkerClusterer(map, gmarkers,{imagePath: 'https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/m'});
</script>
<script src="https://maps.googleapis.com/maps/api/js?key=API_KEY_REMOVED&callback=initMap"
async defer></script>
<script src="markercluster.js"></stript>
CSS
html, body{
height: 100%;
padding: 0;
margin: 0;
}
#map {
height: 80%;
weidth: 80%;
}
There are several issues with your code:
The creation of the MarkerClusterer is outside of the initMap function, so it runs before the API is loaded. Move that inside the initMap function.
The addMarker function doesn't return anything, so everytime you create a marker you add "undefined" to the gmarkers array (add: return marker; to the end of the function).
Based on the example in the documentation, you need to load markerclusterer.js before the Google Maps JavaScript API v3.
proof of concept fiddle
code snippet:
var userPosition;
var gmarkers = [];
var map;
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
//center: {lat: -34.928499, lng: 138.600746},
center: {
lat: -33.86882,
lng: 151.209296
},
zoom: 13
});
var markers = [
{coords:{lat:-34.923885, lng:138.562042}, content:'<p><strong>British Raj</strong></p>'},
{coords:{lat:-34.924476, lng:138.561141}, content:'<p><strong>Subway (Torrensville)</strong></p>'},
{coords:{lat:-34.843645, lng:138.507653}, content:'<p>Banyan Hotel Port Adelaide</p>'},
{coords:{lat:-34.92366, lng:138.567063}, content:'<p>Abyssinian Restaurant</p>'},
{coords:{lat:-34.923927, lng:138.561959}, content:'<p>Burger Foundry (Torrensville)</p>'}
];
var bounds = new google.maps.LatLngBounds();
for (var i = 0; i < markers.length; i++) {
//addMarker(markers[i]);
gmarkers.push(addMarker(markers[i]));
bounds.extend(markers[i].coords);
}
map.fitBounds(bounds);
function addMarker(props) {
var marker = new google.maps.Marker({
position: props.coords,
map: map,
});
if (props.content) {
var infoWindow = new google.maps.InfoWindow({
content: props.content
});
marker.addListener('click', function() {
infoWindow.open(map, marker);
});
}
return marker;
}
var markerCluster = new MarkerClusterer(map, gmarkers, {
imagePath: 'https://unpkg.com/#google/markerclustererplus#4.0.1/images/m'
});
}
/* Always set the map height explicitly to define the size of the div
* element that contains the map. */
#map {
height: 100%;
}
/* Optional: Makes the sample page fill the window. */
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
<div id="map"></div>
<script src="https://unpkg.com/#googlemaps/markerclustererplus/dist/index.min.js"></script>
<!-- Replace the value of the key parameter with your own API key. -->
<script async defer src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initMap">
</script>

Object is not moving proper with mouse movement in mobile devices

I am trying to move an object with mouse using pressmove event on the object. In PC and Tablet it is working well. But, in the mobile devices it is not working well as those have different width and height.
You can view the following URL:-
http://quirktools.com/screenfly/#u=http://saurabhysecit.byethost15.com/scratchGame_Canvas.html&w=320&h=568&a=37&s=1
Direct URL is - http://saurabhysecit.byethost15.com/scratchGame_Canvas.html
It has been generated from Animate CC.
These are the code below.
JS Code -
(function (lib, img, cjs, ss, an) {
var p; // shortcut to reference prototypes
lib.ssMetadata = [];
function mc_symbol_clone() {
var clone = this._cloneProps(new this.constructor(this.mode, this.startPosition, this.loop));
clone.gotoAndStop(this.currentFrame);
clone.paused = this.paused;
clone.framerate = this.framerate;
return clone;
}
function getMCSymbolPrototype(symbol, nominalBounds, frameBounds) {
var prototype = cjs.extend(symbol, cjs.MovieClip);
prototype.clone = mc_symbol_clone;
prototype.nominalBounds = nominalBounds;
prototype.frameBounds = frameBounds;
return prototype;
}
(lib.coin = function(mode,startPosition,loop) {
this.initialize(mode,startPosition,loop,{});
// Layer 1
this.shape = new cjs.Shape();
this.shape.graphics.f().s("#AA8801").ss(1,2,1).p("AH5AAQAACrhhCBQgIAKgIAKQgQAUgTASQiKCLjAAKQgNAAgOAAQi5AAiKh2QgRgOgQgRQiUiTAAjTQAAjDCBiOIAAgBQAJgKAKgKQAUgUAVgSQB9hlCigIQAOgBAOAAQAaAAAZACQAHAAAHABQCoAUB8B9QATASAQAUQBtCEAECvQAAADAAACQAAAFAAADg");
this.shape.setTransform(-4.8,0.1);
this.shape_1 = new cjs.Shape();
this.shape_1.graphics.f("#D9AE01").s().p("AlbGiQgTgQgSgSQigieAAjiQAAjhCgifQAWgWAXgTQCRh2DCgBQAdABAbACQC+ARCLCMQAUATASAWQB6CTAADEQAADGh6CSQgSAVgUATQiUCWjQAKIgdAAQjHAAiUh+gAgqnnQijAIh8BmQgVARgUAUIgUAUIAAABQiBCOAADEQAADSCVCTQAQARARAOQCJB2C6AAIAbAAQDAgJCJiMQATgSAQgUIAQgUQBhiBAAiqIAAgJIAAgGQgEithtiFQgQgTgTgTQh7h9ipgTIAAgDQgYgCgaAAQgVAAgVACg");
this.shape_1.setTransform(-3.3,-1.7);
this.shape_2 = new cjs.Shape();
this.shape_2.graphics.f("#FFCC00").s().p("AlDGFQgQgOgQgQQiViUAAjSQAAjDCBiPIAAAAIAUgVQAUgUAUgRQB9hmCigIQAWgCAVAAQAZAAAZACIAAADIgNgCQgZgCgbAAIgcABIAcgBQAbAAAZACIANACQCoATB8B9QATATAQAUQBsCEAFCvIAAAFIAAAIQAACqhhCCIgQATQgQAUgTATQiKCLjAAJIgbABQi5AAiKh3g");
this.shape_2.setTransform(-4.8,0.1);
this.shape_3 = new cjs.Shape();
this.shape_3.graphics.f("#695400").s().p("Ah6I1IgBAAQjHgKiUiJQCUB+DIAAIAeAAQDOgKCUiWQAUgTASgWQB6iSAAjFQAAjEh6iTQgSgWgUgUQiKiLi+gRQgbgDgdAAQjCAAiSB3QCSiBDBgKIABAAIAfAAIAbAAIAAAAQDXAJCbCcIAaAbIACAEQCJCcAADUIAAACQgBDViICaIgCAEQgMANgOANQikCmjpAAIgfAAg");
this.shape_3.setTransform(9,-1.7);
this.timeline.addTween(cjs.Tween.get({}).to({state:[{t:this.shape_3},{t:this.shape_2},{t:this.shape_1},{t:this.shape}]}).wait(1));
}).prototype = getMCSymbolPrototype(lib.coin, new cjs.Rectangle(-57.8,-58.2,113.9,113.1), null);
// stage content:
(lib.scratchGame_Canvas = function(mode,startPosition,loop) {
if (loop == null) { loop = false; } this.initialize(mode,startPosition,loop,{});
// timeline functions:
this.frame_0 = function() {
var pressBool=false;
var mask_mc = new createjs.Shape();
var bg_mc = new createjs.Bitmap("images/YLogo1.jpg");
//var coin_mc = new lib.coin();
var coin_mc = new createjs.Shape(new createjs.Graphics().beginFill("#FFFFFF").drawCircle(0, 0, 50));
coin_mc.x = stage.canvas.width/2;
coin_mc.y = stage.canvas.width/2;
stage.addChild(bg_mc, coin_mc);
createjs.Touch.enable(stage, false, true);
if(sRatio<1){
coin_mc.scaleX = coin_mc.scaleY = sRatio;
}
coin_mc.addEventListener('pressmove', moveCoin.bind(this));
coin_mc.addEventListener('mouseup', releaseCoin.bind(this));
updateCacheImage(false);
function moveCoin(e){
e.currentTarget.x = e.stageX;
e.currentTarget.y = e.stageY;
stage.update();
createMask(e);
}
function createMask(e) {
if(!pressBool)return;
var xLoc = stage.mouseX-20;
var yLoc = stage.mouseY-30;
mask_mc.graphics.beginFill("FFFFFF").drawEllipse(xLoc, yLoc, 40, 60);
updateCacheImage(true);
}
function updateCacheImage(update){
var w = 361;
if (update) {
mask_mc.updateCache();
} else {
mask_mc.cache(0, 0, w, w);
}
maskFilter = new createjs.AlphaMaskFilter(mask_mc.cacheCanvas);
bg_mc.filters = [maskFilter];
if (update) {
bg_mc.updateCache(0, 0, w, w);
} else {
bg_mc.cache(0, 0, w, w);
}
}
function releaseCoin(e) {
//stage.canvas.style.cursor = "default";
pressBool = false;
updateCacheImage(true);
}
}
// actions tween:
this.timeline.addTween(cjs.Tween.get(this).call(this.frame_0).wait(1));
}).prototype = p = new cjs.MovieClip();
p.nominalBounds = new cjs.Rectangle(385.9,359.4,113.9,113);
// library properties:
lib.properties = {
width: 550,
height: 400,
fps: 24,
color: "#999999",
opacity: 1.00,
manifest: [],
preloads: []
};
})(lib = lib||{}, images = images||{}, createjs = createjs||{}, ss = ss||{}, AdobeAn = AdobeAn||{});
var lib, images, createjs, ss, AdobeAn;
HTML Code:-
<!DOCTYPE html>
<!--
NOTES:
1. All tokens are represented by '$' sign in the template.
2. You can write your code only wherever mentioned.
3. All occurrences of existing tokens will be replaced by their appropriate values.
4. Blank lines will be removed automatically.
5. Remove unnecessary comments before creating your template.
-->
<html>
<head>
<meta charset="UTF-8">
<meta name="authoring-tool" content="Adobe_Animate_CC">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, minimal-ui" />
<meta name="msapplication-tap-highlight" content="no"/>
<title>scratchGame_Canvas</title>
<!-- write your code here -->
<script src="jquery-3.2.1.slim.min.js"></script>
<script src="createjs-2015.11.26.min.js"></script>
<script src="scratchGame_Canvas.js?1497868121984"></script>
<script>
var canvas, stage, exportRoot, anim_container, dom_overlay_container, fnStartAnimation;
var pRatio = window.devicePixelRatio || 1, xRatio, yRatio, sRatio=1;
function init() {
canvas = document.getElementById("canvas");
anim_container = document.getElementById("animation_container");
dom_overlay_container = document.getElementById("dom_overlay_container");
handleComplete();
}
function handleComplete() {
//This function is always called, irrespective of the content. You can use the variable "stage" after it is created in token create_stage.
exportRoot = new lib.scratchGame_Canvas();
stage = new createjs.Stage(canvas);
stage.addChild(exportRoot);
//Registers the "tick" event listener.
fnStartAnimation = function() {
createjs.Ticker.setFPS(lib.properties.fps);
createjs.Ticker.addEventListener("tick", stage);
}
//Code to support hidpi screens and responsive scaling.
function makeResponsive(isResp, respDim, isScale, scaleType) {
var lastW, lastH, lastS=1;
window.addEventListener('resize', resizeCanvas);
resizeCanvas();
function resizeCanvas() {
var w = lib.properties.width, h = lib.properties.height;
var iw = window.innerWidth, ih=window.innerHeight;
pRatio = window.devicePixelRatio || 1, xRatio=iw/w, yRatio=ih/h, sRatio=1;
if(isResp) {
if((respDim=='width'&&lastW==iw) || (respDim=='height'&&lastH==ih)) {
sRatio = lastS;
}
else if(!isScale) {
if(iw<w || ih<h)
sRatio = Math.min(xRatio, yRatio);
}
else if(scaleType==1) {
sRatio = Math.min(xRatio, yRatio);
}
else if(scaleType==2) {
sRatio = Math.max(xRatio, yRatio);
}
}
canvas.width = w*pRatio*sRatio;
canvas.height = h*pRatio*sRatio;
canvas.style.width = dom_overlay_container.style.width = anim_container.style.width = w*sRatio+'px';
canvas.style.height = anim_container.style.height = dom_overlay_container.style.height = h*sRatio+'px';
stage.scaleX = pRatio*sRatio;
stage.scaleY = pRatio*sRatio;
lastW = iw; lastH = ih; lastS = sRatio;
}
}
makeResponsive(true,'both',false,1);
fnStartAnimation();
}
</script>
<!-- write your code here -->
</head>
<body onload="init();" style="margin:0px;">
<div id="animation_container" style="background-color:rgba(153, 153, 153, 1.00); width:550px; height:400px">
<canvas id="canvas" width="550" height="400" style="position: absolute; display: block; background-color:rgba(153, 153, 153, 1.00);"></canvas>
<div id="dom_overlay_container" style="pointer-events:none; overflow:hidden; width:550px; height:400px; position: absolute; left: 0px; top: 0px; display: block;">
</div>
</div>
</body>
</html>
Hope to get response soon.
Thanks.
As I mentioned in the comments, you can transform the coordinates, so your x/y mouse position is not affected by the canvas scaling by responsiveness, and one alternative is to use, in the binded function with the pressmove event (in your case, the function moveCoin()), the globalToLocal() method.
scratchGame_Canvas.js
Function moveCoin()
function moveCoin(e){
var point;
point = stage.globalToLocal(e.stageX, e.stageY);
e.currentTarget.x = point.x;
e.currentTarget.y = point.y;
stage.update();
createMask(e);
}
See also: Drag and drop with easeljs in Animate CC 2017
& MovieClip class (EaselJS API)

Multiple Bing Map Pushpins from SQL not showing in Firefox & Chrome but do in IE

I'm displaying a Bing Map (v7) in my Webmatrix2 website with a series of pushpins & infoboxes drawn from a SQL Express database using a JSON enquiry.
While the maps appears in all 3 browsers I'm testing (IE, FF & Chrome) the pushpins are sometimes not showing in FF & Chrome, particularly if I refresh with Cntrl+F5
This is my first JSON and Bing Maps app so expect there's a few mistakes.
Any suggestions on how to improve the code and get display consistency?
#{
Layout = "~/_MapLayout.cshtml";
}
<script type="text/javascript" src="~/Scripts/jquery-1.9.1.min.js"></script>
<script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0"></script>
<link rel="StyleSheet" href="infoboxStyles.css" type="text/css">
<script type="text/javascript">
var map = null;
var pinLayer, pinInfobox;
var mouseover;
var pushpinFrameHTML = '<div class="infobox"><a class="infobox_close" href="javascript:closeInfobox()"><img src="/Images/close2.jpg" /></a><div class="infobox_content">{content}</div></div><div class="infobox_pointer"><img src="images/pointer_shadow.png"></div>';
var pinLayer = new Microsoft.Maps.EntityCollection();
var infoboxLayer = new Microsoft.Maps.EntityCollection();
function getMap() {
map = new Microsoft.Maps.Map(document.getElementById('map'), {
credentials: "my-key",
zoom: 4,
center: new Microsoft.Maps.Location(-25, 135),
mapTypeId: Microsoft.Maps.MapTypeId.road
});
pinInfobox = new Microsoft.Maps.Infobox(new Microsoft.Maps.Location(0, 0), { visible: false });
AddData();
}
$(function AddData() {
$.getJSON('/ListSchools', function (data) {
var schools = data;
$.each(schools, function (index, school) {
for (var i = 0; i < schools.length; i++) {
var pinLocation = new Microsoft.Maps.Location(school.SchoolLat, school.SchoolLon);
var NewPin = new Microsoft.Maps.Pushpin(pinLocation);
NewPin.title = school.SchoolName;
NewPin.description = "-- Learn More --";
pinLayer.push(NewPin); //add pushpin to pinLayer
Microsoft.Maps.Events.addHandler(NewPin, 'mouseover', displayInfobox);
}
});
infoboxLayer.push(pinInfobox);
map.entities.push(pinLayer);
map.entities.push(infoboxLayer);
});
})
function displayInfobox(e) {
if (e.targetType == "pushpin") {
var pin = e.target;
var html = "<span class='infobox_title'>" + pin.title + "</span><br/>" + pin.description;
pinInfobox.setOptions({
visible: true,
offset: new Microsoft.Maps.Point(-33, 20),
htmlContent: pushpinFrameHTML.replace('{content}', html)
});
//set location of infobox
pinInfobox.setLocation(pin.getLocation());
}
}
function closeInfobox() {
pinInfobox.setOptions({ visible: false });
}
function getCurrentLocation() {
var geoLocationProvider = new Microsoft.Maps.GeoLocationProvider(map);
geoLocationProvider.getCurrentPosition();
}
</script>
<body onload="getMap();">
<div id="map" style="position:relative; width:800px; height:600px;"></div>
<div>
<input type="button" value="Find Nearest Schools" onclick="getCurrentLocation();" />
</div>
</body>
The JSON file is simply
#{
var db = Database.Open("StarterSite");
var sql = #"SELECT * FROM Schools WHERE SchoolLon != ' ' AND SchoolLon != 'null' ";
var data = db.Query(sql);
Json.Write(data, Response.Output);
}
Add your pinLayer, infobox, and infoboxLayer before calling the AddData function and see if that makes a difference. Also verify that school.SchoolLat and school.SchoolLon are numbers and not a string version of a number. If they are a string, then use parseFloat to turn them into a number. Other than that everything looks fine.

Draw line between two points using OpenLayers

I have two points having lolLat as 0,10 and 30,0
Now to draw a marker at this point i use this transform while generating marker for it
lonLat.transform(
new OpenLayers.Projection("EPSG:4326"), // transform from WGS 1984
map.getProjectionObject() // to Spherical Mercator Projection
)
How can i draw line between them is there any way to do that in openlayers,i have tried doing it with linestring in vector layer but it doesn't seems to be working for me.
In OpenLayers version 3.3, you can do this as
var points = [ [-89.8802, 32.5804], [-95.04286, 46.9235] ];
for (var i = 0; i < points.length; i++) {
points[i] = ol.proj.transform(points[i], 'EPSG:4326', 'EPSG:3857');
}
var featureLine = new ol.Feature({
geometry: new ol.geom.LineString(points)
});
var vectorLine = new ol.source.Vector({});
vectorLine.addFeature(featureLine);
var vectorLineLayer = new ol.layer.Vector({
source: vectorLine,
style: new ol.style.Style({
fill: new ol.style.Fill({ color: '#00FF00', weight: 4 }),
stroke: new ol.style.Stroke({ color: '#00FF00', width: 2 })
})
});
Then add layer to map
map.addLayer(vectorLineLayer);
For example:
map = new OpenLayers.Map();
var start_point = new OpenLayers.Geometry.Point(0,10);
var end_point = new OpenLayers.Geometry.Point(30,0);
var vector = new OpenLayers.Layer.Vector();
vector.addFeatures([new OpenLayers.Feature.Vector(new OpenLayers.Geometry.LineString([start_point, end_point]))]);
map.addLayers([vector]);
Live demo
I am aware that this is an old question, but no up-to-date answer exists.
Here is a runnable code as an answer, using current version of Openlayers (August 2022).
const Feature = ol.Feature;
const VectorSource = ol.source.Vector;
const VectorLayer = ol.layer.Vector;
const LineString = ol.geom.LineString;
//const Point = ol.geom.Point;
const Style = ol.style.Style;
const Stroke = ol.style.Stroke;
const fromLonLat = ol.proj.fromLonLat;
const Overlay = ol.Overlay;
// Two locations with long/lat values in degrees
const lonlat0 = [100.538142, 13.765230];
const lonlat1 = [100.529321, 13.793656];
/* BEGIN: Code for the line joining the 2 points */
var points = [fromLonLat(lonlat0), fromLonLat(lonlat1)];
var line_feat1 = new Feature({
geometry: new LineString(points),
name: "My_Simple_LineString"
});
var line_vsrc = new VectorSource({
features: [line_feat1],
wrapX: false
});
var lineStyle = new Style({
stroke: new Stroke({
color: "red",
width: 5,
//lineDash: [4, 4, 4],
lineCap: "butt"
/* https://openlayers.org/en/latest/apidoc/module-ol_style_Stroke.html */
})
});
var veclay_line = new VectorLayer({
source: line_vsrc,
style: lineStyle
});
// `veclay_line` is the outcome of this complicate code
/* END: Code for the line joining the 2 points */
// Create map
// Note: `veclay_line`, containing the LineString is used within `layers`
var map = new ol.Map({
target: "map",
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
veclay_line
],
view: new ol.View({
center: ol.proj.fromLonLat(lonlat0),
zoom: 13
})
});
.map {
height: 400px;
width: 100%;
}
<head>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io#master/en/v6.15.1/css/ol.css" type="text/css">
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io#master/en/v6.15.1/build/ol.js"></script>
<title>OpenLayers 6</title>
</head>
<body>
<div id="map" class="map"></div>
</body>
As this question comes up on top in search results, I figured giving the current v6 answer would be beneficial.
It's a bit more complicated now, need to create a bunch of intermediary objects (at least as far as I understood):
const raster = new ol.layer.Tile({
source: new ol.source.OSM(),
});
const source = new ol.source.Vector();
const p1 = [-12500000, 6500000];
const p2 = [-10000000, 4000000];
const line = new ol.geom.LineString([p1, p2]);
const feature = new ol.Feature({
geometry: line,
name: "Line"
});
source.addFeature(feature);
const vector = new ol.layer.Vector({
source: source,
});
const map = new ol.Map({
layers: [raster, vector],
target: 'mapdiv',
view: new ol.View({
center: [-11000000, 4600000],
zoom: 4,
}),
});
You can then also modify the geometry on the fly with e.g.
line.appendCoodrinate([long,lat]);
and the map will be updated extending the line.
Here's a working demo for v6: Live demo
I don't get why the coord format is this way (10000ths of a degree), the docs on Coordinates, for example, show "normal" values, but code examples use that.