I am attempting to add infowindows to the markers with PlaceDetails that are returned after a google searchbox search. When I click on the markers no infowindows open. I cannot figure out where I went wrong?
var infowindow = new google.maps.InfoWindow();
//Function for search box
var input = document.getElementById('target');
var searchBox = new google.maps.places.SearchBox(input);
var markers = [];
google.maps.event.addListener(searchBox, 'places_changed', function() {
var places = searchBox.getPlaces();
for (var i = 0, marker; marker = markers[i]; i++) {
marker.setMap(null);
}
markers = [];
var bounds = new google.maps.LatLngBounds();
for (var i = 0, place; place = places[i]; i++) {
var image = new google.maps.MarkerImage(
'img/pin_blue.png',
new google.maps.Size(15,29),
new google.maps.Point(0,0),
new google.maps.Point(8,29)
);
var shadow = new google.maps.MarkerImage(
'img/pin_shadow.png',
new google.maps.Size(33,29),
new google.maps.Point(0,0),
new google.maps.Point(8,29)
);
var shape = {
coord: [11,1,12,2,13,3,14,4,14,5,14,6,14,7,14,8,14,9,14,10,14,11,14,12,13,13,12,14,11,15,8,16,8,17,8,18,8,19,8,20,8,21,8,22,8,23,8,24,11,25,11,26,11,27,3,27,3,26,3,25,6,24,6,23,6,22,6,21,6,20,6,19,6,18,6,17,6,16,3,15,2,14,1,13,0,12,0,11,0,10,0,9,0,8,0,7,0,6,0,5,0,4,1,3,2,2,3,1,11,1],
type: 'poly'
};
var marker = new google.maps.Marker({
map: map,
icon: image,
shadow: shadow,
shape: shape,
title: place.name,
position: place.geometry.location
});
markers.push(marker);
bounds.extend(place.geometry.location);
}
map.fitBounds(bounds);
//add an infowindow
google.maps.event.addListener(markers, 'click', function() {
infowindow.setContent(place.name);
infowindow.open(map, markers[i]);
});
});
google.maps.event.addListener(map, 'bounds_changed', function() {
//var bounds = map.getBounds();
searchBox.bindTo('bounds', map);
});
};
To get the Place Details to use in the InfoWindow, you need to make a second request to the Places API (when the marker is clicked). Inside the createMarker function (which has function closure on the "place"):
var request = {
reference: place.reference
};
google.maps.event.addListener(marker,'click',function(){
service.getDetails(request, function(place, status) {
if (status == google.maps.places.PlacesServiceStatus.OK) {
var contentStr = '<h5>'+place.name+'</h5><p>'+place.formatted_address;
if (!!place.formatted_phone_number) contentStr += '<br>'+place.formatted_phone_number;
if (!!place.website) contentStr += '<br><a target="_blank" href="'+place.website+'">'+place.website+'</a>';
contentStr += '<br>'+place.types+'</p>';
infowindow.setContent(contentStr);
infowindow.open(map,marker);
} else {
var contentStr = "<h5>No Result, status="+status+"</h5>";
infowindow.setContent(contentStr);
infowindow.open(map,marker);
}
});
});
Example
I little bit changed your code.
Try this one.
<html>
<head>
<script src="http://maps.googleapis.com/maps/api/js?sensor=false&libraries=places"></script>
<script type='text/javascript'>
var map, infowindow;
var searchBox;
var markers = [];
function initialize() {
var mapDiv = document.getElementById("map_canvas");
map = new google.maps.Map(mapDiv, {
center : new google.maps.LatLng(35, 138),
zoom : 7,
mapTypeId : google.maps.MapTypeId.ROADMAP
});
infowindow = new google.maps.InfoWindow();
//Function for search box
var input = document.getElementById('target');
searchBox = new google.maps.places.SearchBox(input);
google.maps.event.addListener(searchBox, 'places_changed', function() {
var places = searchBox.getPlaces();
for (var i = 0, marker; marker = markers[i]; i++) {
marker.setMap(null);
}
markers = [];
var bounds = new google.maps.LatLngBounds();
for (var i = 0, place; place = places[i]; i++) {
var image = new google.maps.MarkerImage('img/pin_blue.png', new google.maps.Size(15, 29), new google.maps.Point(0, 0), new google.maps.Point(8, 29));
var shadow = new google.maps.MarkerImage('img/pin_shadow.png', new google.maps.Size(33, 29), new google.maps.Point(0, 0), new google.maps.Point(8, 29));
var shape = {
coord : [11, 1, 12, 2, 13, 3, 14, 4, 14, 5, 14, 6, 14, 7, 14, 8, 14, 9, 14, 10, 14, 11, 14, 12, 13, 13, 12, 14, 11, 15, 8, 16, 8, 17, 8, 18, 8, 19, 8, 20, 8, 21, 8, 22, 8, 23, 8, 24, 11, 25, 11, 26, 11, 27, 3, 27, 3, 26, 3, 25, 6, 24, 6, 23, 6, 22, 6, 21, 6, 20, 6, 19, 6, 18, 6, 17, 6, 16, 3, 15, 2, 14, 1, 13, 0, 12, 0, 11, 0, 10, 0, 9, 0, 8, 0, 7, 0, 6, 0, 5, 0, 4, 1, 3, 2, 2, 3, 1, 11, 1],
type : 'poly'
};
var marker = createMarker({
map : map,
//icon : image,
//shadow : shadow,
//shape : shape,
title : place.name,
position : place.geometry.location,
place_name : place.name
})
markers.push(marker);
bounds.extend(place.geometry.location);
}
map.fitBounds(bounds);
});
google.maps.event.addListener(map, 'bounds_changed', function() {
//var bounds = map.getBounds();
searchBox.bindTo('bounds', map);
});
}
function createMarker(options) {
var marker = new google.maps.Marker(options);
//add an infowindow
google.maps.event.addListener(marker, 'click', function() {
infowindow.setContent(options.place_name);
infowindow.open(map, marker);
});
return marker;
}
google.maps.event.addDomListener(window, "load", initialize);
</script>
</head>
<body>
<input type="text" id="target" />
<div id="map_canvas" style="width: 500px;height:400px"></div>
</body>
</html>
Related
sha 256 Encrypt code (from document)
function hmacEncrypt(r) {
let str = r.uri.split("/", 2)
return require('crypto').createHash('sha256', 'key')
.update(str)
.digest('base64url');
}
I want to use njs to decode aes256, base64 encoded string.
However, the official njs document only shows the encrypt method.
Is there a way to decode or encode aes256? Can I help you?
For the aes256, you can do something like:
const crypto = require("crypto");
const initVector = new Uint8Array([
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
]);
function encryptString(string, securityKey) {
const cipher = crypto.createCipheriv(
'aes-256-cbc',
securityKey,
initVector
);
cipher.update(string, 'utf-8', 'hex');
return cipher.final('hex');
}
function decryptString(string, securityKey) {
const decipher = crypto.createDecipheriv(
'aes-256-cbc',
securityKey,
initVector
);
decipher.update(string, 'hex', 'utf-8');
return decipher.final('utf-8');
}
The initVector is to provide the initial state of the algorithm, you can change it to whatever you want but it should be an array of exactly 16 bytes, then just simply use those functions:
const securityKey = new Uint8Array([
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
31, 32
]);
const text = 'example string';
const encrypted = encryptString(text, securityKey);
const decrypted = decryptString(encrypted, securityKey);
console.log(encrypted);
console.log(decrypted);
The securityKey key is the password that will be used to encrypt and decrypt the string, it should be an array of exactly 32 bytes, change it to whatever you want!
My goal is to create Boxes with individual images on each side, which I have been completing by using a TriangleMesh to create the boxes, and using a single texture to map the points over the Mesh.
The issue is that I have been experiencing heavy overhead (high ram, long load times and slowness when moving objects in the world) from creating these TriangleMesh, and I'm not sure why fully, but here are a few of my guesses.
I initially tried to use a total of 8 points and reuse the points when creating the individual faces, and wrap the textures, but for some reason the texcoords did not like using only 8 points. As I look at Box's class I see they use 24 points as well as I do, so it seems we cannot reuse points.
2.a I am loading the 3 images into an hbox and then taking a snapshot to then map the coordinates. I am wondering if somehow snapshot is causing issues, or if there is some issue with the amount of pixels.
2.b This further comes into question when I tried turning multiple boxes
that were stacked together into one large box and it still having a
ton of slowness, if not more. I would take a snapshot of x number
of images and then map them onto this one big Box. i.e., if I had
5x5x5 it would be one box with 5 images mapped on each side. Even
with 1 single mesh it still causes slowness. It speeds up if I edit
the "fitWidth/fitHeight" of the imageView which causes a quality
change. To me, it seems like the pixel amounts are the cause. The thing is, if I'm taking the same images and just multiplying them, why is it causing slowness? Especially since when doing a normal box, the single image I was using had more pixels than the other images, so I would think it would be faster by doing the trianglemesh myself.
I don't really have a working example since this was added to an already working program that has data, but I will try to create something if need be.
I'm just trying to figure out why making a TriangleMesh on my own, which has similar code to the Box's code except.
without the face smoothing group, but not sure that matters.
My face array is different, and a bit confused why they have 24 points but the face array only goes from 1-8
int[] faces = {
2, 2, 1, 1, 0, 0, //front
2, 2, 3, 3, 1, 1,
6, 6, 5, 5, 4, 4, //right
6, 6, 7, 7, 5, 5,
10, 10, 9, 9, 8, 8, //back
10, 10, 11, 11, 9, 9,
14, 14, 13, 13, 12, 12,//left
14 ,14, 15, 15, 13, 13,
18, 18, 17, 17, 16, 16,//top
18, 18, 19, 19, 17, 17,
22, 22, 21, 21, 20, 20, //bottom
22, 22, 23, 23, 21, 21`
My texCoords are 6 sets of pairs instead of the 1 set here.
static TriangleMesh createMesh(float w, float h, float d) {
// NOTE: still create mesh for degenerated box
float hw = w / 2f;
float hh = h / 2f;
float hd = d / 2f;
float points[] = {
-hw, -hh, -hd,
hw, -hh, -hd,
hw, hh, -hd,
-hw, hh, -hd,
-hw, -hh, hd,
hw, -hh, hd,
hw, hh, hd,
-hw, hh, hd};
float texCoords[] = {0, 0, 1, 0, 1, 1, 0, 1};
// Specifies hard edges.
int faceSmoothingGroups[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
int faces[] = {
0, 0, 2, 2, 1, 1,
2, 2, 0, 0, 3, 3,
1, 0, 6, 2, 5, 1,
6, 2, 1, 0, 2, 3,
5, 0, 7, 2, 4, 1,
7, 2, 5, 0, 6, 3,
4, 0, 3, 2, 0, 1,
3, 2, 4, 0, 7, 3,
3, 0, 6, 2, 2, 1,
6, 2, 3, 0, 7, 3,
4, 0, 1, 2, 5, 1,
1, 2, 4, 0, 0, 3,
};
TriangleMesh mesh = new TriangleMesh(true);
mesh.getPoints().setAll(points);
mesh.getTexCoords().setAll(texCoords);
mesh.getFaces().setAll(faces);
mesh.getFaceSmoothingGroups().setAll(faceSmoothingGroups);
return mesh;
}
I also had heard that there were improvements to 3D with Version 9. I have been trying to update the past few days to 11 with issues (I had tried 10 before but a lot of my code needed fixings), and 9 isn't downloading so I wanted to ask before trying to put in more effort to get 11 working if it will in fact improve the situation, but I am still wondering why trianglmesh is so slowed comparatively. I'm maybe making 1000 boxes max.
Thank you
EDIT:
Example of how I create the images.
public BoxMesh(width, height,depth, int stack)
{
float width = width;
float height = height;
float depth = depth
List<ImageView> imageList = new ArrayList();
imageList.add(new ImageView(new Image("file:"C:\\file1.jpg"));
HBox h = new HBox();
Image image = null;
for(int i = 0; i < stack; i++)
{
image = new Image("file:"C:\\file2.jpg");
ImageView iv = new ImageView(image);
iv.setFitWidth(image.getWidth()/2); //decreases quality to
iv.setFitHeight(image.getHeight()/2); //speed up program
h.getChildren().add(iv);
}
imageList.add(new ImageView(h.snapshot(null,null)));
VBox v = new VBox();
Image image = null;
for(int i = 0; i < stack; i++)
{
image = new Image("file:"C:\\file3.jpg");
ImageView iv = new ImageView(image);
iv.setFitWidth(image.getWidth()/2);
iv.setFitHeight(image.getHeight()/2);
v.getChildren().add(iv);
}
imageList.add(new ImageView(v.snapshot(null, null)));
PhongMaterial p = new PhongMaterial();
HBox hb = new HBox();
hb.getChildren().addAll(imageList);
WritableImage snapshot = hb.snapshot(null, null);
if(snapshot.isError())
{
System.out.println(snapshot.exceptionProperty().getValue());
}
p.setDiffuseMap(snapshot);
How do I prevent the first and last bars from being cut off (showing half)?
I need to show the short month names on the x-axis. I've tried playing around with various min/max settings, but I can't seem to get it right.
var graphData = {
dates: [
'2016-06-01',
'2016-07-01',
'2016-08-01',
'2016-09-01',
'2016-10-01',
'2016-11-01',
'2016-12-01',
'2017-01-01',
'2017-02-01',
'2017-03-01',
'2017-04-01',
'2017-05-01'
],
wins: [23, 5, 13, 24, 8, 11, 23, 5, 13, 24, 8, 11],
draws: [2, 1, 2, 0, 2, 2, 3, 1, 2, 4, 0, 1],
losses: [3, 1, 2, 10, 8, 8, 3, 1, 2, 10, 8, 8],
winRates: [50, 40, 72, 30, 46, 80, 50, 40, 72, 30, 46, 80]
};
var winsMax = Math.max.apply(Math, graphData.wins);
var lossesMax = Math.max.apply(Math, graphData.losses);
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: "bar",
data: {
labels: graphData.dates.map((date) => moment(date)),
datasets: [
{
type: "bar",
backgroundColor: "green",
hoverBackgroundColor: "green",
data: graphData.wins,
yAxisID: "winsAndLosses"
},
{
type: "bar",
backgroundColor: "red",
hoverBackgroundColor: "red",
data: graphData.losses.map((i) => -i),
yAxisID: "winsAndLosses"
},
{
type: "line",
data: graphData.winRates,
fill: true,
backgroundColor: "gray",
pointRadius: 0,
pointHoverRadius: 0,
yAxisID: "winRate"
}
]
},
options: {
legend: {
display: false
},
scales: {
xAxes: [{
type: "time",
time: {
unit: "month",
displayFormats: {
month: "MMM"
}
},
stacked: true,
gridLines: {
display: false
},
ticks: {
callback: (label) => label.toUpperCase(),
fontSize: 10
}
}],
yAxes: [
{
id: "winsAndLosses",
stacked: true,
ticks: {
min: (lossesMax + 10) * -1,
max: winsMax + 10,
callback: (label) => Math.abs(label) // TODO: Localization (number formatting).
},
display: false
},
{
id: "winRate",
ticks: {
min: 0,
max: 100,
stepSize: 10,
callback: (label) => label + "%", // TODO: Localization (number formatting).
fontSize: 10
}
}
]
}
}
});
.myChartDiv {
max-width: 800px;
max-height: 400px;
}
<script src="https://npmcdn.com/chart.js#latest/dist/Chart.bundle.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
<html>
<body>
<div class="myChartDiv">
<canvas id="myChart" width="800" height="400"></canvas>
</div>
</body>
</html>
There's a setting called offset which seems to work for me:
xAxes: [{
offset: true
}]
var graphData = {
dates: [
'2016-06-01',
'2016-07-01',
'2016-08-01',
'2016-09-01',
'2016-10-01',
'2016-11-01',
'2016-12-01',
'2017-01-01',
'2017-02-01',
'2017-03-01',
'2017-04-01',
'2017-05-01'
],
wins: [23, 5, 13, 24, 8, 11, 23, 5, 13, 24, 8, 11],
draws: [2, 1, 2, 0, 2, 2, 3, 1, 2, 4, 0, 1],
losses: [3, 1, 2, 10, 8, 8, 3, 1, 2, 10, 8, 8],
winRates: [50, 40, 72, 30, 46, 80, 50, 40, 72, 30, 46, 80]
};
var winsMax = Math.max.apply(Math, graphData.wins);
var lossesMax = Math.max.apply(Math, graphData.losses);
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: "bar",
data: {
labels: graphData.dates.map((date) => moment(date)),
datasets: [
{
type: "bar",
backgroundColor: "green",
hoverBackgroundColor: "green",
data: graphData.wins,
yAxisID: "winsAndLosses"
},
{
type: "bar",
backgroundColor: "red",
hoverBackgroundColor: "red",
data: graphData.losses.map((i) => -i),
yAxisID: "winsAndLosses"
},
{
type: "line",
data: graphData.winRates,
fill: true,
backgroundColor: "gray",
pointRadius: 0,
pointHoverRadius: 0,
yAxisID: "winRate"
}
]
},
options: {
legend: {
display: false
},
scales: {
xAxes: [{
type: "time",
time: {
unit: "month",
displayFormats: {
month: "MMM"
}
},
stacked: true,
gridLines: {
display: false
},
ticks: {
callback: (label) => label.toUpperCase(),
fontSize: 10
},
offset:true
}],
yAxes: [
{
id: "winsAndLosses",
stacked: true,
ticks: {
min: (lossesMax + 10) * -1,
max: winsMax + 10,
callback: (label) => Math.abs(label) // TODO: Localization (number formatting).
},
display: false
},
{
id: "winRate",
ticks: {
min: 0,
max: 100,
stepSize: 10,
callback: (label) => label + "%", // TODO: Localization (number formatting).
fontSize: 10
}
}
]
}
}
});
.myChartDiv {
max-width: 800px;
max-height: 400px;
}
<script src="https://npmcdn.com/chart.js#latest/dist/Chart.bundle.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
<html>
<body>
<div class="myChartDiv">
<canvas id="myChart" width="800" height="400"></canvas>
</div>
</body>
</html>
This is a followup on a previous question (see Coloring individual triangles in a triangle mesh on javafx) which I believe is another topic on its own.
Is there a way (with javafx) that I can get away from having to actually write to disk (or external device) an image file to use a texture?
In other words: can I use a specific texture without having to use Image?
Since my color map will change on runtime I don't want to have to write to disk every time I run it. Also, this might be a security issue (writing to disk) for someone using my app.(with javafx)
As #Jens-Peter-Haack suggest, with Snapshot you can create any image you want, and then apply this image as the diffusion map. For that, you need to create some nodes, fill them with the colors you require, group them in some container and then take the snapshot.
There's a straight-in approach, where you can build an image with a pattern of colors using PixelWriter.
Let's say you want 256 colors, this method will return an image of 256 pixels, where each pixel has one of these colors. For simplicity I've added two simple ways of building a palette.
public static Image colorPallete(int numColors){
int width=(int)Math.sqrt(numColors);
int height=numColors/width;
WritableImage img = new WritableImage(width, height);
PixelWriter pw = img.getPixelWriter();
AtomicInteger count = new AtomicInteger();
IntStream.range(0, height).boxed()
.forEach(y->IntStream.range(0, width).boxed()
.forEach(x->pw.setColor(x, y, getColor(count.getAndIncrement(),numColors))));
// save for testing purposes
try {
ImageIO.write(SwingFXUtils.fromFXImage(img, null), "jpg", new File("palette.jpg"));
} catch (IOException ex) { }
return img;
}
private Color getColor(int iColor, int numColors){
// nice palette of colors
java.awt.Color c = java.awt.Color.getHSBColor((float) iColor / (float) numColors, 1.0f, 1.0f);
return Color.rgb(c.getRed(), c.getGreen(), c.getBlue());
// raw palette
//return Color.rgb((iColor >> 16) & 0xFF, (iColor >> 8) & 0xFF, iColor & 0xFF);
}
Once you have the image object, you can set the diffuse map:
IcosahedronMesh mesh = new IcosahedronMesh();
PhongMaterial mat = new PhongMaterial();
mat.setDiffuseMap(colorPallete(256));
mesh.setMaterial(mat);
But you still have to provide the proper mapping to the new texture.
For this you need to map the vertices of the mesh to a pixel in the image.
First, we need a way to map colors with texture coordinates on the mesh. This method will return a pair of coordinates for a given color index:
public static float[] getTextureLocation(int iPoint, int numColors){
int width=(int)Math.sqrt(numColors);
int height=numColors/width;
int y = iPoint/width;
int x = iPoint-width*y;
return new float[]{(((float)x)/((float)width)),(((float)y)/((float)height))};
}
Finally, we add these textures to m.getTextCoords() and to the faces m.getFaces(), as shown here.
If we assign a color to every vertex in our icosahedron we pick a color from all the palette (scaling up or down according the number of colors and vertices), and then set every face with t0=p0, t1=p1, t2=p2:
IntStream.range(0,numVertices).boxed()
.forEach(i->m.getTexCoords()
.addAll(getTextureLocation(i*numColors/numVertices,numColors)));
m.getFaces().addAll(
1, 1, 11, 11, 7, 7,
1, 1, 7, 7, 6, 6,
1, 1, 6, 6, 10, 10,
1, 1, 10, 10, 3, 3,
1, 1, 3, 3, 11, 11,
4, 4, 8, 8, 0, 0,
5, 5, 4, 4, 0, 0,
9, 9, 5, 5, 0, 0,
2, 2, 9, 9, 0, 0,
8, 8, 2, 2, 0, 0,
11, 11, 9, 9, 7, 7,
7, 7, 2, 2, 6, 6,
6, 6, 8, 8, 10, 10,
10, 10, 4, 4, 3, 3,
3, 3, 5, 5, 11, 11,
4, 4, 10, 10, 8, 8,
5, 5, 3, 3, 4, 4,
9, 9, 11, 11, 5, 5,
2, 2, 7, 7, 9, 9,
8, 8, 6, 6, 2, 2
);
This will give us something like this:
EDIT
Playing around with the textures coordinates, instead of mapping node with color, you can add some function and easily create a contour plot, like this:
You might create the texture to be used for fill etc. in your code by using any graphic object and convert that into an image in memory, not touching disk.
The example below will create a texture using a green spline.
Pane testImage2(Pane pane) {
Pane inner = new Pane();
inner.prefWidthProperty().bind(pane.widthProperty());
inner.prefHeightProperty().bind(pane.heightProperty());
pane.getChildren().add(inner);
SVGPath texture = new SVGPath();
texture.setStroke(Color.GREEN);
texture.setStrokeWidth(2.5);
texture.setFill(Color.TRANSPARENT);
texture.setContent("M 10 10 C 40 10 10 70 70 20");
SnapshotParameters params = new SnapshotParameters();
params.setViewport(new Rectangle2D(-5, -5, 70, 50));
Image image = texture.snapshot(params, null);
Paint paint = new ImagePattern(image, 5,5, 20, 20, false);
inner.setBackground(new Background(new BackgroundFill(paint, new CornerRadii(0), new Insets(inset))));
return pane;
}
I am using the graphaeljs library to display charts, at an ASP.NET MVC 4
I have copied this code from the graphaeljs website
<script src="scripts/raphael.js"></script>
<script src="scripts/g.raphael-min.js"></script>
<script src="scripts/g.bar-min.js"></script>
<script>
window.onload = function () {
var r = Raphael("holder"),
fin = function () {
this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
},
fout = function () {
this.flag.animate({ opacity: 0 }, 300, function () { this.remove(); });
},
fin2 = function () {
var y = [], res = [];
for (var i = this.bars.length; i--;) {
y.push(this.bars[i].y);
res.push(this.bars[i].value || "0");
}
this.flag = r.popup(this.bars[0].x, Math.min.apply(Math, y), res.join(", ")).insertBefore(this);
},
fout2 = function () {
this.flag.animate({ opacity: 0 }, 300, function () { this.remove(); });
},
txtattr = { font: "12px sans-serif" };
r.text(160, 10, "Single Series Chart").attr(txtattr);
r.text(480, 10, "Multiline Series Stacked Chart").attr(txtattr);
r.text(160, 250, "Multiple Series Chart").attr(txtattr);
r.text(480, 250, "Multiline Series Stacked Chart\nColumn Hover").attr(txtattr);
r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]]).hover(fin, fout);
r.hbarchart(330, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55]], { stacked: true }).hover(fin, fout);
r.hbarchart(10, 250, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55]]).hover(fin, fout);
var c = r.barchart(330, 250, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55]], { stacked: true, type: "soft" }).hoverColumn(fin2, fout2);
};
</script>
But when I run at my browser, this message appears
Uncaught TypeError: Cannot read property 'x' of undefined raphael.js:11
c._engine.create raphael.js:11
c raphael.js:9
window.onload (index):92
I do not know what I do wrong, and I used the libraries exactly as they are. Can you please tell me, what might be my mistake?
Sorry, I don't see anything wrong with the code you posted.
I made a fiddle for you.
It is obviously an issue with the raphael.js file.
Be sure to include class="raphael" on your body tag, and a div with id="holder".
If that fails, try re-downloading raphael.js.