I'm trying to create a stacked bar chart with Clartjs.Blazor version 2.0.2. After a long research, I found the source code of this library.
The application is a Blazor WebAssembly. So, I added in the index.html
<script src="lib/moment.js/moment.js"></script>
<script src="lib/Chart.js/chart.js"></script>
<script src="_content/ChartJs.Blazor.Fork/ChartJsBlazorInterop.js"></script>
In the page I added the graph
#page "/"
#using ChartJs.Blazor.BarChart
#using ChartJs.Blazor.BarChart.Axes
#using System.Drawing
#using System.Collections.Generic
#using System.Collections.ObjectModel
<Chart Config="_config" #ref="_chart"></Chart>
<button #onclick="RandomizeData">Randomize Data</button>
#code { private const int InitalCount = 7;
private BarConfig _config;
private Chart _chart;
protected override void OnInitialized()
{
_config = new BarConfig
{
Options = new BarOptions
{
Responsive = true,
Title = new OptionsTitle
{
Display = true,
Text = "Chart.js Bar Chart - Stacked"
},
Tooltips = new Tooltips
{
Mode = InteractionMode.Index,
Intersect = false
},
Scales = new BarScales
{
XAxes = new List<CartesianAxis>
{
new BarCategoryAxis
{
Stacked = true
}
},
YAxes = new List<CartesianAxis>
{
new BarLinearCartesianAxis
{
Stacked = true
}
}
}
}
};
IDataset<int> dataset1 = new BarDataset<int>(RandomScalingFactor(InitalCount))
{
Label = "Dataset 1",
BackgroundColor = ColorUtil.FromDrawingColor(ChartColors.Red)
};
IDataset<int> dataset2 = new BarDataset<int>(RandomScalingFactor(InitalCount))
{
Label = "Dataset 2",
BackgroundColor = ColorUtil.FromDrawingColor(ChartColors.Blue)
};
IDataset<int> dataset3 = new BarDataset<int>(RandomScalingFactor(InitalCount))
{
Label = "Dataset 3",
BackgroundColor = ColorUtil.FromDrawingColor(ChartColors.Green)
};
_config.Data.Labels.AddRange(Months.Take(InitalCount));
_config.Data.Datasets.Add(dataset1);
_config.Data.Datasets.Add(dataset2);
_config.Data.Datasets.Add(dataset3);
}
private void RandomizeData()
{
foreach (IDataset<int> dataset in _config.Data.Datasets)
{
int count = dataset.Count;
dataset.Clear();
dataset.AddRange(RandomScalingFactor(count));
}
_chart.Update();
}
private static readonly Random _rng = new Random();
public static class ChartColors
{
private static readonly Lazy<IReadOnlyList<Color>> _all = new Lazy<IReadOnlyList<Color>>(() => new Color[7]
{
Red, Orange, Yellow, Green, Blue, Purple, Grey
});
public static IReadOnlyList<Color> All => _all.Value;
public static readonly Color Red = Color.FromArgb(255, 99, 132);
public static readonly Color Orange = Color.FromArgb(255, 159, 64);
public static readonly Color Yellow = Color.FromArgb(255, 205, 86);
public static readonly Color Green = Color.FromArgb(75, 192, 192);
public static readonly Color Blue = Color.FromArgb(54, 162, 235);
public static readonly Color Purple = Color.FromArgb(153, 102, 255);
public static readonly Color Grey = Color.FromArgb(201, 203, 207);
}
public static IReadOnlyList<string> Months { get; } = new ReadOnlyCollection<string>(new[]
{
"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
});
private static int RandomScalingFactorThreadUnsafe() => _rng.Next(-100, 100);
public static int RandomScalingFactor()
{
lock (_rng)
{
return RandomScalingFactorThreadUnsafe();
}
}
public static IEnumerable<int> RandomScalingFactor(int count)
{
int[] factors = new int[count];
lock (_rng)
{
for (int i = 0; i < count; i++)
{
factors[i] = RandomScalingFactorThreadUnsafe();
}
}
return factors;
}
public static IEnumerable<DateTime> GetNextDays(int count)
{
DateTime now = DateTime.Now;
DateTime[] factors = new DateTime[count];
for (int i = 0; i < factors.Length; i++)
{
factors[i] = now.AddDays(i);
}
return factors;
}
}
For future reference, this code should create the following graph. I found this code in GitHub.
Obviously, it didn't work for me. When I run the application Blazor raises an error
crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
Unhandled exception rendering component: Cannot read properties of undefined (reading 'onClick')
TypeError: Cannot read properties of undefined (reading 'onClick')
at getDefaultFunc (https://localhost:44384/_content/ChartJs.Blazor.Fork/ChartJsBlazorInterop.js:75:116)
Is it only me that facing this issue? Is there a way to fix it?
I had this same problem and it came down to the version of chart.js.
I was using chart.js v3.5.1.
When I switched to v2.9.4 the onClick was resolved.
Related
I have been trying to create a custom brush paint with an image file using fabric JS . I have tried using the fabric.PatternBrush but this is not the exact thing that I was looking for because this creates a background pattern kind of paint and what I am trying to do is repeat the image wherever the mouse is dragged.
Can anyone please direct me towards the right way? It will be fine for me to switch to any other drawing library that does what I am looking for.
I found a solution to this problem. We can create a custom brush using fabric.BaseBrush as follows:
fabric.SprayBrush = fabric.util.createClass(fabric.BaseBrush, {
opacity: .2,
width: 30,
_baseWidth: 5,
_drips: [],
_dripThreshold: 15,
_inkAmount: 0,
_interval: 20,
_lastPoint: null,
_point: null,
_strokeId: 0,
brush: null,
brushCol : '/static/img/creation_room/textures/texture2.png',
initialize: function(canvas, opt) {
var context = this;
opt = opt || {};
this.canvas = canvas;
this.width = opt.width || canvas.freeDrawingBrush.width;
this.opacity = opt.opacity || canvas.contextTop.globalAlpha;
this.color = opt.color || canvas.freeDrawingBrush.color;
this.canvas.contextTop.lineJoin = "round";
this.canvas.contextTop.lineCap = "round";
this._reset();
fabric.Image.fromURL(this.brushCol, function(brush) {
console.log(brush);
context.brush = brush;
context.brush.filters = [];
context.changeColor(context.color || this.color);
}, { crossOrigin: "anonymous" });
},
changeColor: function(color) {
this.color = color;
this.brush.filters[0] = new fabric.Image.filters.Tint({ color: color });
this.brush.applyFilters(this.canvas.renderAll.bind(this.canvas));
},
changeOpacity: function(value) {
this.opacity = value;
this.canvas.contextTop.globalAlpha = value;
},
onMouseDown: function(pointer) {
this._point = new fabric.Point(pointer.x, pointer.y);
this._lastPoint = this._point;
this.size = this.width + this._baseWidth;
this._strokeId = +new Date();
this._inkAmount = 0;
this.changeColor(this.color);
this._render();
},
onMouseMove: function(pointer) {
this._lastPoint = this._point;
this._point = new fabric.Point(pointer.x, pointer.y);
},
onMouseUp: function(pointer) {
},
_render: function() {
var context = this;
setTimeout(draw, this._interval);
function draw() {
var point, distance, angle, amount, x, y;
point = new fabric.Point(context._point.x || 0, context._point.y || 0);
distance = point.distanceFrom(context._lastPoint);
angle = point.angleBetween(context._lastPoint);
amount = (100 / context.size) / (Math.pow(distance, 2) + 1);
context._inkAmount += amount;
context._inkAmount = Math.max(context._inkAmount - distance / 10, 0);
if (context._inkAmount > context._dripThreshold) {
context._drips.push(new fabric.Drip(context.canvas.contextTop, point, context._inkAmount / 2, context.color, context._strokeId));
context._inkAmount = 0;
}
x = context._lastPoint.x + Math.sin(angle) - context.size / 2;
y = context._lastPoint.y + Math.cos(angle) - context.size / 2;
context.canvas.contextTop.drawImage(context.brush._element, x, y, context.size, context.size);
if (context.canvas._isCurrentlyDrawing) {
setTimeout(draw, context._interval);
} else {
context._reset();
}
}
},
_reset: function() {
this._drips.length = 0;
this._point = null;
this._lastPoint = null;
}
});
Now, we just need to use this brush in the canvas.
var canvas = new fabric.Canvas('canvas');
canvas.freeDrawingBrush = new fabric.SprayBrush(canvas, { width: 70,opacity: 0.6, color: "transparent" });
In my QML file I have gradient defined as below:
ColorizedRoundedButton
{
gradient: Gradient
{
GradientStop { position: 0.0; color: "#3f5c43" }
GradientStop { position: 0.33; color: "#113d14" }
GradientStop { position: 0.66; color: "#023105" }
GradientStop { position: 1.0; color: "#056508" }
}
}
So here I want this gradient value to be applied through Stylesheet i.e exactly setting this value from C++.
I have the Style.h file like this:
#include <QLinearGradient>
Q_DECLARE_METATYPE(QLinearGradient)
class Style: public QObject
{
Q_PROPERTY(QLinearGradient PositiveGradient READ getPositiveGradient WRITE setPositiveGradient)
QLinearGradient _positiveGradient;
QLinearGradient getPositiveGradient();
void setPositiveGradient(QLinearGradient p_grad);
}
With this approach of using the QLinearGradient type as Q_PROPERTY and changing the QML file to:
gradient: style.PositiveGradient
This approach didnt work, I am getting the runtime error as cannot assign QLinearGradient to QQuickGradient*.
Anybody knows the solution for this or any better solution to pass the gradient values between c++ and QML ?
Declare Class:
class Style: public QObject
{
Q_OBJECT
public:
explicit Style(QObject *parent = nullptr)
{}
public slots:
QStringList stops()
{
QLinearGradient gradeint(0, 0, 1, 100);
gradeint.setColorAt(0, "red");
gradeint.setColorAt(1, "black");
QStringList colors;
for (const auto &g : gradeint.stops())
{
colors.append(g.second.name());
}
return colors;
}
};
After you wrote this class register it in main and write in qml:
Rectangle {
id: root
gradient: Gradient {
id:gradient
}
Component
{
id:stopComponent
GradientStop {}
}
Component.onCompleted:
{
var stops = Style.stops()
var stopsList = [];
var length = stops.length;
for (let i = 0; i < length; i++) {
var s1 = stopComponent.createObject(root, {"position": i / length , "color": stops[i]});
stopsList.push(s1)
}
gradient.stops = stopsList
}
}
I'm working with Chart.js and I'm wondering if there's a way when you click on part of a pie chart, it filters the bar chart.
Since this is a Chart.js question :-), this is how you do it Chart.js (and it's not too complex either)
Setting up the Pie Chart
// pie
var data = [
{
value: 300,
color: "#F7464A",
highlight: "#FF5A5E",
label: "Red",
subData: [28, 48, 40, 19, 86, 27, 190]
}, {
value: 50,
color: "#46BFBD",
highlight: "#5AD3D1",
label: "Green",
subData: [90, 28, 48, 40, 19, 86, 127]
}, {
value: 100,
color: "#FDB45C",
highlight: "#FFC870",
label: "Yellow",
subData: [28, 48, 40, 19, 86, 27, 190]
}
]
var canvas = document.getElementById("chart");
var ctx = canvas.getContext("2d");
var myPieChart = new Chart(ctx).Pie(data);
Setting up the Bar Chart using Pie Data
// bar using pie's sub data
var bardata = {
labels: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
datasets: [
{
label: "My Second dataset",
fillColor: "rgba(151,187,205,0.5)",
strokeColor: "rgba(151,187,205,0.8)",
highlightFill: "rgba(151,187,205,0.75)",
highlightStroke: "rgba(151,187,205,1)",
data: data[0].subData.map(function (point, i) {
var pointTotal = 0;
data.forEach(function (point) {
pointTotal += point.subData[i]
})
return pointTotal;
})
}
]
};
var subcanvas = document.getElementById("subchart")
var subctx = subcanvas.getContext("2d");
var myBarChart = new Chart(subctx).Bar(bardata);
Updating Bar data when Clicking Pie
// connect them both
canvas.onclick = function (evt) {
var activeSector = myPieChart.getSegmentsAtEvent(evt);
myBarChart.datasets[0].bars.forEach(function (bar, i) {
var pointTotal = 0;
data.forEach(function (point, j) {
if (activeSector.length === 0 || point.label === activeSector[0].label)
pointTotal += data[j].subData[i]
})
bar.value = pointTotal;
});
myBarChart.update();
};
Clicking outside the pie (but in the pie chart's canvas) resets the bar chart.
Fiddle - http://jsfiddle.net/0zwkjv8a/
Other answers posted already cover what I would generally advise here which is to use dc-js if you want crossfilter enabled charts out of the gate. I would have commented on this answer, but I don't have enough reputation so I'm posting this as option 'c.)' where 'a.)' is using dc-js and 'b.)' is making some modifications to an existing Chart.js chart.
Option 'c.)' is to extend the Chart.js chart type and make the child chart work like a dc-js chart. Chart.js chart types follow an inheritance hierarchy, so if you like a chart that already exists you can wrap its prototype methods with some of your own. Additionally important to this option, in the selected answer to the stack overflow question with heading 'dc.js - Listening for chart group render', it is described how the current implementation of dc-js's chartRegistry object is fairly decoupled from d3 or dc internals, so any chart implementing chartRegistry's interface can be part of a chartGroup.
I was in the position of wanting very much to use Polar Area Charts in a dataset where I was already using a chart group full of dc-js charts to crossfilter the data. I wrote an extension for Polar Area charts that could serve as an example of one way (I'm going to go ahead and say probably not the best way) to extend a chart type with dc-js like behaviors. The repo for this is at https://github.com/nsubordin81/Chart.dc.js, Licensed under an MIT License, and in case that ever goes anywhere, all of the code is copied into the example fiddle: http://jsfiddle.net/nsubordin81/3w725o3c/1/
Chart.dc.js v. 0.1.0
MIT Licensed: opensource.org/licenses/MIT
Copyright (c) 2015 Taylor Bird
(function () {
"use strict";
var root = this,
Chart = root.Chart,
dc = root.dc,
helpers = Chart.helpers,
//class for data structure that manages filters as they relate to chart segments. This should probably be generalized to chart elements of all kinds.
FilterManager = function (segmentList) {
//private member variable
var filterMap = [];
//constructor
//accepts a list of SegmentArcs that have had the extra properties added to them
for (var i = 0; i < segmentList.length; i++) {
add(segmentList[i].segmentID);
}
//private methods
function testOnAll(test) {
var testResult = true;
for (var i = 0; i < filterMap.length; i++) {
//one failure of test means testOnAll fails
if (!test(filterMap[i])) {
testResult = false;
}
}
return testResult;
}
//add a filter, pretty much just a wrapper for push
function add(segmentID) {
filterMap.push({
"segmentID": segmentID,
"active": false
});
}
//remove a filter by id, returns removed filter
function remove(segmentID) {
var removed = filterMap.find(segmentID);
filterMap = filterMap.filter(function (elem) {
return elem.segmentID !== segmentID;
});
return removed;
}
//return this segment if it is filtered
function find(segmentID) {
for (var i = 0; i < filterMap.length; i++) {
if (filterMap[i].segmentID === segmentID) {
return filterMap[i];
}
}
return -1;
}
//public methods
return {
//tell me if the filter for this segment is active
isActive: function (segmentID) {
var filter = find(segmentID);
if (filter === -1) {
console.error("something went wrong, the filter for this segment does not exist");
}
return filter.active;
},
//for the given segment, activate or deactivate its filter. return whether the filter is on or off.
flip: function (segmentID) {
var filter = find(segmentID);
if (filter === -1) {
console.error("something went wrong, the filter for this segment does not exist");
}
filter.active ? filter.active = false : filter.active = true;
return filter.active;
},
//if all filters are on, we want to be able to quickly deactivate them all
turnAllOff: function () {
for (var i = 0; i < filterMap.length; i++) {
filterMap[i].active = false;
}
},
//tell me if all of the filters are off
allOff: function () {
return testOnAll(function (elem) {
return !elem.active;
});
},
//tell me if all the filters are on
allOn: function () {
return testOnAll(function (elem) {
return elem.active;
});
}
}
};
//utility function, Takes an array that has some property as its key
//and forms a javascript object with the keys as properties so we can get O(1) access
function createKeyMap(arr, propName) {
var keyMap = {}
for (var i = 0; i < arr.length; i++) {
keyMap[arr[i][propName]] = arr[i];
}
return keyMap;
}
Chart.types.PolarArea.extend({
name: "PolarAreaXF",
//this will have to be a member
dimension: undefined,
colorTypes: {
"NORMAL": 0,
"HIGHLIGHT": 1,
"FILTER": 2,
"FILTER_HIGHLIGHT": 3
},
chartGroup: undefined,
filters: undefined,
originalDataKeys: undefined,
initialize: function (data) {
//--PRE--
var that = this;
//Polar Area initialize method is expecting (data, options) in arguments,
//but we pass in an array of components to merge. Let's clean this up.
var argsArray = Array.prototype.slice.call(arguments);
//remove the first element of arguments which is our array, then we do a bunch of Chartjs converison on it . . .
argsArray.splice(0, 1);
//TODO - check if data is an array, if not, put a message in a console explaining how you are supposed to send data in an array
this.dimension = data.dimension;
data.chartGroup ? this.chartGroup = data.chartGroup : this.chartGroup = 0;
//short but magical line. Now we are linked with all dc charts in this group!
dc.registerChart(this, this.chartGroup);
var data = this.setupChartData(data.colors, data.highlights, data.labels);
//... and push the result in its place.
argsArray.unshift(data);
//originalDataArray -- this is used as a reference to the original state of the chart, since segments can come and go,
//we use this to track what a segment's original colors were when adding it back in. This would mess up adding a truly new segment, but who
//is gonna do that? Assumption here is dimensions start with so many groups and that is it.
this.originalDataKeys = createKeyMap(data, "key");
//parent's initialize
Chart.types.PolarArea.prototype.initialize.apply(this, argsArray);
//--modify SegmentArcs--
//assign colors and ids to all existing segment arcs
var mySegments = this.segments;
for (var i = 0; i < mySegments.length; i++) {
mySegments[i].colorList = [undefined, undefined, "#777", "#aaa"];
mySegments[i].colorList[this.colorTypes.NORMAL] = mySegments[i].fillColor;
mySegments[i].colorList[this.colorTypes.HIGHLIGHT] = mySegments[i].highlight;
mySegments[i].segmentID = i;
mySegments[i].key = data[i].key;
}
//add methods to SegmentArc objects that will color them one way or the other depending on their filter
this.SegmentArc.prototype.setIncluded = function (include) {
if (include) {
this.fillColor = this.colorList[that.colorTypes.NORMAL];
this.highlight = this.colorList[that.colorTypes.HIGHLIGHT];
} else {
this.fillColor = this.colorList[that.colorTypes.FILTER];
this.highlight = this.colorList[that.colorTypes.FILTER_HIGHLIGHT];
}
}
//--initialize filters--
this.filters = new FilterManager(this.segments);
//handle clicks on segments as filter events, do the styling and crossfilter changes at the Chart level in the filter method.
helpers.bindEvents(this, ["mousedown"], function (evt) {
var activeSegment = Chart.types.PolarArea.prototype.getSegmentsAtEvent.apply(this, [evt])[0];
this.handleFilter(activeSegment);
});
},
//convert crossfilter dimension into chart.js Polar Area data object array
setupChartData: function (colors, highlights, labels) {
var chartJSible = [];
//probably need checks here to make sure client actually passed in a crossfilter dimension
var grouped = this.dimension.group().reduceCount().top(Infinity);
//probably need checks here to either fail if the arrays aren't all long enough or have some way to add random colors/highlights if they are shorter.
for (var i = 0; i < grouped.length; i++) {
var dataObject = {
value: grouped[i].value,
key: grouped[i].key,
color: colors[i],
highlight: highlights[i],
label: labels ? (labels[i] ? labels[i] : grouped[i].key) : grouped[i].key
};
chartJSible.push(dataObject);
}
return chartJSible;
},
//figure out what changed between Chart.js' internally maintained data object array and crossfilter's dimension data. use the saved information
//about what colors and highlight a key has to rebuild the segmentArc list 'segments'. can't trash the old, it might mess up the animations.
redraw: function () {
var grouped = this.dimension.group().reduceCount().top(Infinity);
var currentSegmentKeys = createKeyMap(this.segments, "key");
var crossfilterGroupKeys = createKeyMap(grouped, "key");
//loop through the segment list, if the segment for a group is already there, update the value, if it is not there, add it back using the
//original data as a guide for what it's color and highlight color should be. if there are segments in the existing list
var length = Math.max(this.segments.length, grouped.length);
//going through both lists, whichever is longer
for (var i = 0; i < length; i++) {
var sList = this.segments;
var gList = grouped;
//only do this part if we still have items in the new filtered list
if (gList[i]) {
//we already have a segment for this crossfilter group, just get that segment and update its value
if (currentSegmentKeys[gList[i].key]) {
currentSegmentKeys[gList[i].key].value = gList[i].value;
} else {
//the chart doesn't have the crossfilter group item, add a new segment with the right colors and values from original data
var theSegment = this.originalDataKeys[gList[i].key];
this.addData(theSegment, 0, true);
}
}
//only do this part if we still have items in the current chart segment list
if (sList[i]) {
//we don't have this segment in the new crossfilter group, remove it from the chart
if (!crossfilterGroupKeys[sList[i].key]) {
this.removeData(i);
}
}
}
this.update();
},
filterAll: function () {
this.dimension.filterAll();
this.filters.turnAllOff();
this.colorMeIn();
this.redraw();
},
handleFilter: function (clicked) {
//after we have all of the filters figured out, change the colors to reflect what they should be and update the chart
this.filters.flip(clicked.segmentID);
this.colorMeIn();
if (this.filters.allOn()) {
this.dimension = this.dimension.filterAll();
dc.redrawAll(this.chartGroup);
this.filters.turnAllOff();
}
dc.redrawAll(this.chartGroup);
},
colorMeIn() {
var activeFilters = [];
var segments = this.segments;
for (var i = 0; i < segments.length; i++) {
var segment = segments[i];
if (this.filters.isActive(segment.segmentID) || this.filters.allOff()) {
segment.setIncluded(true);
activeFilters.push(segment.key);
} else {
segment.setIncluded(false);
}
}
this.dimension = this.dimension.filterFunction(function (d) {
for (var i = 0; i < activeFilters.length; i++) {
if (d === activeFilters[i]) {
return true;
}
}
return false;
});
}
})
}).call(this);
Use dc.js: https://dc-js.github.io/dc.js/
It has exactly the functionality asked for.
Hi,
i have a european raphael map.Now I would like to plot points on
certain cities in the map.i tried by converting latitude n longitude
to plot points in it.But unfortunately it is plotting somewhere
else.is it like we should have world map to plot points??here is my
code.
script type="text/javascript" charset="utf-8">
$(document).ready(function() {
var rsr = Raphael('map', '631', '686');
var attr = {
fill: "#C0C0C0",
stroke: "#666",
"stroke-width": 1,
"stroke-linejoin": "round"
};
var world = {};
world.Portugal = rsr.path("56,0.133-1.32,0.527c-0.661,1.321-0.264,2.906- 0.925,4.228c-0.528,1.057-3.698,5.415-3.434,6.868c0.132,0.526,1.056-0.529,1.584-0.529c0.792-0.132,1.585,0.133,2.377,0c0.396,0,0.792-0.396,1.188-0.264
c2.113,0.527,8.981,5.019,9.906,4.887c0.396,0,4.49-1.981,4.754-2.113C57.876,621.536,58.537,621.536,59.197,621.536L59.197,621.536
z").attr(attr);
world.Spain = rsr.path(" M194.57,552.728c0.924,0.396,1.981,0.63.434,4.754c-,0,0.792,0 c0.661,0.133,1.453,0.133,1.849,0.528c0.66,0.528,0.264,1.717,0.924,2.113v0.132C190.74,552.066,190.476,553.916,194.57,552.728
L194.57,552.728z").attr(attr);
var current = null;
for(var country in world) {
(function (st, country) {
country = country.toLowerCase();
st[0].style.cursor = "pointer";
st[0].onmouseover = function () {
st.animate({fill:"#808080", stroke: "#ccc"}, 500);
};
st[0].onmouseout = function () {
st.animate({fill: "#C0C0C0", stroke: "#666"}, 500);
st.toFront();
R.safari();
};
st[0].onclick = function () {
st.toFront();
st.animate({
fill: '#808080',
transform: 's1.5 '
}, 1000);
};
})(world[country], country);
}
});
var cities = {};//here i define the cities with lat n long but both draws in thesame point all time
cities.rome = plot(55.70466,13.19101,1);
cities.copenhagen = plot(55.676097,12.568337,1);
var city_attr = {
fill:"#FF7F50",
stroke:"#666",
opacity: .3
};
function plot(lat,lon,size) {
size = size * .5 + 4;
return rsr.circle(lon2x(lon),lat2y(lat),size).attr(city_attr);
}
function lon2x(lon) {
var xfactor = 1.5255;
var xoffset = 263.58;
var x = (lon * xfactor) + xoffset;
return x; } function lat2y(lat) {
var yfactor = -1.5255;
var yoffset = 130.5;
var y = (lat * yfactor) + yoffset;
return y; }
});
var myMarker = rsr.ellipse(513.859,35.333, 7, 7).attr({
stroke: "none",
opacity: .7,
fill: "#f00"
});
The coordinates in which the map is coded seem rather arbitrary. If that is so, there is no [easy] way to determine the mapping automatically. I would suggest taking a bounding box of the vector image in it's own coordinate system and a corresponding bounding box in lat/long coordinates on a regular map and deriving the mapping from that, at least as a first approximation.
. I am very new to raphael.js.I have done a europe map using t.I'm
able to change color while mouseover.But I just want to zoom the
particular country while t s clicked.It must be like zoom t the
clicked country with some specific points n the country
script type="text/javascript" charset="utf-8">
$(document).ready(function() {
var rsr = Raphael('map', '631', '686');
var attr = {
fill: "#C0C0C0",
stroke: "#666",
"stroke-width": 1,
"stroke-linejoin": "round"
};
var world = {};
world.Portugal = rsr.path("56,0.133-1.32,0.527c-0.661,1.321-0.264,2.906-0.925,4.228c-0.528,1.057-3.698,5.415-3.434,6.868
c0.132,0.526,1.056-0.529,1.584-0.529c0.792-0.132,1.585,0.133,2.377,0c0.396,0,0.792-0.396,1.188-0.264
c2.113,0.527,8.981,5.019,9.906,4.887c0.396,0,4.49-1.981,4.754-2.113C57.876,621.536,58.537,621.536,59.197,621.536L59.197,621.536
z").attr(attr);;
world.Spain = rsr.path(" M194.57,552.728c0.924,0.396,1.981,0.63.434,4.754c-,0,0.792,0
c0.661,0.133,1.453,0.133,1.849,0.528c0.66,0.528,0.264,1.717,0.924,2.113v0.132C190.74,552.066,190.476,553.916,194.57,552.728
L194.57,552.728z").attr(attr);
var current = null;
for(var country in world) {
(function (st, country) {
country = country.toLowerCase();
st[0].style.cursor = "pointer";
st[0].onmouseover = function () {
st.animate({fill:"#808080", stroke: "#ccc"}, 500);
};
st[0].onmouseout = function () {
st.animate({fill: "#C0C0C0", stroke: "#666"}, 500);
st.toFront();
R.safari();
};
st[0].onclick = function () {
st.animate({width: "500px"}, 'slow');//THS DOES NOT WORk
};
})(world[country], country);
}
});
can anyone help me how to do ths???please
..
You are trying to set the 'width' attribute which the path, in fact, does not possess. The way to go is to set the 'transform' attribute as here. You might also have to set the scaling origin, since the path you are scaling is not centered at zero (cf. Raphael center of scale in transform method).