I'd like to set an image of a map - or, better yet, a generated map - on the x-z plane of a high-charts graph. Is there a way to do this with background image? I understand you can set the color of the back, bottom, and side frame, is there any way to set images for those frames?
You can use SVG <pattern> element with <image> added inside of it, and set the chart.options3d.frame.bottom.color equal to this pattern, just like that:
First you need to create new pattern basing on current dimensions of mentioned frame. The best place to implement it, should be the chart.events.load function:
chart: {
events: {
load() {
var chart = this
var frameBottomDim = chart.frameShapes.bottom.element.getBBox()
var defs = document.querySelectorAll('defs')[0]
var pattern = chart.renderer.createElement('pattern')
var img = chart.renderer.createElement('image')
pattern.attr({
"patternUnits": "userSpaceOnUse",
"x": frameBottomDim.x,
"y": frameBottomDim.y,
"width": frameBottomDim.width,
"height": frameBottomDim.height,
"id": "frameBg",
})
img.attr({
"href": "https://static.makeuseof.com/wp-content/uploads/2010/03/clouds-1-670x335.jpg",
"width": frameBottomDim.width,
"height": frameBottomDim.height,
preserveAspectRatio: 'none'
})
img.add(pattern)
pattern.add(this.renderer.defs)
}
}
}
Then set the frame color property to url(#[pattern_name]):
options3d: {
enabled: true,
alpha: 10,
beta: 20,
depth: 400,
frame: {
bottom: {
color: 'url(#frameBg)'
}
}
}
Live example: https://jsfiddle.net/h8tv4xpg/
Web API Reference: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/pattern
Related
I have create map using javascript Amcharts functions. this is my code -
var recentlyLegend = {"id":"recentlyLegendDiv","width":155,"maxColumns":1,"backgroundAlpha":0,"left":0,"top":350,"horizontalGap":10,"switchable":true,"switchType":"x","markerSize":16,"fontSize":10,"data": recentlyWorldLegendData};
$scope.regionByCountryGeoMap = function(chart){
var source = worldLevelProcessImages(chart.data, recentlyWorldDataProvider, recentlyLegendColorArray);
AmCharts.theme = AmCharts.themes.dark;
recentlyMap = new AmCharts.AmMap();
recentlyMap.mouseWheelZoomEnabled = true;
recentlyMap.zoomControl = {
panControlEnabled: false,
zoomControlEnabled: true,
top: 60,
left: 15,
gridHeight: 100,
iconSize:9,
gridBackgroundAlpha: 0
};
recentlyMap.responsive = {
enabled: true
};
recentlyMap.areasSettings = {color: "#D8DDDF", selectable: true, selectedColor: "#436BFF", outlineColor: "#fff", outlineThickness:
0.5};
recentlyMap.imagesSettings.balloonText = "<div align='left' style='font-size:10px;'>[[title]]</div>";
recentlyMap.imagesSettings.bringForwardOnHover = false;
recentlyMap.legend = recentlyLegend;
recentlyMap.hiddenLegendItems = {};
recentlyMap.addListener('init', function () {
recentlyMap.preventDragOut = true;
recentlyMap.legend.switchable = true;
recentlyMap.legend.addListener('clickMarker', recentlyHandleLegendClick);
recentlyMap.legend.addListener('clickLabel', recentlyHandleLegendClick);
});
recentlyMap.addListener("rendered", function () {
recentlyMap.initialZoomLatitude = recentlyMap.zoomLatitude();
recentlyMap.initialZoomLongitude = recentlyMap.zoomLongitude();
});
recentlyMap.dataProvider = source;
recentlyMap.addListener("clickMapObject", handleMapObjectClick);
recentlyMap.export = {
enabled: true,
position: "bottom-right"
};
recentlyMap.write(chart.chartId);
}
Map has been rendered properly but legends only appears on window resize and its also not taking custom css for legends
Can anyone give solution for this?
After writing the chart to html, try to call validate data and validate size methods.
i.e After
recentlyMap.write(chart.chartId);
this line write the following
recentlyMap.validateData();
recentlyMap.validateSize();
I have used this methods over normal map.I'm not sure about map
I solved this problem in my own amMap, which was also failing to show the legend until the browser resized. The solution was setting additional values in the configuration for my responsive plugin (you're using this plugin too).
The issue relates to the sizing of the map - the responsive plugin will automatically attempt to hide components of the legend bit by bit as the map shrinks and eventually, the entire legend will get hidden as the size of the map becomes smaller than amMap's default responsive breakpoints.
In your configuration, instead of this:
"responsive": {
"enabled": true
},
// ... rest of conf here ...
Try this:
"responsive": {
"enabled": true,
"rules": [
{
"minHeight": 0,
"overrides": {
"legend": {
"enabled": true
}
}
}
]
},
// ... rest of conf here ...
This says: "if the map is taller than 0px tall (which it should always be if you're setting your own width and height styles), show the legend.".
I'm not sure what's going on under the hood in amMaps when you don't provide a rules array but it seems like it applies it's own rules for you if you don't provide them yourself.
Here's a good knowledgebase article explaining the responsive plugin:
https://www.amcharts.com/kbase/making-charts-responsive/
I am building an app in Rails, and I am using a gem called easy_as_pie which enables me to use this Jquery plugin called 'Easy Pie Chart' (http://rendro.github.io/easy-pie-chart/)
I have the pie chart working no problem, using the following code:
$(document).ready(function() {
$('.chart').easyPieChart({
size: 300,
animate: 1400,
lineWidth: 150,
lineCap: "butt",
scaleColor: false,
trackColor: "black",
barColor: "white"
});
});
The question I have, is whether not it would be possible to have the chart load a background image instead of a solid colour. In the documentation it allows you to use a gradient with a function, using the following code:
new EasyPieChart(element, {
barColor: function(percent) {
var ctx = this.renderer.ctx();
var canvas = this.renderer.canvas();
var gradient = ctx.createLinearGradient(0,0,canvas.width,0);
gradient.addColorStop(0, "#ffe57e");
gradient.addColorStop(1, "#de5900");
return gradient;
}
});
I was hoping to get the gradient working, then work on trying to manipulate the function to load in an image. But I have been unsuccessful in even getting the gradient to work.
Provided your gradient example works like it looks, you should be able to draw just about anything you want into the canvas object they've provided. With that in mind, you might be able to draw images like so:
new EasyPieChart(element, {
barColor: function(percent) {
var ctx = this.renderer.ctx();
var canvas = this.renderer.canvas();
var yourImage = new Image();
yourImage.src = "path-to-your-img.jpg";
return ctx.drawImage(yourImage);
}
});
However, Image objects, like <img> tags, require a further GET request to the server to actually load them, so the above probably won't actually work (sorry for the tease). Instead, you'll have to wait for that image to load before calling it, for example:
// Instantiate the image, it's blank here.
var yourImage = new Image();
// Add a callback that uses the fully-loaded img
yourImage.onload = function() {
new EasyPieChart(element, {
barColor: function(percent) {
var ctx = this.renderer.ctx();
var canvas = this.renderer.canvas();
return ctx.drawImage(yourImage);
}
});
};
// Set the src, that queues it for the actual GET request.
yourImage.src = "path-to-your-img.jpg";
I'm getting to grips with SVG.js
I have a pattern effect that I've created and would like to use in a number of SVG's.
I can create it in one SVG with the following code...
$( document ).ready(function() {
var draw = SVG('geo').size(1200, 1700);
// 100 lines of js creating geometric pattern, effectively this...
var rect = draw.polygon(coordinates).fill('#fff').stroke({ width: 1, color:'#fff'}).opacity(0)
});
This creates an SVG with ID geo. But I'd like to use this code again to generate various SVG's, ideally with different options (colour etc).
SVG('geo') refers to a particular SVG, how do I make it so I can apply this to any SVG I want on the page?
Hope that made sense
You can define a function that does this repeatedly. Something like the following:
function create_svg(dom_id, width, height, coord) {
var draw = SVG(dom_id).size(width, height);
var rect = draw.polygon(coord)
.fill('#fff')
.stroke({
width: 1,
color: '#fff'
})
.opacity(0);
}
$(function() {
create_svg('geo', 1200, 1700, coordinates);
create_svg('geo2', 1000, 1500, other_coordinates);
)};
If you need to use the created SVGs further, later on in the code, you could make the create_svg function return the created SVG object to a variable in your document.ready function.
I'm trying to put an image inside a circle but no success. This is my code:
//Elms.raphael() is my stage.
var circle = Elms.raphael().circle( 730, 200, 0 );
circle.attr( { fill : 'url(myImg.jpg)' } );
setTimeout( function()
{
circle.animate( { 'stroke' : '#000', r : 90, 'stroke-width' : '5' }, 300 );
}, 250 );
Instead of put the image in the circle It get colored with black ("#333"). I also tried to make an image-object but still doesn't work.
A little help please?
Another way to do, if you have separate image and want to bring it over you circle object.
This makes the whole image appear with smaller size that fits you circle. DEMO
var r = new Raphael(10,10, 500, 500);
var c = r.circle(200, 200, 80).attr({stroke: 'red', "stroke-width" : 3});
var img = r.image("http://www.eatyourcareer.com/wp-content/uploads/2012/06/ok-256x2561.png", 100, 105, 200, 200);
Here's a link to how I created a circle with an image in it:
jsfiddle
var paper = Raphael(document.getElementById("test"), 320, 200);
var circle = paper.circle(100, 100, 50);
circle.attr({
fill: 'url(http://upload.wikimedia.org/wikipedia/commons/thumb/b/b6/SIPI_Jelly_Beans_4.1.07.tiff/lossy-page1-220px-SIPI_Jelly_Beans_4.1.07.tiff.jpg)'
});
I left the animate out entirely to keep it as basic as I could. It seems to work fine and is very similar to your code. If you cannot see it in the example it may be a browser issue.
I'm trying to implement this awesome map, but I can't figure out how to scale it. Changing the size of the container div or the height/width values just crops the underlying map. I think I need paper.scaleAll(.5) in here somewhere, but can't figure it out. Thanks!
<script>
window.onload = function () {
var R = Raphael("container", 1000, 900),
attr = {
"fill": "#d3d3d3",
"stroke": "#fff",
"stroke-opacity": "1",
"stroke-linejoin": "round",
"stroke-miterlimit": "4",
"stroke-width": "0.75",
"stroke-dasharray": "none"
},
usRaphael = {};
//Draw Map and store Raphael paths
for (var state in usMap) {
usRaphael[state] = R.path(usMap[state]).attr(attr);
}
//Do Work on Map
for (var state in usRaphael) {
usRaphael[state].color = Raphael.getColor();
(function (st, state) {
st[0].style.cursor = "pointer";
st[0].onmouseover = function () {
st.animate({fill: st.color}, 500);
st.toFront();
R.safari();
};
st[0].onmouseout = function () {
st.animate({fill: "#d3d3d3"}, 500);
st.toFront();
R.safari();
};
})(usRaphael[state], state);
}
};
</script>
The other answer is almost correct, but you have to set the anchor point of the scale command to 0,0 so that each state is scaled from the same point:
element.transform("s2,2 0,0");
While you're at it, I'd make an R.set() element and add each state to it, so that you can apply the scale just to the states in the event that you add other objects, like a legend, that you do not want to scale:
usRaphael = {},
states = R.set();
//Draw Map and store Raphael paths
for (var state in usMap) {
usRaphael[state] = R.path(usMap[state]).attr(attr);
states.push(usRaphael[state]);
}
Then at the end:
states.transform("s2,2 0,0");
jsFiddle
After you draw the map (outside of your for loops) try the following:
R.forEach(function(element) {
element.transform("s2");
});
I'm not sure what version of Raphael you are using, but my code is assuming the latest. What this does is it iterates over every path on the paper and sets the transform to "scale 2". This will scale all of the paths by 2.