Insert image on top of VueJS Google Charts - image

I'm trying to adapt the nice solution I found here:
How to place an icon inside Google ColumnChart
to insert images on top of chart bars.
I'm using VueJS to dynamically create my Google charts.
HTML Code :
<GChart type="BarChart" id="villesChart" ref="villesChart" :data="dataprox" :options="optionsprox" :events="eventsprox">
then I populate my chart in my VueJS app:
var result_a = [
[
"Ville",
"Prix au m2",
{ role: "annotation" },
{ role: "style" },
{ role: "code_commune" },
],
];
/*data from sql query*/
for (var ligne in reponse) {
result_a.push([
reponse[ligne].ville,
parseInt(reponse[ligne].prix),
reponse[ligne].prix + " €/m2",
"color: " + couleur,
reponse[ligne].code_commune,
]);
}
The proposed solution to insert icons is the following (extract):
var container = document.getElementById('chart_div');
var containerBounds = container.getBoundingClientRect();
var chart = new google.visualization.ColumnChart(container);
google.visualization.events.addListener(chart, 'ready', function () {
var chartLayout = chart.getChartLayoutInterface();
for (var i = 0; i < data.getNumberOfRows(); i++) {
var barBounds = chartLayout.getBoundingBox('bar#0#' + i);
var path = 'http://findicons.com/files/icons/512/star_wars/32/';
var thumb = container.appendChild(document.createElement('img'));
thumb.src = path + data.getProperty(i, 0, 'thumb');
thumb.style.position = 'absolute';
thumb.style.top = (barBounds.top + containerBounds.top - 40) + 'px';
thumb.style.left = (barBounds.left + containerBounds.left + (barBounds.width / 2) - 16) + 'px';
}
});
chart.draw(data, options);
How do I adapt that code in VueJS context? I don't know how to get the chart element and where I should insert my code (mounted?).
Thanks a lot for your help!
Alex

Related

How to trigger the change event of Kendo Jquery Spreadsheet when using custom Paste function?

I tried the below custom paste function to paste only values but it doesn't trigger the change event in order for me to sync the data to the data source.
Dojo Demo Link
...
change: onExcelChange,
paste: function(e) {
e.preventDefault()
var currentRange = e.range;
var fullData = e.clipboardContent.data;
var mergedCells = e.clipboardContent.mergedCells;
var topLeft = currentRange.topLeft();
var initialRow = topLeft.row;
var initialCol = topLeft.col;
var origRef = e.clipboardContent.origRef;
var numberOfRows = origRef.bottomRight.row - origRef.topLeft.row + 1;
var numberOfCols = origRef.bottomRight.col - origRef.topLeft.col + 1;
var spread = e.sender;
var sheet = spread.activeSheet();
var rangeToPaste = sheet.range(initialRow, initialCol, numberOfRows, numberOfCols);
sheet.batch(function() {
for(var i = 0; i < fullData.length; i += 1) {
var currentFullData = fullData[i];
for(var j = 0; j < currentFullData.length; j += 1 ) {
var range = sheet.range(initialRow + i, initialCol + j);
var value = currentFullData[j].value;
if (value !== null) {
range.input(value);
range.format(null);
}
}
}
sheet.select(rangeToPaste);
}, { layout: true, recalc: true });
} ...
I have tried to use recalc: true in sheet.batch to trigger the change to no avail. Any help would be greatly appreciated.
All Kendo widgets inherit from Observable, which has a trigger method:
var obj = new kendo.Observable();
obj.bind("myevent", function(e) {
console.log(e.data); // outputs "data"
});
obj.trigger("myevent", { data: "data" });
You need to manually trigger the Spreadheet's change event with its correct parameters.

zoom issue in dagre-d3 when use with vuejs2 with watch mode

I am using d3-dagre to render the data. Initially i can render the data without any problem. When i try to update the same view in watch mode, it is updating the data but still some error is thrown in the console for "g" attribute transformation. Whenever i try to rewrite the SVG elements i am removing the "g" element inside the "svg" tag. I am trying this in vuejs2 ui library.
watch: {
workflowDetails: function (changes) {
console.log('Update component ==> ' + changes)
this.workflowName = changes.label
this.workflowDetails = changes
this.metricGraph = false
this.drawDAGView()
}
},
mounted () {
this.drawDAGView()
},
methods: {
getJobid: function (nodeId) {
console.log('Function to get graph api' + nodeId)
this.metricGraph = true
},
drawDAGView: function (isUpdate) {
/* eslint-disable */
d3.selectAll('svg > g').remove()
// Create a new directed graph
var g = new dagreD3.graphlib.Graph().setGraph({})
var DagNodes = this.workflowDetails.nodes
var fillColor
// Add states to the graph, set labels, and style
Object.keys(DagNodes).forEach(function(key) {
console.log("Nodes - "+ DagNodes[key].name)
var value = DagNodes[key]
value.label = DagNodes[key].name + " (" + DagNodes[key].exec_time + ")"
value.rx = value.ry = 5
g.setNode(DagNodes[key].name, value)
})
var DagEdges = this.workflowDetails.edges;
// Add states to the graph, set labels, and style
Object.keys(DagEdges).forEach(function(key) {
g.setEdge(DagEdges[key].startEdge, DagEdges[key].endEdge, { label: ""} )
})
// Create the renderer
var render = new dagreD3.render()
// Set up an SVG group so that we can translate the final graph.
var svg = d3.select("svg"),
inner = svg.append("g")
// Set up zoom support
var zoom = d3.behavior.zoom().on("zoom", function() {
inner.attr("transform", "translate(" + d3.event.translate + ")" +
"scale(" + d3.event.scale + ")")
})
svg.call(zoom)
// Simple function to style the tooltip for the given node.
var styleTooltip = function(name, description) {
return "<p class='name'>" + name + "</p><p class='description'>" + description + "</p>"
}
// Run the renderer. This is what draws the final graph.
render(inner, g)
inner.selectAll("g.node")
.attr("title", function(v) {
return styleTooltip(v, "Execution Time: "+g.node(v).label + " <br /> Description: "+g.node(v).label)
})
//.each(function(v) { $(this).tipsy({ gravity: "w", opacity: 1, html: true }) })
var self = this
inner.selectAll("g.node")
.on("click", function(v) {
console.log("Nodes --> "+ v + " -- "+ g.node(v).node_id)
// whatever
//window.location = "../dag/"+g.node(v).job_id
self.nodeId = g.node(v).node_id
console.log("Node id -- "+ self.nodeId)
self.getJobid(self.nodeId)
})
// Center the graph
var initialScale = 1.2
zoom
.translate([(svg.attr("width") - g.graph().width * initialScale) / 50, 20])
.scale(initialScale)
.event(svg)
svg.attr('height', g.graph().height * initialScale + 40)
svg.attr('width', "100%")
}
Error - Due to this below error newly loaded data not able to zoom
Error: <g> attribute transform: Expected number, "translate(NaN,20)
Have you tried removing the svg? After removing the svg you can add the new Graph.

Ckeditor scrollbar marker / Text Position Indicator

I would like to implement scrollbar marker into ckeditor and i can't seem to find the right way to do it i have triyed this code
var win = new CKEDITOR.dom.window( window );
var pos = win.getScrollPosition();
console.log(pos);
but it only return the google chrome scrollbar x=0 & Y=0
var win = new CKEDITOR.dom.window( domWindow );
var pos = win.getScrollPosition();
console.log(pos);
and this give me an error domWindow is not defined
i found this example it may help: https://codepen.io/Rplus/pen/mEjWJm
(() => {
var containerQS = '.article';
var container = document.querySelector(containerQS);
var form = document.querySelector('.form');
var input = form.querySelector('input[type="text"]');
var markClass = 'mark';
var markerHeight = '2px';
var _color = 'currentColor';
var containerY = container.offsetTop;
var containerH = container.scrollHeight;
var customStyle = document.createElement('style');
container.appendChild(customStyle);
var renderScrollMarker = ($parent, posArr) => {
var _posArr = posArr.map(i => {
return `transparent ${i}, ${_color} ${i}, ${_color} calc(${i} +
${markerHeight}), transparent calc(${i} + ${markerHeight})`;
});
customStyle.innerHTML = `article::-webkit-scrollbar-track {
background-image: linear-gradient(${_posArr.join()});
}`;
};
var calcEleRelativePos = ($ele) => {
return ($ele.offsetTop - containerY) / containerH;
};
var markOpt = {
className: markClass,
done: function () {
var marks = document.querySelectorAll(`.${markClass}`);
var allY = [].map.call(marks, (mark) => {
return (calcEleRelativePos(mark) * 100).toFixed(2) + '%';
});
renderScrollMarker(container, allY);
console.log(allY);
}
};
var instance = new Mark(container);
form.addEventListener('submit', (e) => {
e.preventDefault();
var _text = input.value.trim();
console.log(_text, form.oldText);
if (_text === '') {
instance.unmark(markOpt);
return;
}
form.oldText = _text;
instance.unmark().mark(_text, markOpt);
});
// trigger
form.querySelector('input[type="submit"]').click();
})();
but as ckeditor secures a lot of element, i would love to know if any one has done this before with CKeditor
i just got the real editor scrollbar position, i only need to put a marker using style or any availble methode
var win=CKEDITOR.instances.editor1.document.getWindow();
var pos = win.getScrollPosition().y;
console.log(pos);
this worked for me :
var jqDocument = $(editor.document.$);
var documentHeight = jqDocument.height();
var scrollTo =jqDocument.scrollTop();
var docHeight = jqDocument.height();
var scrollPercent = (scroll)/(docHeight);
var scrollPercentRounded = Math.round(scrollPercent*100);
$(".ui-slider-handle").css("bottom", 100-scrollPercentRounded+"%");

jquery plugin pass variable inside config settings

I would like to pass an array in my plugin defaults config settings. I am trying to give the user, the option to add as many title and src variable as they like for instance:
desktop_xl: {
"title":"beach",
"src":"http://images.smh.com.au/2013/02/25/4061249/art-Whitehaven-Beach-620x349.jpg"
},
{
"title":"sunset",
"src":"https://lh5.googleusercontent.com/-Oh0HlfM31BQ/TlXHejUNpeI/AAAAAAAABiI/tQbJJEGEOnU/s400/red_sunset_beach.jpg"
}
I have seen this question on stack overflow but could not find an answer that works for me.
I did some reading and figured out that I can create an array of objects, it works well only on my index.html page as per the below fiddle, http://jsfiddle.net/michelm/7gS6g/2/
The issue is that I would like to use this array as a config option in my plugin so users can add as many title and src variables as they need, but the array does not work inside the plugin.
When I did console.log(desktop_xl); on my index.html page, it shows as an object.
I read the documentation at http://api.jquery.com/jquery.extend/ and from what I understand I need to merge my objects to pass them as a config option, here is the link to my plugin from my drop box account (js fiddle did not take the https link for some reasons), please see below link to jquery.myplugin.js (random name for now, but will use unique naming convention once I work out the logic):
https://www.dropbox.com/s/boadofib6nggfzp/jquery.myplugin.js
Can anyone help me figure out how to pass this variable in my config option so users can add as many "title" and "src" from the option desktop_xl please?
UPDATE:
I have figured out how to pull array information and append it to my images, however, I still have no idea on how to "link" this to the plugin option settings as I need to give the user the option to add as many images with title as they would like in the option settings.
Here is how I have figured out how to pull data from array:
//create img desktop_xl loop
$.each(desktop_xl, function( index , value ){
$('#container').append(
$("<img />").attr({
id: value.title,
src: value.src,
title: value.title
})
);
});
UPDATE 2:
I have done some more work on the plugin, here is the code so far:
;(function($, window, document, undefined){
//define MyjQueryPlugin object with default config settings:
$.MyjQueryPlugin = {
defaults: {
imagecontainer: "#container",
version: "v01"
// add my Arrays to default options here?
// arrays should allow users to add as many images to #container div as they require
// arrays are desktop_xl[] , desktop_l[] , ipad_p[] , mobile_l[], mobile_p[]
}
};
//extend jquery with the plugin
$.fn.extend({
MyjQueryPlugin:function(config) {
//use defaults or properties supplied by user
var config = $.extend({}, $.MyjQueryPlugin.defaults, config );
//append slides
$(config.imagecontainer).append('<div class="imagecontainerfordesktop_xlarray" </div>').css('height', $(window).height() );
// append MyjQueryPlugin sidebar
this.append( '<div id="Mysidebar" class="open">' +
'<p class="review">Version ' + config.version + '- ready for review</p>'+
'<hr>' +
'</div>')
.children()
.css('height', $(window).height() );
//create array of objects
var desktop_xl = [
{
"title":"Homepage", // text for sidebar
"src":"slides/1200/Homepage.jpg"// path to image >= 1200px wide
},
{
"title":"Categories", // text for sidebar
"src":"slides/1200/Categories.jpg"// path to image >= 1200px wide
},
{
"title":"Product description", // text for sidebar
"src":"slides/1200/Product_description.jpg" // path to image >= 1200px wide
}
];
var desktop_l = [
// if array is empty, remove elements from the page
];
var ipad_p = [
{
"title":"Homepage", // text for sidebar
"src":"slides/480/Homepage.jpg" // path to image >= 480px wide
}
];
var mobile_l = [];
var mobile_p = [];
// set Global Variables
var width = $(window).width();
var currHeight = $(window).height();
var ctrl = $(".ctrl");
var ulscreenlia = $('ul.screen li a');
var sidebarlia = $('#MyjQueryPluginsidebar li a');
var sidebar = $("#MyjQueryPluginsidebar");
var ulscreenli = $('ul.screen li');
if (desktop_xl.length === 0) {
ulscreenli.eq(0).hide();
$('div.select_join option[value="xld"]').remove();
}
if (desktop_l.length === 0) {
ulscreenli.eq(1).hide();
$('div.select_join option[value="ld"]').remove();
}
if (ipad_p.length === 0) {
ulscreenli.eq(2).hide();
$('div.select_join option[value="ip"]').remove();
}
if (mobile_l.length === 0) {
ulscreenli.eq(3).hide();
$('div.select_join option[value="ml"]').remove();
}
if (mobile_p.length === 0) {
ulscreenli.eq(4).hide();
$('div.select_join option[value="mp"]').remove();
}
//create img desktop_xl loop
$.each(desktop_xl, function( index , value ){
$('#container .slides-xld').append(
//getting values from array but cannot understand how to pass array(s): desktop_xl, desktop_l, ipad_p, mobile_l, mobile_p inside config option
//And Each arrays should allow user to add multiple images to #container dive
$("<img />").attr({
id: value.title,
src: value.src,
title: value.title
})
);
});
//create img ipadp loop
$.each(ipad_p, function( index , value){
$('#container .slides-ipadp').append(
$("<img />").attr({
id: value.title,
src: value.src,
title: value.title
})
);
});
function rundateobject(){
var current_date = new Date ( );
var month_names = new Array ( );
month_names[month_names.length] = "January";
month_names[month_names.length] = "February";
month_names[month_names.length] = "March";
month_names[month_names.length] = "April";
month_names[month_names.length] = "May";
month_names[month_names.length] = "June";
month_names[month_names.length] = "July";
month_names[month_names.length] = "August";
month_names[month_names.length] = "September";
month_names[month_names.length] = "October";
month_names[month_names.length] = "November";
month_names[month_names.length] = "December";
var day_names = new Array ( );
day_names[day_names.length] = "Sunday";
day_names[day_names.length] = "Monday";
day_names[day_names.length] = "Tuesday";
day_names[day_names.length] = "Wednesday";
day_names[day_names.length] = "Thursday";
day_names[day_names.length] = "Friday";
day_names[day_names.length] = "Saturday";
$('#date').html( day_names[current_date.getDay()]
+ ', '
+ month_names[current_date.getMonth()]
+ ' '
+ current_date.getDate()
+ ' '
+ current_date.getFullYear() );
};
//create animation for anchor links with jQuery DOM ready function
$(function(){
$('a').hover(function(){
$(this).animate({
'margin-left':10,
'padding-left':20
},200);
$(this).dequeue();
},
function() {
$(this).animate({
'margin-left':0,
'padding-left':15
},200);
$(this).dequeue();
}
);
});
//on resize browser, adjust elements height
//initialise plugins
$(".nano").nanoScroller();
//initialise functions
rundateobject();
//return the jquery object for chaining
return this;
}// config options
}); // jQuery extend
})(jQuery, window, document);
The answer was given to me on jquery.com by user kbwood.au
defaults: {
imagecontainer: "#container",
version: "v01",
desktop_xl: [] //Array
}
Then in the .each function we need to pass the array as a config.desktop_xl:
//create img desktop_xl loop
$.each(config.desktop_xl, function( index , value ){
$('#container').append(
$("<img />").attr({
id: value.title,
src: value.src,
title: value.title
})
);
});

titanium mobile:get row value from tableview on button click issue

Hello friends,
I am developing an app using Google Place API in Titanium Development and successfully got data and display in tableview and add button in each row but my issue is that I want to get name and address on button click in each row so please give me idea or any link to solve my issue.
Please take a look in my screenshot so on btnclick I want to get name and address.
Thanks in advance.
var categoryName;
var addressLabel;
var row;
var tableData=[];
PlacesListCells = function createRow()
{
//var tableData=[];
var loader = Titanium.Network.createHTTPClient();
var url = "https://maps.googleapis.com/maps/api/place/search/json?";
url = url + "location=" + lat + ',' + lon;
url = url + "&radius=" + radius;
url = url + "&name=" + name;
url = url + "&sensor=" + sensor;
url = url + "&key=" + key;
Ti.API.info(url);
// Sets the HTTP request method, and the URL to get data from
loader.open("GET",url);
// Create our HTTP Client and name it "loader"
// Runs the function when the data is ready for us to process
loader.onload = function()
{
var obj = JSON.parse(this.responseText);
Ti.API.log(obj);
var results = obj.results;
Ti.API.log(results);
for (var i = 0; i < results.length; i++)
{
categoryName = obj.results[i].name;
reference = obj.results[i].reference;
Ti.API.log('Refernce:'+reference);
// Create a row and set its height to auto
row = Titanium.UI.createTableViewRow({height:'78'});
var placeImage = Titanium.UI.createImageView
({
image:'../iphone/appicon.png',
width:70,
height:50,
top:12,
left:5
});
// Create the label to hold the tweet message
var nameLabel = Titanium.UI.createLabel({
//text:name,
left:80,
top:5,
height:'auto',
width:185,
textAlign:'left',
font:{fontSize:12}
});
// Create the label to hold the tweet message
addressLabel = Titanium.UI.createLabel({
left:80,
top:25,
height:'auto',
width:185,
textAlign:'left',
font:{fontSize:14}
});
var arrowImage = Ti.UI.createImageView
({
image:'../iphone/appicon.png',
width:20,
height:20,
left:280,
top:30
});
var favoriteButton = Ti.UI.createButton
({
title:'btn',
//font:{fontFamily:'Helvetica Neue',fontSize:15},
top:20,
left:255,
height:30,
width:50,
url:'../Images/favorite.png'
//image:'../Images/favorite.png'
});
nameLabel.text = categoryName;
getDetailsData(addressLabel,row,i);
row.add(placeImage);
row.add(nameLabel);
row.add(addressLabel);
row.add(favoriteButton);
//row.add(arrowImage);
tableData[i] = row;
//set page title for each row
row.pageTitle = nameLabel.text;
favoriteButton.row = i;
favoriteButton.addEventListener('click', function(e)
{
Ti.API.log('favoriteButton clicked on row ' + e.source.row +' at ' + new Date().getSeconds());
alert('favoriteButton clicked on row ' + e.source.row);
var index = e.source.row;
var name = tableData[index];
alert('name'+name);
});
}
tableView.setData(tableData);
};
//-- Network error
loader.onerror = function(e)
{
Ti.API.info('Network error: ' + JSON.stringify(e));
};
// Send the HTTP request
loader.send();
return tableData;
};
Once you have your index, you should be able to reference your original data source by that.
var favoriteButton = Ti.UI.createButton({
title:'btn',
//font:{fontFamily:'Helvetica Neue',fontSize:15},
top:20,
left:255,
height:30,
width:50,
url:'../Images/favorite.png'
//image:'../Images/favorite.png',
name:categoryName,
address:address;//address mention here
});
row.add(favoriteButton);
favoriteButton.addEventListener('click', function(e)
{
var index = e.source.row;
var name = e.source.name;
var address = e.source.address;
alert('name'+name);
});
}
I think this might help you a lot.

Resources