I have a highcharts graphic, which consists of a static javascript code and a dynamic preformatted HTML text (pre) containing CSV data. (The dynamic text with the CSV data is updated daily, the Javascript code remains unchanged).
Now I would like to add a footnote, e.g. using "caption", which should also be dynamic.
How can I make the footer dynamic?
I had the idea to write the footnote into the CSV data and read it out of there, but I didn't succeed.
The jsfiddle example is here:
https://jsfiddle.net/martindfurrer/r4tjdka9/
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/data.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
<div id="container" style="background: pink; width: 400px; height: 300px"></div>
<!--dynamic csv data from other source-->
<pre id="csv" style="display:none">
"utcdate;"value"
"1";"181"
"2";"225"
"3";"171"
"4";"188"
"5";"246"
"6";"98"
"7";"48"
</pre>
<script type='text/javascript'>
// static javascript code
Highcharts.chart('container', {
title: {
text: 'Corona Virus cases'
},
subtitle: {
text: 'Data input from CSV'
},
data: {
csv: document.getElementById('csv').innerHTML
},
series: [ {
name: 'Infection rate',
type: 'column',
}],
caption: {
text: 'The Javascript code is static, the csv data is dynamic. This text should also be dynamic, i.e. some sort of variable',
}
});
</script>
You can use for example a load event to update the caption with dynamic content:
chart: {
events: {
load: function() {
this.update({
caption: {
text: document.getElementById('dynamicCaption').innerHTML
}
});
}
}
}
Or just use a HTML reference in a text property:
caption: {
text: document.getElementById('dynamicCaption').innerHTML,
}
Live demo: https://jsfiddle.net/BlackLabel/zbkhm41r/
API Reference:
https://api.highcharts.com/highcharts/caption.text
https://api.highcharts.com/class-reference/Highcharts.Chart#update
Related
I have a chat on my website that reads from a JSON file and grabs each message and then displays it using Vue.js. However, my problem is that when a user posts a link, it is not contained in an anchor tag <a href=""/>. Therefore it is not clickable.
I saw this post, and I think something like this would work, however, I am not allowed to add any more dependencies to the site. Would there be a way for me to do something similar to this without adding more dependencies?
Code for displaying the message.
<p v-for="msg in messages">
<em class="plebe">
<b> [ {{msg.platform.toUpperCase()}} ]
<span style="color: red" v-if="msg.isadmin">{{msg.user.toUpperCase()}}</span>
<span style="color: #afd6f8" v-else="">{{msg.user.toUpperCase()}}</span>
</b>
</em>:
{{msg.message}}
</p>
In a situation like this, its preferred to write a custom functional component.
The reason for this is the fact that we are required to emit a complex html structure, but we have to make sure to properly protect against xss attacks (so v-html + http regex is out of the picture)
We are also going to use render functions, because render functions have the advantage to allow for javascript that generates the html, having more freedom.
<!-- chatLine.vue -->
<script>
export default {
functional: true,
render: function (createElement, context) {
// ...
},
props: {
line: {
type: String,
required: true,
},
},
};
</script>
<style>
</style>
We now need to think about how to parse the actual chat message, for this purpose, I'm going to use a regex that splits on any length of whitespace (requiring our chat urls to be surrounded with spaces, or that they are at the start or end of line).
I'm now going to make the code in the following way:
Make a list for child componenets
Use a regex to find url's inside the target string
For every url found, do:
If the match isn't at the start, place the text leading from the previous match/start inside the children
place the url inside the list of children as an <a> tag, with the proper href attribute
At the end, if we still have characters left, at them to the list of children too
return our list wrapped inside a P element
Vue.component('chat-line', {
functional: true,
// To compensate for the lack of an instance,
// we are now provided a 2nd context argument.
// https://vuejs.org/v2/guide/render-function.html#createElement-Arguments
render: function (createElement, context) {
const children = [];
let lastMatchEnd = 0;
// Todo, maybe use a better url regex, this one is made up from my head
const urlRegex = /https?:\/\/([a-zA-Z0-9.-]+(?:\/[a-zA-Z0-9.%:_()+=-]*)*(?:\?[a-zA-Z0-9.%:_+&/()=-]*)?(?:#[a-zA-Z0-9.%:()_+=-]*)?)/g;
const line = context.props.line;
let match;
while(match = urlRegex.exec(line)) {
if(match.index - lastMatchEnd > 0) {
children.push(line.substring(lastMatchEnd, match.index));
}
children.push(createElement('a', {
attrs:{
href: match[0],
}
}, match[1])); // Using capture group 1 instead of 0 to demonstrate that we can alter the text
lastMatchEnd = urlRegex.lastIndex;
}
if(lastMatchEnd < line.length) {
// line.length - lastMatchEnd
children.push(line.substring(lastMatchEnd, line.length));
}
return createElement('p', {class: 'chat-line'}, children)
},
// Props are optional
props: {
line: {
required: true,
type: String,
},
},
});
var app = new Vue({
el: '#app',
data: {
message: 'Hello <script>, visit me at http://stackoverflow.com! Also see http://example.com/?celebrate=true'
},
});
.chat-line {
/* Support enters in our demo, propably not needed in production */
white-space: pre;
}
<script src="https://unpkg.com/vue#2.0.1/dist/vue.js"></script>
<div id="app">
<p>Message:</p>
<textarea v-model="message" style="display: block; min-width: 100%;"></textarea>
<p>Output:</p>
<chat-line :line="message"></chat-line>
</div>
You can watch or write computed method for the variable having url and manupulate it to html content and then use v-html to show html content on the page
v-html
I am using Ckeditor as rich editor for text input in the Chrome browser. I also have added some html id tag for easy parsing by bs4 after the system getting the data.
The following is my setting in the html:
CKEDITOR.replace( 'editor', {
toolbar : 'Basic',
uiColor : '#9AB8F3',
height : '70%',
startupShowBorders: false,
})
And in the config.js:
config.toolbarGroups = [
{ name: 'clipboard', groups: [ 'clipboard', 'undo' ] },
{ name: 'editing', groups: [ 'find', 'selection', 'spellchecker' ] },
{ name: 'links' },
{ name: 'insert' },
{ name: 'forms' },
{ name: 'tools' },
{ name: 'document', groups: [ 'mode', 'document', 'doctools' ] },
{ name: 'others' },
'/',
{ name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] },
{ name: 'paragraph', groups: [ 'list', 'indent', 'blocks', 'align', 'bidi' ] },
{ name: 'styles' },
{ name: 'colors' },
{ name: 'about' }
];
// Remove some buttons provided by the standard plugins, which are
// not needed in the Standard(s) toolbar.
config.removeButtons = 'Underline,Subscript,Superscript';
// Set the most common block elements.
config.format_tags = 'p;h1;h2;h3;pre';
// Simplify the dialog windows.
config.removeDialogTabs = 'image:advanced;link:advanced';
config.allowedContent = True;
};
Although I have already followed the instruction to allow all html tag content to be preserved with config.allowedContent = *; in the config.jd. However, it seems not working as I got the following results when getting data (by CKEDITOR.instances.editor.getData()):
<span style='font-size:11.0pt;'> content </span>
instead of this that I want:
<span id="news_content" style='font-size:11.0pt;'> content </span>
In other words, it still strips out all the html tag I added.
When I checked the source code, I found that the same textarea content was produced twice with the one with the tag being put in hidden format, i.e.,
<textarea name="editor" id="editor" rows="100" cols="40" style="visibility: hidden; display: none;">
And the editor produces another version in the real textarea that allows me to edit. However, this is useless because all the html tags are stripped there.
So, my question is, how to preserve the html tag in the real textarea so that I can parse the html with id tags after editing and submission. Could anyone advise on this? Thanks a lot.
I may not be able to answer my own question, but I like to share my solution with those encountering similar situation.
In short, finally I give up using ckeditor or any plug-in editor as many of them will strip off the html tag, which is essential to me in the subsequent process.
Thanks to html5, my solution is using editable div. The setting is very simple as below:
css:
#my-content {
box-shadow: 0 0 2px #CCC;
min-height: 150px;
overflow: auto;
padding: 1em;
margin: 5px;
resize: vertical;
outline: none;
}
html:
<div id="my-content" class="editable" style="width:900px; height:400px; text-overflow: ellipsis; overflow-y: scroll;"></div>
js script:
$('.editable').each(function(){
this.contentEditable = true;
});
So far, I am happy with it, it shows what exactly the html code showing and preserve all the tags I added. The only downside is it does not provide any toolbar for format editing. My solution is to make one for it, and via the following link you can get a very good tutorial as to making a toolbar with a ready-to-use demo as illustration.
https://code.tutsplus.com/tutorials/create-a-wysiwyg-editor-with-the-contenteditable-attribute--cms-25657
Hope this helps.
is it possible in a TimelineJs instance to load JSON data from a variable in the page?
<div id="timeline-embed"></div>
<script type="text/javascript">
var timeline_config = {
width: "100%",
height: "100%",
source: 'example_json.json'
}
</script>
<script type="text/javascript" src="../compiled/js/storyjs-embed.js"></script>
this is the default code from the timelineJS example.
Basically i'm trying to replace the source: 'example_json.json' with a
source: '{
"timeline":
{
"headline":"Sh*t People Say",
"type":"default",
"text":"People say stuff",
"startDate":"2012,1,26",
"date": [
{
"startDate":"2011,12,12",
"endDate":"2012,1,27",
"headline":"Vine",
"text":"<p>Vine Test</p>",
"asset":
{
"media":"https://vine.co/v/b55LOA1dgJU",
"credit":"",
"caption":""
}
},
{
"startDate":"2012,1,26",
"endDate":"2012,1,27",
"headline":"Sh*t Politicians Say",
"text":"<p>In true political fashion, his character rattles off common jargon heard from people running for office.</p>",
"asset":
{
"media":"http://youtu.be/u4XpeU9erbg",
"credit":"",
"caption":""
}
}
]
}
}'
but it doesn't work
The problem is that you are passing in the JSON object as a string. Remove quotation marks and it should work. Should look like this:
source: {
"timeline": {
...
}
}
I've put together a working example on JSFiddle
Using ExtJs 4.1.
I'm creating a panel (for example) and I would like that the generated html includes one or more "data-" attributes (for example: data-intro="some text" data-step="1")
How can this be done?
After the component has rendered, you could apply the attributes to the top level element representing the component
Example:
var panel = Ext.create('Ext.panel.Panel',{
title: 'Test',
width: 500,
height: 200,
renderTo: Ext.getBody(),
listeners: {
afterrender: function(cmp) {
cmp.getEl().set({
"data-intro": 'some text',
"data-step": 1
});
}
}
});
panel.show();
You can use the autoEl config option to achieve this.
{
xtype: 'panel',
title: 'My Panel',
autoEl: {
tag: 'div',
'data-step': '1'
}
}
I want a dojox.grid.DataGrid with a dojo.data.ItemFileReadStore as the data store. I want it to fill the entire screen. I don't want to specify dimensions in pixels. All the examples that I've seen specify them in pixels or use a CSV data store. I've tried using HTML elements and javascript to setup the datagrid and store.
Has anyone done this? Is there a bug? It seems like what anyone would want, but maybe it's not possible for some reason. Any ideas? Thanks!
Edit to insert code:
<div id="gridContainer" style="width: 100%; height: 100%;"></div>
<div id="gridContainer1" style="width: 400px; height: 200px;"></div>
<script type="text/javascript">
dojo.addOnLoad(function(){
// our test data store for this example:
var jsonStore = new dojo.data.ItemFileReadStore({
url: '/mydata.json'
});
var layout = [{
field: 'id',
name: 'id',
width: '20px'
},
{
field: 'name',
name: 'name',
width: '50px'
},
{
field: 'owner',
name: 'owner',
width: '50px'
}];
// create a new grid:
var grid = new dojox.grid.DataGrid({
query: {
rowid: '*'
},
store: jsonStore,
clientSort: true,
rowSelector: '20px',
structure: layout
},
document.createElement('div'));
dojo.byId("gridContainer1").appendChild(grid.domNode);
grid.startup();
});
</script>
Depending on whether I use gridContainer or gridContainer1, it does not show or shows the grid respectively.
What gives?
Yep - perfectly possible.
1) Page layout is the responsibility of the layout widgets (ContentPane, StackContainer, BorderContainer, TabContainer...) The grid is able to take part in a layout but you should really place it in a contianer that is designed to do layout.
2) Programatic creation can be achieved with:
var layout = [{
name: "MyFirstColumnHeader",
field: 'someColumnNameInMyData',
width: "180px;"
},
{
name: "MySecondColumnHeader",
field: 'someOtherColumnName',
width: "180px;"
}
];
var emptyData = {
identifier: 'uniqueIdOfEachItem',
label: 'displayName',
items: []
};
var store = new dojo.data.ItemFileWriteStore({
data: emptyData
});
var grid = new dojox.grid.DataGrid({
id: 'myGrid',
query: {
uniqueIdOfEachItem: '*'
},
store: store,
structure: layout
}, gridPlaceholder);
grid.startup();
where
MyFirstColumnHeader is the text you would like in the first column header
someColumnInMyData is the object attribute or 'column' in the data to be displayed
gridPlaceholder is a div on the page to put the grid into (just add an empty div to ContentPane and make the style of the ContentPane to be width : 100%, height : 100%
uniqueIdOfEachItem is the property of each displayed item that marks them as unique, e.g. their primary key or ID property
This example creates a read/write store and has a simple layout, but the dojo docs should be able to help with more complex examples.