I'm creating a highchart using the lazy_highcharts gem. I'd like to make use of the afterSetExtremes callback to regenerate some other data on the page on zooming. I've tried several ways, currently trying:
#chart = LazyHighCharts::HighChart.new('graph') do |f|
f.chart(:zoomType =>'x', :defaultSeriesType => 'spline')
f.x_axis(:type=> 'datetime', :events => {:afterSetExtremes => "functon(event){alert('something')}"} )
end
But that gives me the error
Uncaught TypeError: Object functon(event){alert('something')} has no method 'apply'
in the javascript console when I zoom the chart. I assume this has something to do with the generator not correctly setting up the callback function, setting it as a string instead of interpreting it as a function.
I've also tried to set it on my chart object via javascript after creation, but so far have had no luck with that. A few attempts below
chart_my_id4.xAxis.events = {setExtremes: function(event) {
alert('set extremes');
}};
chart_my_id4.xAxis[1].events = {setExtremes: function(event) {
alert('set extremes');
}};
No luck there either.
Any insight appreciated, thank you.
Not too familiar with ... ruby, but I took a look at the source on github and they do the following when they set functions into attributes:
:formatter => "function() { return this.x; }".js_code
It would be worth a try to add that .js_code and see if it works so you end up with:
#chart = LazyHighCharts::HighChart.new('graph') do |f|
f.chart(:zoomType =>'x', :defaultSeriesType => 'spline')
f.x_axis(:type=> 'datetime', :events => {
:afterSetExtremes => "functon(event){alert('something')}".js_code
})
end
I'm not familiar with that gem, but in standard Highcharts 3.0 you can add event in that way:
chart.yAxis[0].update({
events: {
afterSetExtremes: function(){
alert('x');
}
}
});
You can do this like that :
LazyHighCharts::HighChart.new('graph') do |f|
...
f.xAxis(:events => { :afterSetExtremes => after_set_extremes_function})
end
-
def after_set_extremes_function
%|function(e) {
chart = Highcharts.charts[0];
chart.showLoading('Loading data...');
$.getJSON("/path_to_your_action?start="+Math.round(e.min)+"&end="+Math.round(e.max), function(data) {
chart.series[0].setData(data);
chart.hideLoading();
}
}
);
}|.js_code
end
Related
So far everything works in the backend regarding Rails and Paperclip. I have it set up so that when you create a new Post, the image within that post will be uploaded to AWS S3. It works fine on the backend. I am also using Expo's ImagePicker to grab an image from the users camera roll. However, when I'm trying to post something with Axios in React Native using formData in the front end, I'm getting this error:
Paperclip::AdapterRegistry::NoHandlerError - No handler found for
"file:///Users/jimmy/Library/Developer/CoreSimulator/Devices/A3590E6A-
281B-4EFB-868C-9F5311718832/data/Containers/Data/Application/CB5ED945-
AA87-4E36-83B6-71426759C70C/Library/Caches/ExponentExperienceData/%2540anonymous%252Fartis
-ed15f4f4-b8d6-460f-a1b3-e06d546eda2a/ImagePicker/B3162237-9BCD-4721-
BDF2-D66BC047A6C0.jpg"
Here's some more snippets of my code:
React Native Submit handler in the PostForm:
onSubmit() {
const { navigate } = this.props.navigation;
return () => {
const formData = new FormData();
formData.append("post[title]", this.state.title);
formData.append("post[body]", this.state.body);
formData.append("post[user_id]", this.props.currentUser.id);
formData.append("post[image]", this.state.image);
this.props.createPost(formData).then((res) => {
if (res.type) {
navigate("Explore");
}
});
};
}
ImagePicker to get an image uri to display a preview as well as update the image uri in the parent component which is the PostForm:
_pickImage = async () => {
let pickerResult = await ImagePicker.launchImageLibraryAsync({
allowsEditing: true,
aspect: [4, 3],
});
if (pickerResult.cancelled) {
return;
}
this.setState({image: pickerResult.uri});
this.props.updatePostWithImage(pickerResult.uri);
};
Action and API Call:
export const createPost = (post) => dispatch => (
postPost(post).then((res) => {
return dispatch(receivePost(res.data));
}).catch((errors) => {
})
);
const url = "http://localhost:3000";
export const postPost = (post) => {
return axios({
method: 'POST',
url: `${url}/api/posts`,
dataType: "JSON",
contentType: false,
processData: false,
data: post
});
};
Post Controller:
def create
#post = Post.new(post_params)
if #post.save
render :show
else
render json: #post.errors.full_messages, status: 422
end
end
def post_params
params.require(:post).permit(:title, :body, :image, :user_id)
end
Post Model:
class Post < ApplicationRecord
validates :title, :body, presence: true
belongs_to :user
has_attached_file :image, default_url: "https://res.cloudinary.com/jun/image/upload/v1506659435/Doge_sggjpf.jpg"
validates_attachment_content_type :image, content_type: /\Aimage\/.*\z/
end
Parameters that Rails receives with Axios POST request:
Parameters: {"post"=>{"title"=>"Test", "body"=>"Testing", "user_id"=>"1", "image"=>"file:///Users/jimmy/Library/Developer/CoreSimulator/Devices/A3590E6A-281B-4EFB-868C-9F5311718832/data/Containers/Data/Application/CB5ED945-AA87-4E36-83B6-71426759C70C/Library/Caches/ExponentExperienceData/%2540anonymous%252Fartis-ed15f4f4-b8d6-460f-a1b3-e06d546eda2a/ImagePicker/B3162237-9BCD-4721-BDF2-D66BC047A6C0.jpg"}}
I'm not really sure what's going on. The parameters looks fine to me, but I think it might be missing a lot of things that paperclip needs I would assume. But I'm not sure how to get them. I tried searching all over but couldn't find a solution that could help. I'm still fairly new to using some of these technologies, so please bear with me, haha.
If there is any other information I can add in to help debug this issue let me know. Thanks in advance!
Welp, I found the issue and was able to fix it. I was missing additional information that Paperclip required on the back end. The only change I made was on the onSubmit handler function.
onSubmit() {
const { navigate } = this.props.navigation;
return () => {
let uriParts = this.state.image.split('.');
let fileType = uriParts[uriParts.length - 1];
console.log(fileType);
const formData = new FormData();
formData.append("post[title]", this.state.title);
formData.append("post[body]", this.state.body);
formData.append("post[user_id]", this.props.currentUser.id);
formData.append("post[image]", {
uri: this.state.image,
name: `${this.state.title}.${fileType}`,
type: `image/${fileType}`,
});
this.props.createPost(formData).then((res) => {
if (res.type) {
navigate("Explore");
}
});
};
}
Setting the uri, name and file type for the image fixed everything. I can now select an image from the camera roll and successfully create a post using that image, which gets uploaded to AWS S3 using paperclip. :D
I am a complete beginner, so please excuse if this question is maybe phrased incorrectly or I am using the wrong terms for certain things.
I have got an MS Word Document in which there are, say, four-hundred diary entries. The software I want to write enables the user to search for specific terms within one entry. So I might want to have all the diary entries that contain both the words "happy" and "sad". Another option I want to include is to search for all diary entries written between e.g. 2008 and 2012 etc.
I would like the search to be 'dynamic', in the sense that the user might type in one word, and while that word is being typed the results-table already filters all the diary entries. So the table changes while the user is typing the word, according to what is currently being typed in the search box.
Is this possible & what exactly is this feature called? What programming language would you recommend me? I would like to have all of this online, so maybe php or ruby would be useful?
Your choice of Ruby-on-Rails is apt for this issue:
Store each diary entry as a database entry
Search these entries using "full text search" - either on the db, or third party
Return the "live" functionality with JS
MVC
Rails uses MVC programming pattern to give you ability to save into the database. This is important because if you're going to develop in rails, you'll need to keep to the MVC pattern:
Basically, you keep your Diary entries in the database, use the controller to manipulate the data & use the view to show the data:
#app/models/entry.rb
Class Entry < ActiveRecord::Base
#-> stores & brings back the entry data
end
#app/controllers/entries_controller.rb
Class EntriesController < ApplicationController
respond_to :js, :html, :json, only: :search
def index
#entries = Entry.all
end
def search
#entries = Entry.search params[:query]
respond_with #entries
end
end
#config/routes.rb
resources :entries do
collection do
match :search, via [:get, :post]
end
end
--
Full Text Search
When you send the request to your controller, the way you'll handle the search will be with a class method in your Entry model (that's where you get your data from), either referencing -
#app/models/entry.rb
Class Entry < ActiveRecord::Base
def self.search(query)
where("title LIKE '%#{query}%'")
end
end
You can either use full text search for the SQL variant you're using, or use a third party search, like Solr or something
--
"Live" Search
You can get "live" search working with Javascript (example here):
There are a number of tutorials on how to do this online - just Google live search rails or autocomplete rails. However, the principle is basically the same for all implementations:
JS will capture the text entered into a search box
JS sends Ajax request to your Rails controller
Controller sends response to ajax
JS takes response & shows on screen
Notice how this is primarily focused on the JS element? Here's the code we use:
#app/assets/javascripts/application.js
//Livesearch
$(document).ready( function() {
var base_url = window.location.protocol + "//" + window.location.host;
$('#SearchSearch').searchbox({
url: base_url + '/search/',
param: 'search',
dom_id: '#livesearch',
loading_css: '#livesearch_loading'
})
});
#app/assets/javascripts/livesearch.js
// Author: Ryan Heath
// http://rpheath.com
(function($) {
$.searchbox = {}
$.extend(true, $.searchbox, {
settings: {
url: 'search',
param: 'search',
dom_id: '#livesearch',
minChars: 2,
loading_css: '#livesearch_loading',
del_id: '#livesearch_del'
},
loading: function() {
$($.searchbox.settings.loading_css).show()
},
idle: function() {
$($.searchbox.settings.loading_css).hide()
},
start: function() {
$.searchbox.loading()
$(document).trigger('before.searchbox')
},
stop: function() {
$.searchbox.idle()
$(document).trigger('after.searchbox')
},
kill: function() {
$($.searchbox.settings.dom_id).fadeOut(50)
$($.searchbox.settings.dom_id).html('')
$($.searchbox.settings.del_id).fadeOut(100)
},
reset: function() {
$($.searchbox.settings.dom_id).html('')
$($.searchbox.settings.dom_id).fadeOut(50)
$('#SearchSearch').val('')
$($.searchbox.settings.del_id).fadeOut(100)
},
process: function(terms) {
if(/\S/.test(terms)) {
$.ajax({
type: 'GET',
url: $.searchbox.settings.url,
data: {search: terms.trim()},
complete: function(data) {
$($.searchbox.settings.del_id).fadeIn(50)
$($.searchbox.settings.dom_id).html(data.responseText)
if (!$($.searchbox.settings.dom_id).is(':empty')) {
$($.searchbox.settings.dom_id).fadeIn(100)
}
$.searchbox.stop();
}
});
return false;
}else{
$.searchbox.kill();
}
}
});
$.fn.searchbox = function(config) {
var settings = $.extend(true, $.searchbox.settings, config || {})
$(document).trigger('init.searchbox')
$.searchbox.idle()
return this.each(function() {
var $input = $(this)
$input
.keyup(function() {
if ($input.val() != this.previousValue) {
if(/\S/.test($input.val().trim()) && $input.val().trim().length > $.searchbox.settings.minChars){
$.searchbox.start()
$.searchbox.process($input.val())
}else{
$.searchbox.kill()
}
this.previousValue = $input.val()
}
})
})
}
})(jQuery);
So I have a chart which is configured using the MVC style configuration...
#(Html.Kendo().Chart<DIMVC.ViewModel.CompanyProduction>(Model.CompanyProduction)
.Name("Chart")
.Title("Files sent")
.Legend(legend => legend
.Position(ChartLegendPosition.Bottom)
)
.ChartArea(chartArea => chartArea
.Background("transparent")
)
.SeriesDefaults(seriesDefaults =>
seriesDefaults.Line().Style(ChartLineStyle.Smooth)
)
.Series(series => {
series.Line(model => model.SentFiles).Name("Sent Files");
... { lots more series added here }
}
.CategoryAxis(axis => axis
.Categories(model => model.MonthDisplay)
.Labels(labels => labels.Rotation(-90))
)
.ValueAxis(axis => axis.Numeric()
.Labels(labels => labels.Format("{0:N0}"))
.MajorUnit(10000)
)
.Tooltip(tooltip => tooltip
.Visible(true)
.Format("{0:N0}")
)
.Events(e => e
.SeriesClick("onSeriesClick")
)
)
I also have a slider on the page. When the slider value is changed I handle this event.
#(Html.Kendo().RangeSlider()
.Name("yearRange")
.Min(2000)
.Max(DateTime.Today.Year)
.SmallStep(1)
.LargeStep(5)
.Values(Model.MinYear, Model.MaxYear)
.Events(e => e.Change("yearRangeChange"))
)
javascript method
function yearRangeChange(e)
{
var url = "/FetchData/";
$.ajax({
type: "GET",
url: url,
data: { startYear: e.values[0], endYear: e.values[1] },
dataType: "json",
success: function (json) {
$("#DINETChart").kendoChart({
dataSource: {
data: json
}
});
var chart = $("#DINETChart").data("kendoChart");
chart.refresh();
}
});
}
now when the chart is updated the grid is just blank.
The json request is successfully called and the data is retrieved.
but after the chart is populated the chart is blank.
has anyone got any suggestions?
* EDIT *
adding a sample of the JSON returned
"[{\"CompanyID\":1,\"Year\":2011,\"Month\":8,\"SentFiles\":1666,\"ReceivedFiles\":1632,\"SentData\":12803.674593292486,\"ReceivedData\":11908.047586546765,\"Note\":null,\"MonthDisplay\":\"Aug\",\"CompanyDisplay\":null},{\"CompanyID\":1,\"Year\":2013,\"Month\":10,\"SentFiles\":21004,\"ReceivedFiles\":20387,\"SentData\":157376.825542573,\"ReceivedData\":152878.87845794103,\"Note\":null,\"MonthDisplay\":\"Oct\",\"CompanyDisplay\":null},{\"CompanyID\":1,\"Year\":2013,\"Month\":4,\"SentFiles\":9989,\"ReceivedFiles\":9880,\"SentData\":74913.53277995327,\"ReceivedData\":75145.16331588416,\"Note\":null,\"MonthDisplay\":\"Apr\",\"CompanyDisplay\":null},{\"CompanyID\":1,\"Year\":2013,\"Month\":11,\"SentFiles\":25956,\"ReceivedFiles\":25249,\"SentData\":196155.8977337967,\"ReceivedData\":189320.44546897494,\"Note\":null,\"MonthDisplay\":\"Nov\",\"CompanyDisplay\":null}]"
I would also like to point out that if I add this
.DataSource(ds => ds.Read(read =>
read.Action("FetchData", "Home", new { startYear = 2012, endYear = 2013 })
))
to my chart configuration, this will populate the chart fine, without using the page Model.
i.e. The data is correct for the chart.
The data source expects an array as value for its data, but it looks like the json variable you're assigning contains a JSON string (at least if the string you added to the question is what you're seeing on the client in the json var). jQuery should normally parse that for you if you set dataType to "json" (not sure why that is not happening for you - you should double check that the dataType param is set correctly).
You can try parsing it yourself; apart from that, you should also use chart.setDataSource() instead of creating a new chart. They way you're doing it now, you're simply replacing your original chart with its configuration with a chart that has no configuration. Try something like this in your callback:
var data = JSON.parse(json);
var chart = $("#DINETChart").data("kendoChart");
var dataSource = new kendo.data.DataSource({
data: data
});
chart.setDataSource(dataSource);
Note that in your yearRangeChange function, you're trying to call refresh on the chart outside of your ajax success call. You don't need to refresh when you use setDataSource, but even if you needed to do that, it would have to be in the callback. Otherwise it happens before the ajax call completes.
I'm using highcharts 3.0.1 with ruby on rails.
basically i have finally this javascript ( in an ajax/remote request) :
var chart = $('#my_bar_div').highcharts();
chart.xAxis[0].setCategories(["cat1", "cat2", "cat4"]);
chart.series[0].setData([6.0,7.0,8.0]);
ruby version _updatechart.js.erb:
var chart = $('#my_bar_div').highcharts();
chart.xAxis[0].setCategories(<%= #qids.to_s.html_safe %>);
chart.series[0].setData(<%= #average_values.to_json %>);
i'm going back from 6 to 3 categories/rows, I use a vertical column chart:
#bar = LazyHighCharts::HighChart.new('column') do |f|
f.series(:name=>'Punkte',:data=> #average_values )
f.title({ :text=>"Auswertung Fragen " + #theobjects.name })
### Options for Bar
f.options[:chart][:defaultSeriesType] = "bar"
f.plot_options({:series=>{:stacking=>"normal"}, :bar => { :dataLabels => { :enabled => true }}})
f.options[:xAxis] = {:plot_bands => "none", :title=>{:text=>""}, :categories => #qids}
f.options[:yAxis] = {:title => { :text =>'Punkte', :align =>'high'}, :labels => { :overflow => 'justify' } }
end
it resizes the categories, but does not redraw the columns, I tried almost everything without success.
Maybe you got any ideas?
Thanks, Patrick
Fixed example: http://jsfiddle.net/BCRyP/4/
1) "plotBands": "none" -> remove that or use {}
2) Use the same variable's name:
var chart;
$(document).ready(function () {
var chart = new Highcharts.Chart(options);
jQuery("#button").on("click", function () {
chart.xAxis[0].setCategories(["Wie geht es?", "How is your mam?"], true);
chart.series[0].setData([5.5, 6.0], true);
});
});
I'm playing around with FLOT with Ruby and I'm having a hard time passing the code to javascript; I know my javascript isn't reading the data correctly from Ruby. I need some syntax help.
o={};
o= {'label' => "A", 'data' => #example.collect{|x| [Time.utc(x.date).to_i, x.num]}}
render :text => o.to_json
I have successfully rendered the output as such:
{"label":"A","data":[[1281225600,1.31],[1281225600,1.31],[1281225600,1.25]]}
The HTML outputs this data only.
My javascript is as follows:
var obj = jQuery.parseJSON(text);
var options = {
lines: { show: true },
points: { show: true },
xaxis: { mode: "time", timeformat: "%m/%d/%y", minTickSize: [1, "day"]}
};
var data = obj;
$.plot(placeholder,[data],options);
}
What you are missing is that Ruby puts out timestamps in the Unix format (i.e. seconds since the epoch 1281225600). Flot requires javascript timestamps, which count the milliseconds since the epoch, i.e. 1281225600*1000.
So in your Ruby code, your best bet is to do something like this:
o={};
o= {'label' => "A", 'data' => #example.collect{|x| [Time.utc(x.date).to_i*1000, x.num]}}
render :text => o.to_json
Or if you prefer, you could loop over the obj.data and do the multiplication on the Javascript side:
for (i=0;i<obj.data.length;i++){
obj.data[i] = obj.data[i]*1000;
}
Ok I got it....
Ruby code:
#o={};
#o= {'label' => "A", 'data' => #example.collect{|x| [Time.utc(x.date).to_i, x.num]}}
Java code:
$(function () {
var obj = <%= #o.to_json %>;
var options = {
lines: { show: true },
points: { show: true },
xaxis: { mode: "time", timeformat: "%m/%d/%y", minTickSize: [1, "day"]}
};
var data = obj;
$.plot(placeholder,[data],options);
});