p:barChart y axis format - charts

I use primefaces 4.0 barchart, but i want to modify some default proprieties. This is my xhtml page
<p:barChart id="chart" value="#{marchebean.model}" legendPosition="ne" xaxisLabel="Année" yaxisLabel="Montant en DT" title="Factures payés par années" />
What i want to do
1.I want to separate between hundreds , thousands and millions in y axis by a space i.e changing the format of my numbers , i use NumberFormat.getNumberInstance(Locale.FRANCE).format(mynumber); in java but i don't know how to achieve this with charts in primefaces.
I want to display on the top of every bar the value setted in backing bean and change it's size.
Edit
Separation between thousand done, but i still don't know how display values above every bar or change their size. this is my new code
<p:barChart id="chart" value="#{marchebean.model}" extender="ext" style="height:600px;" legendPosition="ne" xaxisLabel="Année" yaxisLabel="Montant en DT" title="Factures payés par années" />
<script type="text/javascript">
function ext() {
this.cfg.axes.yaxis.tickOptions = {
formatString: "%'i"
};
this.cfg.seriesDefaults={
renderer: $.jqplot.BarRenderer,
pointLabels:{show:true}
},
$.jqplot.sprintf.thousandsSeparator = ' ';
}
</script>

First question
You can fulfill your need #1 using an extender.
Here's the related excerpt from Primefaces' manual regarding extenders:
3.14.15 Extender Chart API provide high level access to commonly used jqplot options however there are many more customization options
available in jqplot. Extender feature provide access to low level apis
to do advanced customization by enhancing the configuration object,
here is an example to increase shadow depth of the line series where
model's extender property is set to "ext".
<p:chart type="line" model="#{bean.model}" />
function ext() {
//this = chart widget instance
//this.cfg = options
this.cfg.seriesDefaults = {
shadowDepth: 5
};
}
Refer to jqPlot docs for available options.
Note: in Primefaces 4.0, the extender function name is provided as an attribute of the component tag, eg. <p:barChart extender="ext" .../>
To use whitespaces as thousands separator, use the following extender:
function ext() {
this.cfg.axes.yaxis.tickOptions = {
formatString: "%'i"
};
$.jqplot.sprintf.thousandsSeparator = ' ';
}
Second question
You will also manage to do it making some tweaking in your extender.
For example, the following piece of configuration will display values above every bar:
seriesDefaults: {
renderer: $.jqplot.BarRenderer,
pointLabels:{show:true}
},
And just use some CSS to change the size!
--
Zim

Related

Common tile layer settings for multiple vue2-leaflet maps

In my Vue (2.x) application, I have a number of places where I use vue2-leaflet maps.
There are a few common features of these maps, but they are otherwise completely different, so it doesn't make sense to have all of them use a single component that contains an <l-map> (and all other relevant map components).
In order to reduce copying an pasting, I have created a few mixins with common features. For example, I have written a mixin for any maps that need to be able to auto-fit to their contents, so the only thing I need to do in each component that uses it is add :bounds="autofitBounds" to the <l-map> component.
I wanted to do create something similar for the <l-tile-layer> component, because all of our maps use the same layers.
I created a mixin that provides the url and attribution for the tile layer like this:
export default {
data () {
return {
url: process.env.VUE_APP_MAP_TILE_URL || 'https://{s}.tile.osm.org/{z}/{x}/{y}.png',
attribution: process.env.VUE_APP_MAP_TILE_COPYRIGHT || '© OpenStreetMap contributors',
};
},
};
I can use it by adding the mixin to my component and then adding the <l-tile-layer> component inside the <l-map> like this:
<l-tile-layer :url="url" :attribution="attribution" />
I wanted to see if there was a way to reduce the boilerplate further.
First, I tried to create it as a component instead, like this:
<template>
<l-tile-layer :url="url" :attribution="attribution" />
</template>
<script>
import { LTileLayer } from 'vue2-leaflet';
export default {
name: 'MyTileLayer',
components: {
LTileLayer,
},
data () {
return {
url: process.env.VUE_APP_MAP_TILE_URL || 'https://{s}.tile.osm.org/{z}/{x}/{y}.png',
attribution: process.env.VUE_APP_MAP_TILE_COPYRIGHT || '© OpenStreetMap contributors',
};
},
};
</script>
Then I can use that component inside my <l-map> without needing to add any attributes to it, like this:
<my-tile-layer>
The problem is that this doesn't render properly. Here are two screenshots - the <l-tile-layer> used directly on the left, and the <my-tile-layer> wrapper on the right.
Is there a better way to create a tile layer component with default values? Or is there a way I can fix the rendering of <my-tile-layer>?

Is there a way/workaround to have the slot principle in hyperHTML without using Shadow DOM?

I like the simplicity of hyperHtml and lit-html that use 'Tagged Template Literals' to only update the 'variable parts' of the template. Simple javascript and no need for virtual DOM code and the recommended immutable state.
I would like to try using custom elements with hyperHtml as simple as possible
with support of the <slot/> principle in the templates, but without Shadow DOM. If I understand it right, slots are only possible with Shadow DOM?
Is there a way or workaround to have the <slot/> principle in hyperHTML without using Shadow DOM?
<my-popup>
<h1>Title</h1>
<my-button>Close<my-button>
</my-popup>
Although there are benefits, some reasons I prefer not to use Shadow DOM:
I want to see if I can convert my existing SPA: all required CSS styling lives now in SASS files and is compiled to 1 CSS file. Using global CSS inside Shadow DOM components is not easily possible and I prefer not to unravel the SASS (now)
Shadow DOM has some performance cost
I don't want the large Shadow DOM polyfill to have slots (webcomponents-lite.js: 84KB - unminified)
Let me start describing what are slots and what problem these solve.
Just Parked Data
Having slots in your layout is the HTML attempt to let you park some data within the layout, and address it later on through JavaScript.
You don't even need Shadow DOM to use slots, you just need a template with named slots that will put values in place.
<user-data>
<img src="..." slot="avatar">
<span slot="nick-name">...</span>
<span slot="full-name">...</span>
</user-data>
Can you spot the difference between that component and the following JavaScript ?
const userData = {
avatar: '...',
nickName: '...',
fullName: '...'
};
In other words, with a function like the following one we can already convert slots into useful data addressed by properties.
function slotsAsData(parent) {
const data = {};
parent.querySelectorAll('[slot]').forEach(el => {
// convert 'nick-name' into 'nickName' for easy JS access
// set the *DOM node* as data property value
data[el.getAttribute('slot').replace(
/-(\w)/g,
($0, $1) => $1.toUpperCase())
] = el; // <- this is a DOM node, not a string ;-)
});
return data;
}
Slots as hyperHTML interpolations
Now that we have a way to address slots, all we need is a way to place these inside our layout.
Theoretically, we don't need Custom Elements to make it possible.
document.querySelectorAll('user-data').forEach(el => {
// retrieve slots as data
const data = slotsAsData(el);
// place data within a more complex template
hyperHTML.bind(el)`
<div class="user">
<div class="avatar">
${data.avatar}
</div>
${data.nickName}
${data.fullName}
</div>`;
});
However, if we'd like to use Shadow DOM to keep styles and node safe from undesired page / 3rd parts pollution, we can do it as shown in this Code Pen example based on Custom Elements.
As you can see, the only needed API is the attachShadow one and there is a super lightweight polyfill for just that that weights 1.6K min-zipped.
Last, but not least, you could use slots inside hyperHTML template literals and let the browser do the transformation, but that would need heavier polyfills and I would not recommend it in production, specially when there are better and lighter alternatives as shown in here.
I hope this answer helped you.
I have a similar approach, i created a base element (from HyperElement) that check the children elements inside a custom element in the constructor, if the element doesn't have a slot attribute im just sending them to default slot
import hyperHTML from 'hyperhtml/esm';
class HbsBase extends HyperElement {
constructor(self) {
self = super(self);
self._checkSlots();
}
_checkSlots() {
const slots = this.children;
this.slots = {
default: []
};
if (slots.length > 0) {
[...slots].map((slot) => {
const to = slot.getAttribute ? slot.getAttribute('slot') : null;
if (!to) {
this.slots.default.push(slot);
} else {
this.slots[to] = slot;
}
})
}
}
}
custom element, im using a custom rollup plugin to load the templates
import template from './customElement.hyper.html';
class CustomElement extends HbsBase {
render() {
template(this.html, this, hyperHTML);
}
}
Then on the template customElement.hyper.html
<div>
${model.slots.body}
</div>
Using the element
<custom-element>
<div slot="body">
<div class="row">
<div class="col-sm-6">
<label for="" class="">Name</label>
<p>
${model.firstName} ${model.middleInitial} ${model.lastName}
</p>
</div>
</div>
...
</div>
</custom-element>
Slots without shadow dom are supported by multiple utilities and frameworks.
Stencil enables using without shadow DOM enabled. slotted-element gives support without framework.

Identifying pushpins after plotting them - Bingmaps

I am currently working with Bing maps version 8 . I was previously working with version 7 . When plotting pushpins in version 7 a htmlContent attribute was sent along with the pushpins. What this html content did was that the pushpin was contained inside the div element .
var pushpinOptions = {
htmlContent: "<div id='container" + siteIndex + "'style='pointer-events: all !important; z-index: 35000; '></div><div id='lines"+siteIndex+"'></div>",
anchor:new Microsoft.Maps.Point(iconWidth/2,iconHeight/2),
width: iconWidth,
height: iconHeight
};
var pin = new Microsoft.Maps.Pushpin(latLon, pushpinOptions);
I used Konva JS to plot over these pushpins which i plotted with BingMaps.
var stage = new Konva.Stage({
container: 'container' + siteIndex,
width: width,
height: height,
stroke: 'green'
});
'container' + siteIndex, was the id of the div i set in bing maps pushpins which i used in konva to plot another image over the pushpins. This is my requirement . I have to plot a pushpin with coordinates and then plot some images over the pushpins . Now when i shifted from v7 to v8 for various reasons, I am facing an issue .
In v8 htmlContent is not sent with the pushpins, rather we send an svg image which has no way to identify after being plotted other than co-ordinates .
var customHtml = '<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50"><circle id="myCircle htmlId" cx="25" cy="25" r="20" stroke="orange" stroke-width="4" fill="yellow" /></svg>';
var pin = new Microsoft.Maps.Pushpin(latLon, {
icon: customHtml.replace("htmlId",siteIndex.toString()),
anchor: new Microsoft.Maps.Point(iconWidth/2,iconHeight/2)
});
Now , what i am lokking for is a way to either plot images with a third party api which plots over co-ordinates or find to way to get access of the pushpins i plotted without the html content i.e with svg images. When i access the id with
document.getElementById("myCircle 0");
i get null.
I have looked for many different third party apis like leafleat js, konva js , Graphics js. But i do not find a way to identify my pushpins .
Is there a way to achieve what i wish to? There must be.
HTML pushpins are not supported in Bing Maps V8 as they can't be drawn on an HTML5 canvas. Using SVG would render on the Canvas but there is no DOM element create, which is why you aren't able to use document.getElementById. Using DOM elements with maps really limits performance and is the main reason why rendering is now done with an HTML5 canvas. That said, even in V7 using the approach of custom HTML in general so you can do document.getElementById to retrieve the pushpins was not a good approach. If you want to assign a unique ID to each pushpin and then be able to retrieve it, you should use a custom JavaScript property, or the existing metadata property. For example:
var pin = new Microsoft.Maps.Pushpin(map.getCenter());
pin.metadata = {
id: 'myCircle 0'
};
map.entities.push(pin);
function getPushpinById(id){
var pin;
for(var i=0,len = map.entities.getLength(), i<len;i++){
pin = map.entities.get(i);
if(pin.metadata && pin.metadata.id === id){
return pin;
}
}
}
Using this approach would allow the greatest performance in your app. However, if you really want to use custom HTML to create pushpins, it is possible to achieve this in V8 by using a custom overlay. Here is a code sample: https://msdn.microsoft.com/en-US/library/mt762877.aspx

Get selection Number from GWT Highcharts

I have areacharts with 2 series. Each of both has the same data, but different values. When I select one of the point, I want to know index of point. For example. when I select first point, I want take "1" and so on. Like here.
For instance they used
formatter: function() {
return 'point ' + this.point.myIndex;
}
but it is for javascript
formatter: function() {
return 'point ' + this.point.myIndex;
}
Does anybody know how to do it from gwt wrapper Moxie Apps GWT Highcharts?

jqPlot- issue with displaying bar charts -axis padding and inter-bar distance

I'm using the following piece of code to display a set of bar charts in jqPlot. However, I am getting 2 problems:
There is no padding on either side of the range values for the xaxis. The pad attribute seems to have no effect.
When the number of bars is large, the bars overlap on top of each other. The barPadding attribute seems to have no effect.
I looked at this link Having problems with jqPlot bar chart . The answer suggested there was to use a CategoryAxisRenderer. But since I'm using time-series data, I require the DateAxisRenderer.
Please help.
function plotBarGraph(data,myticks,series)
{
$("#placeholder").empty();
$.jqplot('placeholder',data,
{
//stackSeries:true,
seriesDefaults:{
renderer:$.jqplot.BarRenderer,
barMargin:1,
barPadding:0.5
},
axes:
{
xaxis:
{
ticks:myticks,
tickInterval:10,
renderer:$.jqplot.DateAxisRenderer,
pad:2.5,
tickOptions:
{
formatString:'%d-%m-%y'
}
}
},
legend:
{
show:true,
labels:series
}
});
}
In this case if you do not want to use the approach mentioned in the link, you might want to play with min/max values for your date axis.
I think you might also find useful the approach to a similar sort of problem with padding where I chose to set ticks on creation and hide the unwanted ones after the plot is drawn.
Before I can be of any further assistance please provide a sample presenting your problem.
For your second problem, I ran into a similar issue. I set up a selection statement that widened the size of my chart depending on how many bars would be in it. I then made the parent div scrollable (called "dataHolder"), and that solved the problem.
// set div properties depending on how many sets of data are in the
//array so the view is sized properly
$("#chartDiv").html("").css("width", "750px"); // chartDiv's default settings
$("#tabs-6").removeClass("dataHolder").css("width", "900px"); // parent Div's default settings
if (dataArray.length > 10) {
$("#chartDiv").css("width", "1600px");
$("#tabs-6").addClass("dataHolder").css("width", "900px");
} else if (dataArray.length > 6) {
$("#chartDiv").css("width", "1200px");
$("#tabs-6").addClass("dataHolder").css("width", "900px");
}
I found a solution to use Date data with CategoryAxisRenderer. You have to configure de xaxis like follows:
axes: {
xaxis: {
renderer: $.jqplot.CategoryAxisRenderer,
rendererOptions: {
tickRenderer: $.jqplot.DateTickRenderer,
tickOptions: {
formatter: $.jqplot.DateTickFormatter,
formatString:'%d/%m'
}
}
}
}
I hope it helps! ;)