I'm using 2 custom patterns and trying to make AR.js recognize them. both of the markers are 6x6 barcodes that I've made into pattern using AR.js Marker Training, and put the downloaded pattens into the folder (as 500.patt and 600.patt). The result is both markers identified when I show it a single marker as showed in picture.
In addition, I would like to get a reaction when a marker is recognized (that's why the console prints are there), but although both markers' shapes are drawn, there are no prints in the console.
My code:
`<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ar.js</title>
</head>
<!-- include A-Frame obviously -->
<script src="https://aframe.io/releases/0.6.0/aframe.min.js"></script>
<!-- include ar.js for A-Frame -->
<script src="https://jeromeetienne.github.io/AR.js/aframe/build/aframe-ar.js"></script>
<body style='margin : 0px; overflow: hidden;'>
<a-scene embedded arjs="patternRatio: 0.90">
<!-- create your content here. just a box for now -->
<!-- define a camera which will move according to the marker position -->
<a-marker-camera type='pattern' url='500.patt'>
<a-box position='0 0.5 0' material='opacity: 0.5; color: red;'></a-box>
console.log(500);
</a-marker-camera>
<a-marker-camera type='pattern' url='600.patt'>
<a-sphere position='0 0.5 0' material='opacity: 0.5; color: blue;'></a-sphere>
console.log(600);
</a-marker-camera>
</a-scene>
</body>
</html>`
Outcome:
How do I make the pattern recognition show only one item and print the correct pattern recognized?
Thanks
How to log something to the console when a marker is recognized:
AFRAME.registerComponent('registerevents', {
init: function () {
var marker = this.el;
marker.addEventListener('markerFound', function() {
var markerId = marker.id;
console.log('! markerFound', markerId);
// do additional things you want to do
});
marker.addEventListener('markerLost', function() {
var markerId = marker.id;
console.log('! markerLost', markerId);
// do additional things you want to do
});
}
});
Then add the registerevents component to your marker:
<a-marker id="marker" preset='hiro' registerevents>
That should do it.
Related
I just started trying the A-frame with AR.js to hopefully get an object to render on a piece of paper. I have tested the object and it is correctly rendered. However, when I try it with a custom image, it no longer works... I am trying to show a gltf file on a pattern. THe pattern is (in image form): and was made using https://jeromeetienne.github.io/AR.js/three.js/examples/marker-training/examples/generator.html
Does anyone see anything wrong with my code as to why that pattern is not being taken by the camera as a match? Is it my code? or is it something to do with the pattern file I am trying to load?
<head>
<script src="https://aframe.io/releases/0.8.0/aframe.min.js"></script>
<script src="https://cdn.rawgit.com/jeromeetienne/AR.js/1.6.0/aframe/build/aframe-ar.js"></script>
</head>
<body style='margin : 0px; overflow: hidden;'>
<a-scene embedded arjs='sourceType: webcam;'>
<a-assets>
<a-asset-item id="mesh" src="./data/Camargue.gltf"></a-asset-item>
</a-assets>
<a-entity gltf-model="#mesh" rotation="0 180 0" modify-materials></a-entity>
<a-light type="directional" color="#fff" position="-1 -5 -5" look-at="a-entity"></a-light>
<a-light type="ambient" color="#fff" intensity="3" look-at="a-entity"></a-light>
<a-marker-camera type="pattern" patternUrl="data/pattern-logo.patt"></a-marker-camera>
</a-scene>
<script>
AFRAME.registerComponent('modify-materials', {
init: function () {
// Wait for model to load.
this.el.addEventListener('model-loaded', () => {
// Grab the mesh / scene.
const obj = this.el.getObject3D('mesh');
// Go over the submeshes and modify materials we want.
obj.traverse(node => {
if (node.name.indexOf('Loggia-frame') !== -1) {
var environment = new THREE.CubeTextureLoader().setPath('data/HDR/').load(
[
'posx.jpg', 'negx.jpg', 'posy.jpg', 'negy.jpg', 'posz.jpg', 'negz.jpg'
]
);
environment.format = THREE.RGBFormat;
environment.mapping = THREE.CubeReflectionMapping;
var material = node.material;
material.envMap = environment;
}
});
});
}
});
</script>
</body>
Currently trying to implement/solve an issue with an ESRI ArcGIS map environment where I have a multi-layered map with custom graphics being rendered in each layer. Some of the graphics are simple shapes such as lines and circles, but a majority of the graphics are icons (.png) files that are being drawn on the layers. (All of this is being done in JavaScript.)
I have been able to get all of the layers generated correctly - the data IS NOT being stored in ArcGIS maps but a custom designed Contact & Location database (SQL) and other forms within the web application maintain this C&L data.
The graphic icons that are rendered on the map need to have a mouse-over tooltip popup appear with information that has been stored with the icon when it is created where the .substitute() command will update the template. The information displayed is HTML formatted in a <div>.
Problem:
When the mouse is moved over an icon, the tooltipDialog appears but 1) it always appears in the lower right corner of the screen - despite "orient:" and specific "x:" and "y:" coordinates being specified. Additionally when the tooltipDialog.open() command is executed, the dialog's offsetHeight is set to 624 and the offsetTop is set to 502. (The offsetWidth is actually set to the correct value.) How do I override either/both the offsetHeight/offsetTop?
I have tried specifying additional parameters to the tooltipDialog.open() command but nothing tried so far has altered the outcome. Even when I change the template content to be as simple as "Hi There!" does not change the outcome.
Note: If I click on an icon the IconWindow dialog will popup with the proper content and formatting being displayed. So it leads me to believe that the issue is within CSS or some other aspect of dojo/dijit as the tooltipDialog.open() command is actually where the offset changes are being made - the values are retained (offsetTop=0 offsetHeight=0) prior to the open() call.
Ideas/Recommendations?
You could try to use the dijit/popup module to open the TooltipDialog, which would allow you to pass in the DOM node around which the tooltip should be opened:
popup.open({
popup: myTooltipDialog,
around: dom.byId('thenode')
});
There a full example of this here (next to "A TooltipDialog may be popped up from any node.")
Well, It seems like you want to show info popup with some offset value whenever you hover on any feature on the map.
Solution-
Well to do so i don't think you need to deal with TooltipDialog because whenever you are loading feature or feature layer on the map you can attach info popup to it. It will take care of entire loading and displaying info popup Dialog along with its positioning.
To pass offset value-
If want to pass some offset value to popup dialog you can use below mentioned properties:-
For more Properties of popup dialog refer this link- https://developers.arcgis.com/javascript/3/jsapi/popup.html
Hovering Dialog sample-
<!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>Feature Layer - display results as an InfoWindow onHover</title>
<link rel="stylesheet" href="https://js.arcgis.com/3.18/dijit/themes/tundra/tundra.css">
<link rel="stylesheet" href="https://js.arcgis.com/3.18/esri/css/esri.css">
<style>
html, body, #mapDiv {
padding:0;
margin:0;
height:100%;
}
#mapDiv {
position: relative;
}
#info {
background: #fff;
box-shadow: 0 0 5px #888;
left: 1em;
padding: 0.5em;
position: absolute;
top: 1em;
z-index: 40;
}
</style>
<script src="https://js.arcgis.com/3.18/"></script>
<script>
var map, dialog;
require([
"esri/map", "esri/layers/FeatureLayer",
"esri/symbols/SimpleFillSymbol", "esri/symbols/SimpleLineSymbol",
"esri/renderers/SimpleRenderer", "esri/graphic", "esri/lang",
"esri/Color", "dojo/number", "dojo/dom-style",
"dijit/TooltipDialog", "dijit/popup", "dojo/domReady!"
], function(
Map, FeatureLayer,
SimpleFillSymbol, SimpleLineSymbol,
SimpleRenderer, Graphic, esriLang,
Color, number, domStyle,
TooltipDialog, dijitPopup
) {
map = new Map("mapDiv", {
basemap: "streets",
center: [-80.94, 33.646],
zoom: 8,
slider: false
});
var southCarolinaCounties = new FeatureLayer("https://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Demographics/ESRI_Census_USA/MapServer/3", {
mode: FeatureLayer.MODE_SNAPSHOT,
outFields: ["NAME", "POP2000", "POP2007", "POP00_SQMI", "POP07_SQMI"]
});
southCarolinaCounties.setDefinitionExpression("STATE_NAME = 'South Carolina'");
var symbol = new SimpleFillSymbol(
SimpleFillSymbol.STYLE_SOLID,
new SimpleLineSymbol(
SimpleLineSymbol.STYLE_SOLID,
new Color([255,255,255,0.35]),
1
),
new Color([125,125,125,0.35])
);
southCarolinaCounties.setRenderer(new SimpleRenderer(symbol));
map.addLayer(southCarolinaCounties);
map.infoWindow.resize(245,125);
dialog = new TooltipDialog({
id: "tooltipDialog",
style: "position: absolute; width: 250px; font: normal normal normal 10pt Helvetica;z-index:100"
});
dialog.startup();
var highlightSymbol = new SimpleFillSymbol(
SimpleFillSymbol.STYLE_SOLID,
new SimpleLineSymbol(
SimpleLineSymbol.STYLE_SOLID,
new Color([255,0,0]), 3
),
new Color([125,125,125,0.35])
);
//close the dialog when the mouse leaves the highlight graphic
map.on("load", function(){
map.graphics.enableMouseEvents();
map.graphics.on("mouse-out", closeDialog);
});
//listen for when the onMouseOver event fires on the countiesGraphicsLayer
//when fired, create a new graphic with the geometry from the event.graphic and add it to the maps graphics layer
southCarolinaCounties.on("mouse-over", function(evt){
var t = "<b>${NAME}</b><hr><b>2000 Population: </b>${POP2000:NumberFormat}<br>"
+ "<b>2000 Population per Sq. Mi.: </b>${POP00_SQMI:NumberFormat}<br>"
+ "<b>2007 Population: </b>${POP2007:NumberFormat}<br>"
+ "<b>2007 Population per Sq. Mi.: </b>${POP07_SQMI:NumberFormat}";
var content = esriLang.substitute(evt.graphic.attributes,t);
var highlightGraphic = new Graphic(evt.graphic.geometry,highlightSymbol);
map.graphics.add(highlightGraphic);
dialog.setContent(content);
domStyle.set(dialog.domNode, "opacity", 0.85);
dijitPopup.open({
popup: dialog,
x: evt.pageX,
y: evt.pageY
});
});
function closeDialog() {
map.graphics.clear();
dijitPopup.close(dialog);
}
});
</script>
</head>
<body class="tundra">
<div id="mapDiv">
<div id="info">
Hover over a county in South Carolina to get more information.
</div>
</div>
</body>
</html>
Hoping this will help you :)
However its always recommended to add your code here if you are looking for exact Fix.
Found the answer to my situation. There is what appears to be an unstated requirement that either one of the supplied CSS dijit/themes be utilized OR the user must create their own theme which has some CSS that configures the display location.
The offsetTop issue was resolved by using eliminating any style references to top:.
i have a basic geoJson program in javascript by using leaflet API.
<html>
<head>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.6.4/leaflet.css" />
<script src="http://cdn.leafletjs.com/leaflet-0.6.4/leaflet.js"></script>
<script src="india.js" type="text/javascript"></script>
</head>
<body>
<div id = "map1" style="width: 1100px; height: 400px"> </div>
<script>
var area = L.map('map1', {center: [27.8800,78.0800], zoom: 4 });
L.tileLayer('http://a.tiles.mapbox.com/v3/raj333.map-gugr5h08/{z}/{x}/{y}.png').addTo(area);
var indiaLayer= L.geoJson(india, {style: {weight: 2,
opacity: 1,
color: 'white',
dashArray: '3',
fillOpacity: 0.1}});
area.addLayer(indiaLayer);
function clicked(){
this.options.style.fillOpacity = 0.8;
//how to refresh layer in the given map
}
indiaLayer.on('click', clicked);
</script>
</body>
</html>
the problem is how would i automatically refresh the content of Layer on the map.
example here
function clicked(){
indiaLayer.style.fillOpacity = 0.8;
//how to refresh layer in the given map
}
indiaLayer.on('click', clicked);
when user click on indiaLayer , the fillOpacity variable changes but doesn't reflect back on map which is understood since i am not refreshing the map. I don't know how to do it.
please help
P/s: these are the functions available on indiaLayer object (i.e. this object inside clicked function...which one to use for this purpose or there exist none)
You can check the list of methods available of GEOJson in the Leaflef documentation This is the link to v.0.7.7, which is the closest available to used in this example.
Last time I've used
map._onResize();
and that help me refresh map. Maybe a little hack, but, it work.
In your code will be area._onResize()
P.S: Maybe you should try change the way to set new opacity value - try change
function clicked(){
this.options.style.fillOpacity = 0.8;
}
to that
function clicked(){
this.setStyle({fillOpacity: 0.2});
}
map.invalidateSize();
map._onResize() - it's a hack, and there is no guarantee that it won't be removed in future versions.
area.fitBounds(area.getBounds());
I'm using the Nokia API for my web app (Javascript), and I draw circles in my map with different radium. The thing is when I zoom in, the circle has the same size, which means that when I zoom in, there's a level where I can't see anything else since it covers the whole map. Hence, I want the circle to keep the same size even if I zoom in.
For that, I tried SVG Markers, which solve this problem, but the thing is I had to program when I click on one of them, the color has to change (it's all a mess, and it reduces the performance of the app).
If anyone can help me, that would be awesome !
There are three key points which need to be answered to find a solution your question.
To add functionality when a marker is clicked, you need to add a listener to the click event i.e. marker.addListener("click", function (evt) { ...etc
To switch the color of an SVG marker you need two separate icons for that marker. The icon property is immutable, and hence it should only be updated using the set() method i.e. marker.set("icon", markerIcon);
To force a refresh of the screen after the new icon has been set you need to update the map display - map.update(-1, 0);
Combining these points togther there is a working example appended below. You need to substitute in your own app id and token to get it to work of course.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<meta http-equiv="X-UA-Compatible" content="IE=7; IE=EmulateIE9" />
<title>Highlighing a marker: Istanbul (Not Constantinople)</title>
<meta name="description" content="" />
<meta name="keywords" content="" />
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<script language="javascript" src="http://api.maps.nokia.com/2.2.4/jsl.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<p> Click on the marker to change it.</p>
<div id="gmapcanvas" style="width:600px; height:600px;" > </div><br/><br/>
<script type="text/javascript">
// <![CDATA[
/////////////////////////////////////////////////////////////////////////////////////
// Don't forget to set your API credentials
//
// Replace with your appId and token which you can obtain when you
// register on http://api.developer.nokia.com/
//
nokia.Settings.set( "appId", "YOUR APP ID GOES HERE");
nokia.Settings.set( "authenticationToken", "YOUR AUTHENTICATION TOKEN GOES HERE");
/////////////////////////////////////////////////////////////////////////////////////
map = new nokia.maps.map.Display(document.getElementById('gmapcanvas'), {
'components': [
// Behavior collection
new nokia.maps.map.component.Behavior(),
new nokia.maps.map.component.ZoomBar()
],
'zoomLevel': 5, // Zoom level for the map
'center': [41.0125,28.975833] // Center coordinates
});
// Remove zoom.MouseWheel behavior for better page scrolling experience
map.removeComponent(map.getComponentById("zoom.MouseWheel"));
var iconSVG =
'<svg width="33" height="33" xmlns="http://www.w3.org/2000/svg">' +
'<circle stroke="__ACCENTCOLOR__" fill="__MAINCOLOR__" cx="16" cy="16" r="16" />' +
'<text x="16" y="20" font-size="10pt" font-family="arial" font-weight="bold" text-anchor="middle" fill="__ACCENTCOLOR__" textContent="__TEXTCONTENT__">__TEXT__</text>' +
'</svg>',
svgParser = new nokia.maps.gfx.SvgParser(),
// Helper function that allows us to easily set the text and color of our SVG marker.
createIcon = function (text, mainColor, accentColor) {
var svg = iconSVG
.replace(/__TEXTCONTENT__/g, text)
.replace(/__TEXT__/g, text)
.replace(/__ACCENTCOLOR__/g, accentColor)
.replace(/__MAINCOLOR__/g, mainColor);
return new nokia.maps.gfx.GraphicsImage(svgParser.parseSvg(svg));
};
/* On mouse over we want to change the marker's color and text
* hence we create two svg icons which we flip on mouse over.
*/
var markerText = "1";
var colors = ["#FF0000", "#00FF00", "#0000FF", "#FFFF00", "#00FFFF", "#FF00FF" , "#000000"];
var markerIcon= createIcon("1", "#F00", "#FFF");
map.addListener("click", function (evt) {
var target = evt.target;
if (target instanceof nokia.maps.map.Marker && (target.clickCount === undefined) == false){
target.clickCount++;
var icon = createIcon(target.clickCount, colors[target.clickCount%7], "#FFF");
target.set("icon", icon);
map.update(-1, 0);
}
if (evt.target instanceof nokia.maps.map.Spatial) {
evt.stopImmediatePropagation();
}
});
var istanbul = new nokia.maps.map.Marker(
// Geo coordinate of Istanbul
[41.0125,28.975833],
{
icon: markerIcon,
clickCount : 1
}
);
/// Let's add another marker for comparison:
var bucharest = new nokia.maps.map.Marker(
// Geo coordinate of Bucharest
[44.4325, 26.103889],
{
icon: markerIcon,
clickCount: 1
}
);
// We add the marker to the map's object collection so it will be rendered onto the map.
map.objects.addAll([istanbul, bucharest]);
// ]]>
</script>
</body>
</html>
I am using FabricJS to develop a simple floor plan editor. When adding a Line (that should be a wall) to the canvas, I want the ability to control only the length of the line, not it's width-height.
I have tried setting lockScalingY: true but the problem is that when adding a line the control handles are so close to each other that I can't interact only with the horizontal control handles... the corner handles actually block the horizontal handles...
How can this be done?
Fine control of adjoining FabricJS lines
The way graphics programs like photoshop deal with this common problem is to let the user position lines near the desired intersection and then use the arrowkeys to "nudge" the line into place pixel one at a time.
The code below illustrates a rough solution that does the same thing for FabricJS lines:
User selects a line.
Turn off the control handles and borders.
Let the user "nudge" the line into perfect alignment (here the line length is increased).
Turn the the control handles and borders back On.
This is just "proof of concept" code. In your production app:
You'll probably want to use arrowkeys instead of buttons to "nudge".
I made nudging go 10px at a time--you might do this 1px at a time.
And when the user starts nudging, you'll automatically turn off the handles and borders for them.
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/dd742/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script type="text/javascript" src="fabric.min.js"></script>
<style>
body{ background-color: ivory; padding:30px; }
canvas{border: 1px solid red; }
</style>
<script>
$(function(){
var canvas = new fabric.Canvas('canvas');
var selectedLine;
var line1=newLine(50,100,150,100,"red");
var line2=newLine(160,50,160,150,"green");
canvas.add(line1,line2);
function newLine(x1,y1,x2,y2,color){
var line=new fabric.Line(
[x1,y1,x2,y2],
{fill:color,strokeWidth:15,selectable:true}
);
return(line);
};
$("#hOff").click(function(){
selectedLine.hasBorders=false;
selectedLine.hasControls=false;
canvas.renderAll();
});
$("#hOn").click(function(){
selectedLine.hasBorders=false;
selectedLine.hasControls=true;
canvas.renderAll();
});
$("#shorter").click(function(){
changeLineLength(selectedLine,-10);
canvas.renderAll();
});
$("#longer").click(function(){
changeLineLength(selectedLine,10);
canvas.renderAll();
});
function changeLineLength(line,adjustment){
if(!selectedLine){return;}
if(line.get("y1")==line.get("y2")){ // line is horizontal
line.set("x2",line.get("x2")+adjustment);
}else
if(line.get("x1")==line.get("x2")){ // line is vertical
line.set("y2",line.get("y2")+adjustment);
}else{ // line is diagonal
line.set("x2",line.get("x2")+adjustment);
line.set("y2",line.get("y2")+adjustment);
}
}
canvas.observe('object:selected', function(eventTarget) {
var event=eventTarget.e;
var target=eventTarget.target;
selectedLine=target;
});
}); // end $(function(){});
</script>
</head>
<body>
<p>Select a line,</p><br/>
<p>Turn handles Off</p><br/>
<p>Make lines intersect by pressing longer/shorter</p><br/>
<canvas id="canvas" width="600" height="200"></canvas>
<button id="hOff">Handles Off</button>
<button id="shorter">Shorter</button>
<button id="longer">Longer</button><br/>
<button id="hOn">Handles On</button>
</body>
</html>
May be helps somebody.
Add handler to event
'object:selected': _objSelected
Then at handler set unneeded control to false.
function _objSelected(e)
{
if(e.target.objectType == 'line')
{
var cv = e.target._controlsVisibility;
// mt - middle top, tl - top left and etc.
cv.mt = cv.mb = cv.tl = cv.bl = cv.tr = cv.br = false;
}
}
Also I added objectType (custom property) and padding (for beauty) to new object Line
var obj = new fabric.Line([50, 50, 150, 50], { padding: 10, objectType: 'line' });