I'm fairly new to javascript and kinetic-js.
A while ago I created a script containing a Shape with Kinetic-js 3.9.0.
It was something like this (just the relevant code):
popup = new Kinetic.Shape({
drawFunc: function() {
item = itemlist[0];
},
itemlist: []
}
With 3.9.0 that worked in Firefox, but as of 3.9.2 it doesn't work any more.
Ther error console gives the message "TypeError: popup.itemlist is undefined".
What am I doing wrong?
I think you should initialize the itemlist variable after declaring the popup object.
It seems that Kinetic doesn't accepts user variables in their constructors methods.
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
<script src="http://www.html5canvastutorials.com/libraries/kinetic-v3.10.5.js"></script>
<script>
function draw() {
var stage = new Kinetic.Stage({
container : "container",
width : 800,
height : 600
});
var layer = new Kinetic.Layer();
var popup = new Kinetic.Shape({
drawFunc: function(context) {
context.fillText(this.itemlist[0], 10,10);
context.fillText(this.itemlist[1], 10,50);
context.fillText(this.itemlist[2], 10,90);
this.fill(context);
this.stroke(context);
},
fill: "red",
stroke: "green", strokeWidth:1
});
popup.itemlist = ["one", "two", "three"];
layer.add(popup);
// Add the layer to the stage
stage.add(layer);
};
window.onload = draw;
</script>
</head>
<body>
<div id="container"></div>
</body>
</html>
Related
Is it possible to insert custom HTML-code as a xaxisLabel of a bar - graph?
Like
xaxisLabels: ['<i class="fa fas fa-check fa-2x"></i>']
In the result, the closing-Tag (</i>) is missing.
There's no option to add custom HTML to labels but since the labels are DOM nodes (if you're using DOM text - which is on by default) you can manipulate them to you hearts content that way. Here's an example:
<!DOCTYPE html>
<html>
<head>
<script src="https://www.rgraph.net/libraries/RGraph.common.core.js"></script>
<script src="https://www.rgraph.net/libraries/RGraph.bar.js"></script>
</head>
<body>
<h1>Clickable labels</h1>
<canvas id="cvs1" width="600" height="250">[No canvas support]</canvas>
<script>
bar = new RGraph.Bar({
id:'cvs1',
data: '8,4,6,3,5,4,2'.split(','),
options: {
xaxisLabels: ['Mon','Tue','Wed','Thu','Fri','Sat','Sun'],
textAccessiblePointerevents: true,
// If you just want to manipulate the style of the labels
// there are these five properties
//xaxisLabelsSize: 16,
//xaxisLabelsFont: 'Verdana',
//xaxiLabelsBold: true,
//xaxisLabelsItalic: true,
//xaxisLabelsColor: 'red'
}
}).draw();
labels = document.getElementsByClassName('rgraph_accessible_text_xaxis_labels');
// Maniuplate the style
for (i=0; i<labels.length; ++i) {
labels[i].style.fontWeight = 'bold';
labels[i].style.fontStyle = 'italic';
labels[i].style.fontSize = '14pt';
labels[i].style.color = 'red';
labels[i].style.fontFamily = 'Verdana';
}
// Add a click event listener
labels[0].addEventListener('click', function (e)
{
alert('Label was clicked');
}, false);
// Add a mousemove event listener
labels[0].addEventListener('mousemove', function (e)
{
e.target.style.cursor = 'pointer';
}, false);
</script>
</body>
</html>
And on codepen:
https://codepen.io/rgraph/pen/poEOKPV
EDIT:
In addition you could also use the RGraph.text.find() function after you create the chart like this:
labels = RGraph.text.find({
object: bar,
text: 'Wed'
});
labels[0].style.fontWeight = 'bold';
labels[0].style.cursor = 'pointer';
labels[0].addEventListener('click', function (e)
{
alert('My label!');
}, false);
I keep getting this error ReferenceError: Can't find variable: Set file: http://localhost:1337/bundle.min.js line: 33098
It looks like window.tableau.getSchema() and myConnector.getData() have never been called. I add a log message, but it has never been executed.
Solution from #redec is to add polyfill for react. But I still got error.
Here is my html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Dashboard</title>
<link rel="shortcut icon" href="favicon.ico">
</head>
<body>
<div id="app">
</div>
<script src="https://connectors.tableau.com/libs/tableauwdc-2.3.latest.js" type="text/javascript"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/7.2.5/polyfill.min.js"
type="text/javascript"></script>
</body>
</html>
Here is the component that will display on Tableu WDC, the route will be enter via WDC on Tableu Desktop app is http://localhost:1337/tableau/wdc
import React, { Component } from 'react';
class TableauWDC extends Component {
constructor(props, context) {
super(props, context);
this.state = {
isScriptLoaded: false
};
}
componentDidMount() {
// Create the connector object
var myConnector = window.tableau.makeConnector();
// Define the schema
myConnector.getSchema = function (schemaCallback) {
window.tableau.log("getSchema")
var cols = [{
id: "id",
dataType: window.tableau.dataTypeEnum.string
}, {
id: "mag",
alias: "magnitude",
dataType: window.tableau.dataTypeEnum.float
}, {
id: "title",
alias: "title",
dataType: window.tableau.dataTypeEnum.string
}, {
id: "location",
dataType: window.tableau.dataTypeEnum.geometry
}];
var tableSchema = {
id: "earthquakeFeed",
alias: "Earthquakes with magnitude greater than 4.5 in the last seven days",
columns: cols
};
schemaCallback([tableSchema]);
};
// Download the data
myConnector.getData = function (table, doneCallback) {
window.tableau.log("getData")
this.loadJSON('https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/4.5_week.geojson',
function (data) {
var feat = data.features,
tableData = [];
// Iterate over the JSON object
for (var i = 0, len = feat.length; i < len; i++) {
tableData.push({
"id": feat[i].id,
"mag": feat[i].properties.mag,
"title": feat[i].properties.title,
"location": feat[i].geometry
});
}
table.appendRows(tableData);
doneCallback();
},
function (xhr) { console.error(xhr); }
);
};
window.tableau.registerConnector(myConnector);
}
loadJSON(path, success, error) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200) {
if (success)
success(JSON.parse(xhr.responseText));
} else {
if (error)
error(xhr);
}
}
};
xhr.open("GET", path, true);
xhr.send();
}
submit() {
window.tableau.connectionName = "USGS Earthquake Feed"; // This will be the data source name in Tableau
window.tableau.submit(); // This sends the connector object to Tableau
}
render() {
return (
<div style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
height: "calc( 90vh - 65px)"
}}>
<button onClick={() => this.submit()} className="btn btn-success" >Get Earthquake Data!</button>
</div>
);
}
}
export default TableauWDC;
I keep getting these errors.
A snippet from the error is below here
The web data connector has reported an unrecoverable error and cannot proceed. If the connector has reported details of the error, they are displayed in the pane below.
Script error. file: line: 0
Unfortunately the browser that tableau uses is not es6 compliant so it is missing some es6 components that react needs (such as Set and Map)...so you need to polyfill them. Add this after your tableau <script> tag:
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/7.2.5/polyfill.min.js" type="text/javascript"></script>�
Currently tableau uses an old version of QtWebKit, but rumors say they'll be switching to chromium within the next couple of releases.
It is also a little weird that your registration is being done from a click handler on a div? I would expect that to be done on componentDidMount so it is done as soon as the WDC loads (otherwise tableau will display a warning banner)
Starting with Tableau v2019.4, it is using QTWebEngine ~5.10 which supports ES6 so your code should work without any shims.
I want want to put several markers on the map, these markers are consisting of "parent" markers and "child" markers. All parent markers should be visible on the map the same time, whereas the child-markers of a specific parent-marker should be toggled on/off if clicking onto the specific parent-marker
I created the following working example to demonstrate:
<!DOCTYPE html>
<html>
<head>
<title>Test 1</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.0.1/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet#1.0.1/dist/leaflet.js"></script>
<style>
body {padding: 0; margin: 0;}
html, body, #map {height: 100%;}
</style>
</head>
<body>
<div id='map'></div>
<script>
var thunder = L.tileLayer('https://{s}.tile.thunderforest.com/neighbourhood/{z}/{x}/{y}.png', {subdomains:'abc', attribution:'Thunderforest | OpenStreetMap' });
var map = L.map('map',{layers: [thunder]}).setView([50.08, 10.08], 12);
var parent1 = L.marker([50.0, 10.0]).bindPopup('Marker 1');
var parent2 = L.marker([50.1, 10.1]).bindPopup('Marker 2');;
var layergroupParents = L.layerGroup([parent1, parent2]);
layergroupParents.addTo(map);
var child1a = L.marker([50.02, 10.02],{title: 'Child 1a'});
var child1b = L.marker([50.04, 10.04],{title: 'Child 1b'});
var layergroupChilds1 = L.layerGroup([child1a, child1b]);
var child2a = L.marker([50.12, 10.12],{title: 'Child 2a'});
var child2b = L.marker([50.14, 10.14],{title: 'Child 2b'});
var layergroupChilds2 = L.layerGroup([child2a, child2b]);
parent1.on('click', function(){
if (map.hasLayer(layergroupChilds1)) {
map.removeLayer(layergroupChilds1)
} else {
layergroupChilds1.addTo(map);
}
});
parent2.on('click', function(){
if (map.hasLayer(layergroupChilds2)) {
map.removeLayer(layergroupChilds2)
} else {
layergroupChilds2.addTo(map);
}
});
</script>
</body>
</html>
Since I want to display quite a lot markers, I want put the marker's properties into an Array ("markerArray") and process its markers by the help of For-Loops:
<!DOCTYPE html>
<html>
<head>
<title>Test 2</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.0.1/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet#1.0.1/dist/leaflet.js"></script>
<style>
body {padding: 0; margin: 0;}
html, body, #map {height: 100%;}
</style>
</head>
<body>
<div id='map'></div>
<script>
var thunder = L.tileLayer('https://{s}.tile.thunderforest.com/neighbourhood/{z}/{x}/{y}.png', {subdomains:'abc', attribution:'Thunderforest | OpenStreetMap' });
var map = L.map('map',{layers: [thunder]}).setView([50.08, 10.08], 12);
var markerArray = [
["Marker 1", 50.0, 10.0, [["Child 1a", 50.02, 10.02], ["Child 1b", 50.04, 10.04]]],
["Marker 2", 50.1, 10.1, [["Child 1a", 50.12, 10.12], ["Child 1b", 50.14, 10.14]]],
];
var numberParents = markerArray.length;
var layergroupParents = L.layerGroup();
for (cnt1=0; cnt1<numberParents; cnt1++) {
var parentObject = L.marker([markerArray[cnt1][1], markerArray[cnt1][2]]);
parentObject.bindPopup(markerArray[cnt1][0]);
layergroupParents.addLayer (parentObject);
var numberChilds = markerArray[cnt1][3].length;
var layergroupChilds = L.layerGroup();
for (cnt2=0; cnt2<numberChilds; cnt2++) {
var childObject = L.marker([markerArray[cnt1][3][cnt2][1], markerArray[cnt1][3][cnt2][2]], {title: markerArray[cnt1][3][cnt2][0]});
layergroupChilds.addLayer (childObject);
}
parentObject.on('click', function(){
if (map.hasLayer(layergroupChilds)) {
map.removeLayer(layergroupChilds)
} else {
layergroupChilds.addTo(map);
}
});
}
layergroupParents.addTo(map);
</script>
</body>
</html>
If you execute these script you will see, that there's some problem with assigning an individual 'click' event to each individual parent-marker. Right now just the child-markers of the last parent-marker are toggled on/off even if I click onto the first parent-marker.
Do you have an idea how I could solve these problem and Script 2 is working like in Script 1?
For it to work, you have to attach the children to the parent (using a javascript property)
var layergroupChilds = L.layerGroup();
parentObject.layergroupChilds = layergroupChilds;
When parent receives a click, you can find the parent object in the event e, and hence its children.
parentObject.on('click', function(e){
if (map.hasLayer(e.target.layergroupChilds)) {
map.removeLayer(e.target.layergroupChilds)
} else {
e.target.layergroupChilds.addTo(map);
}
});
Here is your code with corrections
I have setup a map with polygons around the countries on the map, and want to add an infobox so that on hover some information will be displayed for each country.
I can get infoboxes displaying easy enough without the polygons, but when assigning them to the PolygonOptions class, nothing happens. The docs say that so long as I have the Bing Themes module loaded (Which I do), the infoboxes will show up on hover and click.
There seems to be zero documentation/examples of this, so hoping you clever folks can help out.
Here is some of the relevant code;
var center = this.map.getCenter();
// Create an info box
var infoboxOptions = {
width: 300,
height: 100,
title: 'Testing', // sourceItems.data.dataset[0].data[index].key,
description: "Visits: 20", // + sourceItems.data.dataset[0].data[index].visits,
showPointer: true,
titleClickHandler: this.polygonInfo,
offset: new Microsoft.Maps.Point(-100, 0),
typeName: Microsoft.Maps.InfoboxType.mini,
zIndex: 1000
};
var polyinfobox = new Microsoft.Maps.Infobox(center, infoboxOptions);
var polygonOptions = {
fillColor: Microsoft.Maps.Color.fromHex(fillColour),
strokeColor: Microsoft.Maps.Color.fromHex(fillColour),
strokeThickness: 1,
infobox: polyinfobox
};
var result = new Microsoft.Maps.Polygon(vertices, polygonOptions);
There is a working code sample in the interactive SDK for the Bing Maps V7 control here: http://www.bingmapsportal.com/ISDK/AjaxV7#BingThemeModule6
Note that creating an infobox for each shape is very inefficient and will hurt performance if you have a lot of shapes. A better method is to have one infobox and dynamically populate it's data. I wrote a blog post on this here: http://rbrundritt.wordpress.com/2011/10/13/multiple-pushpins-and-infoboxes-in-bing-maps-v7/ If you want to use this approach here is a code sample:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0"></script>
<script type="text/javascript">
var map, dataLayer, infobox;
function GetMap()
{
map = new Microsoft.Maps.Map(document.getElementById("mapDiv"), {
credentials: "YOUR_BING_MAPS_KEY"
});
dataLayer = new Microsoft.Maps.EntityCollection();
map.entities.push(dataLayer);
var infoboxLayer = new Microsoft.Maps.EntityCollection();
map.entities.push(infoboxLayer);
infobox = new Microsoft.Maps.Infobox(new Microsoft.Maps.Location(0, 0), { visible: false });
infoboxLayer.push(infobox);
AddData();
}
function AddData(){
var polygon = new Microsoft.Maps.Polygon([
new Microsoft.Maps.Location(45, -110),
new Microsoft.Maps.Location(65, -90),
new Microsoft.Maps.Location(45, -70)]);
polygon.Metadata = {
title: 'Hello',
description: 'World'
};
dataLayer.push(polygon);
Microsoft.Maps.Events.addHandler(polygon, 'click', displayInfobox);
Microsoft.Maps.Events.addHandler(polygon, 'mouseover', displayInfobox);
}
function displayInfobox(e){
if(e.target){
var point = new Microsoft.Maps.Point(e.getX(), e.getY());
var loc = map.tryPixelToLocation(point);
infobox.setLocation(loc);
var opt = e.target.Metadata;
if(opt){
if(e.target.getIcon){ //is pushpin
opt.offset = new Microsoft.Maps.Point(0,20);
}else{
opt.offset = new Microsoft.Maps.Point(0,0);
}
opt.visible = true;
infobox.setOptions(opt);
}
}
}
</script>
</head>
<body onload="GetMap();">
<div id='mapDiv' style="position:relative; width:600px; height:600px;"></div>
</body>
</html>
someone knows why I have a completely srewed up layout in my d3 scales while entering or updating array values between 5 and 9 and bigger than 100 ?
I have setted up here the example: http://bl.ocks.org/vertighel/5149663
As you can see from the code and in this picture, the bar chart must not exceed a width of 500px and a color of orange...
but try to insert a value between 5 and 9 or bigger than 100 and you'll see. Let's change the "11" in "9":
width and color scale completely screwed up!
This is the code:
<!doctype html>
<meta charset="utf8"></meta>
<title>Test</title>
<style type="text/css">
li{border: 1px solid white; background-color: steelblue; color: white}
li{width: 50px; text-align:right; }
li:hover{opacity:0.7;}
.clicked{background-color: green}
:invalid{background-color: pink}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<input id="inp" value="1,23,42,20,11,33,21" pattern="(\d+)(,\s*\d+)*" required>
<label for="inp">change me</label>
<h1>click on the bars</h1>
<script>
var list = d3.select("body").append("ul");
update()
d3.select("input").on("change",update)
function update(){
var array = d3.select("input").property("value").split(",")
console.log(array);
var cscale = d3.scale.linear()
.domain(d3.extent(array))
.range(["steelblue","orange"])
var wscale = d3.scale.linear()
.domain(d3.extent(array))
.range(["10px","500px"])
var elem = list.selectAll("li").data(array);
elem.enter()
.append("li")
elem.text(function(d){return d})
.transition()
.style("width", function(d){return wscale(d)})
.style("background-color", function(d){return cscale(d)})
elem.on("click",function(d,i){d3.select("h1").text("list item "+i+" has value "+d)})
elem.exit().remove()
}
</script>
You're seeing this because your numbers aren't actually numbers, but strings. In particular, a "9" is only one character long while all your other "numbers" are two characters long (similarly for "100").
The solution is to convert your strings into integers. One way of doing this is to use the map() function as follows. Replace
var array = d3.select("input").property("value").split(",")
to
var array = d3.select("input").property("value").split(",")
.map(function(d) { return(+d); });
The map() function may or may not be implemented in your setup, see here for more information and an implementation you can use.