From fbf6c417b5f67e5539d7f24c1ab818cdbec9e207 Mon Sep 17 00:00:00 2001 From: axel Date: Fri, 5 Nov 2021 17:34:05 +0100 Subject: [PATCH] dates histogram --- app/controllers/catalog_controller.rb | 11 +- app/javascript/packs/application.js | 1 + .../controllers/dates_histogram_controller.js | 148 ++++++++++++++++++ .../packs/controllers/viewer_controller.js | 9 +- app/javascript/packs/stylesheets/catalog.scss | 8 + app/javascript/packs/utils/search_api.js | 17 ++ app/models/article.rb | 8 +- app/models/issue.rb | 2 +- app/models/solr_query.rb | 5 +- app/views/catalog/_dates_histogram.html.erb | 24 +++ app/views/catalog/_facet.html.erb | 3 +- app/views/catalog/_result.html.erb | 2 +- app/views/catalog/_sidebar.html.erb | 1 + .../catalog/_wide_dates_histogram.html.erb | 33 ++++ config/routes.rb | 1 + package.json | 2 + yarn.lock | 17 ++ 17 files changed, 281 insertions(+), 11 deletions(-) create mode 100644 app/javascript/packs/controllers/dates_histogram_controller.js create mode 100644 app/views/catalog/_dates_histogram.html.erb create mode 100644 app/views/catalog/_wide_dates_histogram.html.erb diff --git a/app/controllers/catalog_controller.rb b/app/controllers/catalog_controller.rb index 6587b3a..3598f9b 100644 --- a/app/controllers/catalog_controller.rb +++ b/app/controllers/catalog_controller.rb @@ -30,6 +30,7 @@ class CatalogController < ApplicationController session['search_params'] = @solr_params session['query_params'] = params.to_unsafe_h.slice('q', 'page', 'per_page','sort', 'f') @results = SolrSearcher.query @solr_params + puts @results.to_json @resulting_docs = @results['response']['docs'].map do |solr_doc| case solr_doc['has_model_ssim'] when ['Article'] @@ -50,10 +51,10 @@ class CatalogController < ApplicationController def show if params[:id].include? "_article_" @article = Article.from_solr params[:id] - @issue = Issue.from_solr @article.issue_id, with_pages: true, with_articles: true + @issue = Issue.from_solr @article.issue_id, with_pages=true, with_articles=true else @article = nil - @issue = Issue.from_solr params[:id], with_pages: true, with_articles: true + @issue = Issue.from_solr params[:id], with_pages=true, with_articles=true end end @@ -103,6 +104,12 @@ class CatalogController < ApplicationController render json: out end + def wide_dates_histogram + out = {} + out[:modal_content] = render_to_string(layout: false, partial: "wide_dates_histogram") + render json: out + end + private def strip_input_fields diff --git a/app/javascript/packs/application.js b/app/javascript/packs/application.js index 2cdba21..c3a9f04 100644 --- a/app/javascript/packs/application.js +++ b/app/javascript/packs/application.js @@ -27,3 +27,4 @@ window.$ = $ window.bootstrap = bootstrap window.Panzoom = require('@panzoom/panzoom') import "./application.scss" +import Chart from 'chart.js/auto' diff --git a/app/javascript/packs/controllers/dates_histogram_controller.js b/app/javascript/packs/controllers/dates_histogram_controller.js new file mode 100644 index 0000000..732e691 --- /dev/null +++ b/app/javascript/packs/controllers/dates_histogram_controller.js @@ -0,0 +1,148 @@ +import { Controller } from "stimulus" +import {SearchAPI} from "../utils/search_api" +import Chart from "chart.js/auto" +import zoomPlugin from 'chartjs-plugin-zoom' + + +export default class extends Controller { + static targets = [] + static values = {years: Object, months: Object} + + wide_chart = null + + connect() { + Chart.register(zoomPlugin) + this.setup_dates_histogram() + this.setup_wide_dates_histogram() + $("#wide_date_histogram").click( event => { + SearchAPI.wideDatesHistogram( data => { + $("#wide_dates_histogram_modal").html(data.modal_content) + let myModal = new bootstrap.Modal(document.getElementById('wide_dates_histogram_modal'), {}) + myModal.toggle() + }) + }) + } + + setup_wide_dates_histogram() { + $("#wide_dates_histogram_modal").on("shown.bs.modal", (e) => { + this.generate_chart(this.yearsValue) + }) + $("body").on('click', "#download_histogram", e => { + const b64data = $("#canvas_wide_dates_histogram")[0].toDataURL() + $("#download_histogram").attr('href', b64data) + }) + $("body").on('click', "#reset_zoom_histogram", (e) => { + this.wide_chart.resetZoom() + }) + $("body").on('change', 'input[name="hist_type_input"]', (e) => { + if(e.target.value == "year") + this.generate_chart(this.yearsValue) + if(e.target.value == "month") + this.generate_chart(this.monthsValue) + }) + } + + setup_dates_histogram() { + const labels = [] + const values = [] + for(const [k,v] of Object.entries(this.yearsValue)) { + labels.push(k) + values.push(v) + } + const dataset = {} + dataset['label'] = "Date frequencies" + dataset['backgroundColor'] = 'rgba(0, 0, 0, 0.1)' + dataset['borderColor'] = 'rgba(0, 0, 0, 0.5)' + dataset['lineTension'] = 0.4 + dataset['fill'] = 'origin' + dataset['borderWidth'] = 1 + dataset['hidden'] = false + dataset['data'] = values + const ctx = $("#canvas_dates_histogram") + const opts = { + responsive: true, + maintainAspectRatio: false, + scales: { + y: { + beginAtZero: true + } + }, + plugins: { + legend: { + display: false + } + } + } + new Chart(ctx, { + type: 'bar', + data: { + labels: labels, + datasets: [dataset] + }, + options: opts + }) + } + + generate_chart(data) { + if(this.wide_chart) + this.wide_chart.destroy() + //CatalogIndex.big_chart.destroy() if CatalogIndex.big_chart? + const labels = [] + const values = [] + const keys = Object.keys(data).sort() + for(const k of keys) { + labels.push(k) + values.push(data[k]) + } + const dataset = {} + dataset['label'] = "Date frequencies" + dataset['backgroundColor'] = 'rgba(0, 0, 0, 0.1)' + dataset['borderColor'] = 'rgba(0, 0, 0, 0.5)' + dataset['lineTension'] = 0.4 + dataset['fill'] = 'origin' + dataset['borderWidth'] = 1 + dataset['hidden'] = false + dataset['data'] = values + const ctx = $("#canvas_wide_dates_histogram") + const opts = { + responsive: true, + maintainAspectRatio: false, + tooltips:{ + enabled: false + }, + scales: { + y: { + beginAtZero: true + } + }, + plugins: { + legend: { + display: false + }, + zoom: { + pan: { + enabled: true + }, + zoom: { + wheel: { + enabled: true, + }, + pinch: { + enabled: true + }, + mode: 'xy', + } + } + } + } + //CatalogIndex.big_chart = new Chart(ctx, { + this.wide_chart = new Chart(ctx, { + type: 'bar', + data: { + labels: labels, + datasets: [dataset] + }, + options: opts + }) + } +} \ No newline at end of file diff --git a/app/javascript/packs/controllers/viewer_controller.js b/app/javascript/packs/controllers/viewer_controller.js index c677f69..dab2744 100644 --- a/app/javascript/packs/controllers/viewer_controller.js +++ b/app/javascript/packs/controllers/viewer_controller.js @@ -84,7 +84,14 @@ export default class extends Controller { const text = $.map(this.selectedArticlesValue, (article_id, idx) => { return $(`#${article_id}`).data('text').replaceAll("\"", "").replaceAll("\\n", "
") }).join("\n") - const title = this.selectedArticlesValue.length == 1 ? this.selectedArticlesValue[0] : "Compound" + let title + if(this.selectedArticlesValue.length == 1) { + title = this.articlesValue.filter(o => o.id === this.selectedArticlesValue[0])[0].title + if(title == null) + title = this.selectedArticlesValue[0] + } + else + title = "Compound" $(this.selectedArticlePanelTarget).find('h5')[0].innerHTML = title $(this.selectedArticlePanelTarget).find('p')[0].innerHTML = text } diff --git a/app/javascript/packs/stylesheets/catalog.scss b/app/javascript/packs/stylesheets/catalog.scss index ce40598..47720bb 100644 --- a/app/javascript/packs/stylesheets/catalog.scss +++ b/app/javascript/packs/stylesheets/catalog.scss @@ -24,6 +24,9 @@ body .container-fluid { border: 2px solid #32a1ce; padding: calc(0.5em - 2px); } +#canvas_wide_dates_histogram { + height: 60vh; +} //////////////////////////////////////////// ////////////////// Facets ////////////////// @@ -47,6 +50,11 @@ li.selected_constraint { #viewer_container { position: relative; } + +.openseadragon-canvas + div { + z-index: 2; +} + #page_counter { position: absolute; background-color: #8AF; diff --git a/app/javascript/packs/utils/search_api.js b/app/javascript/packs/utils/search_api.js index 259b5f6..9691bcb 100644 --- a/app/javascript/packs/utils/search_api.js +++ b/app/javascript/packs/utils/search_api.js @@ -50,4 +50,21 @@ export class SearchAPI { } }) } + + static wideDatesHistogram(callback) { + $.ajax({ + type: "POST", + url: "/catalog/wide_dates_histogram", + data: {}, + headers: { + 'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content') + }, + success: (data, textStatus, jqXHR) => { + callback(data) + }, + error: (jqXHR, textStatus, errorThrown) => { + + } + }) + } } \ No newline at end of file diff --git a/app/models/article.rb b/app/models/article.rb index 078a759..36fc5a1 100644 --- a/app/models/article.rb +++ b/app/models/article.rb @@ -22,7 +22,7 @@ class Article a end - def to_solr + def to_solr(page_iiif_url) solr_doc = {} solr_doc['id'] = self.id solr_doc['title_ssi'] = self.title @@ -34,7 +34,7 @@ class Article solr_doc['from_issue_ssi'] = self.issue_id solr_doc['member_of_collection_ids_ssim'] = self.newspaper solr_doc['canvases_parts_ssm'] = self.canvases_parts - solr_doc['thumbnail_url_ss'] = self.get_iiif_url + solr_doc['thumbnail_url_ss'] = self.get_iiif_url(page_iiif_url) solr_doc['has_model_ssim'] = 'Article' solr_doc end @@ -50,7 +50,7 @@ class Article [min_x,min_y,canvas_size[0],canvas_size[1]] end - def get_iiif_url + def get_iiif_url(page_iiif_url) canvas_url = self.canvases_parts[0] coords = self.canvases_parts.map { |c| c[c.rindex('#xywh=')+6..-1].split(',').map(&:to_i) } min_x = coords.map{ |coord| coord[0] }.min @@ -58,7 +58,7 @@ class Article min_y = coords.map{ |coord| coord[1] }.min max_y = coords.map{ |coord| coord[1] + coord[3] }.max pagenum = canvas_url[canvas_url.rindex('_')+1...canvas_url.rindex('#')].to_i - "https://platform.newseye.eu/iiif/#{self.issue_id}_page_#{pagenum}/#{min_x},#{min_y},#{max_x-min_x},#{max_y-min_y}/full/0/default.jpg" + "#{page_iiif_url}/#{min_x},#{min_y},#{max_x-min_x},#{max_y-min_y}/full/0/default.jpg" end def self.named_entities(article_id) diff --git a/app/models/issue.rb b/app/models/issue.rb index 00cd5d4..441430e 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -15,7 +15,7 @@ class Issue i.title = solr_doc['title_ssi'] i.date_created = solr_doc['date_created_ssi'] i.original_uri = solr_doc['original_uri_ss'] - i.nb_pages = solr_doc['nb_pages_isi'] + i.nb_pages = solr_doc['member_ids_ssim'].size i.thumbnail_url = solr_doc['thumbnail_url_ss'] i.all_text = solr_doc["all_text_t#{i.language}_siv"] if with_pages diff --git a/app/models/solr_query.rb b/app/models/solr_query.rb index 4ba413d..9c125db 100644 --- a/app/models/solr_query.rb +++ b/app/models/solr_query.rb @@ -29,9 +29,12 @@ class SolrQuery @hl_dot_fl = @qf @json_dot_facet = {} - I18n.t("newspapers.solr_fields").values_at(:language, :date, :newspaper).each do |f| + I18n.t("newspapers.solr_fields").values_at(:language, :newspaper).each do |f| @json_dot_facet[f] = { terms: { field: f, limit: 15, numBuckets: true} } end + I18n.t("newspapers.solr_fields").values_at(:date).each do |f| + @json_dot_facet[f] = { terms: { field: f, limit: -1, numBuckets: true} } + end I18n.t("newspapers.solr_fields").values_at(:month, :day).each do |f| @json_dot_facet[f] = { terms: { field: f, limit: 15, numBuckets: true, sort: {index: "asc"}} } end diff --git a/app/views/catalog/_dates_histogram.html.erb b/app/views/catalog/_dates_histogram.html.erb new file mode 100644 index 0000000..4b47b97 --- /dev/null +++ b/app/views/catalog/_dates_histogram.html.erb @@ -0,0 +1,24 @@ +<% + year_hist = @results['facets']['date_created_dtsi']['buckets'].map { |e| {DateTime.parse(e['val']).year => e['count']} } + year_hist = year_hist.inject{|a,b| a.merge(b){|_,x,y| x + y}} + year_hist.merge!((year_hist.keys.min..year_hist.keys.max).to_a.map{|e| [e, 0]}.to_h) {|key, oldval, newval| oldval } + month_year_hist = @results['facets']['date_created_dtsi']['buckets'].map{ |e| {"#{DateTime.parse(e['val']).year}/%02d" % DateTime.parse(e['val']).month => e['count']} } + month_year_hist = month_year_hist.inject{|a,b| a.merge(b){|_,x,y| x + y}} + missing_keys = (year_hist.keys.min..year_hist.keys.max).to_a.map{ |e| (1..12).to_a.map{ |f| "#{e}/%02d" % f } }.flatten.map{|t| [t, 0] }.to_h + month_year_hist.merge!(missing_keys) {|key, oldval, newval| oldval } +%> +
+
+ Dates frequencies + +
+
+ +
+
+ \ No newline at end of file diff --git a/app/views/catalog/_facet.html.erb b/app/views/catalog/_facet.html.erb index 4194368..368c243 100644 --- a/app/views/catalog/_facet.html.erb +++ b/app/views/catalog/_facet.html.erb @@ -18,8 +18,9 @@ data-facets-nb-pages-value="<%= nb_pages %>" data-facets-per-page-value="<%= per_page %>">