Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions assets/js/dashboard/datepicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,10 @@ class DatePicker extends React.Component {
return (
<div className="flex rounded shadow bg-white mr-4 cursor-pointer">
<Link to={{search: this.queryWithPeriod(period, {date: prevDate})}} className="flex items-center px-2 border-r border-gray-300">
<svg className="feather h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"></polyline></svg>
<svg className="feather h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="15 18 9 12 15 6"></polyline></svg>
</Link>
<Link to={{search: this.queryWithPeriod(period, {date: nextDate})}} className="flex items-center px-2">
<svg class="feather h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"></polyline></svg>
<svg className="feather h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="9 18 15 12 9 6"></polyline></svg>
</Link>
</div>
)
Expand Down Expand Up @@ -132,7 +132,7 @@ class DatePicker extends React.Component {
<div className="relative" style={{height: '35.5px', width: '190px'}} ref={node => this.dropDownNode = node}>
<div onClick={this.open.bind(this)} className="flex items-center justify-between rounded bg-white shadow px-4 pr-3 py-2 leading-tight cursor-pointer text-sm font-medium text-gray-800 h-full">
<span className="mr-2">{this.timeFrameText()}</span>
<svg class="text-pink-500 h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<svg className="text-pink-500 h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<polyline points="6 9 12 15 18 9"></polyline>
</svg>
</div>
Expand Down
2 changes: 1 addition & 1 deletion assets/js/dashboard/stats/more-link.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export default function MoreLink({site, list, endpoint}) {
return (
<div className="text-center w-full absolute bottom-0 left-0 p-4">
<Link to={`/${encodeURIComponent(site.domain)}/${endpoint}${window.location.search}`} className="leading-snug font-bold text-sm text-gray-500 hover:text-red-500 transition tracking-wide">
<svg className="feather mr-1" style={{marginTop: '-2px'}} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3"/></svg>
<svg className="feather mr-1" style={{marginTop: '-2px'}} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3"/></svg>
MORE
</Link>
</div>
Expand Down
59 changes: 5 additions & 54 deletions assets/js/dashboard/stats/visitor-graph.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { eventName } from '../query'
import numberFormatter, {durationFormatter} from '../number-formatter'
import * as api from '../api'

function mainSet(plot, present_index, ctx, label) {
function buildDataSet(plot, present_index, ctx, label) {
var gradient = ctx.createLinearGradient(0, 0, 0, 300);
gradient.addColorStop(0, 'rgba(101,116,205, 0.2)');
gradient.addColorStop(1, 'rgba(101,116,205, 0)');
Expand Down Expand Up @@ -47,57 +47,6 @@ function mainSet(plot, present_index, ctx, label) {
}
}

function compareSet(plot, present_index, ctx) {
var gradient = ctx.createLinearGradient(0, 0, 0, 300);
gradient.addColorStop(0, 'rgba(255, 68, 87, .2)');
gradient.addColorStop(1, 'rgba(255, 68, 87, 0)');

if (present_index) {
var dashedPart = plot.slice(present_index - 1);
var dashedPlot = (new Array(plot.length - dashedPart.length)).concat(dashedPart)
for(var i = present_index; i < plot.length; i++) {
plot[i] = undefined
}

return [{
label: 'Conversions',
data: plot,
borderWidth: 3,
borderColor: 'rgba(255, 68, 87, 1)',
pointBackgroundColor: 'rgba(255, 68, 87, 1)',
backgroundColor: gradient,
},
{
label: 'Conversions',
data: dashedPlot,
borderWidth: 3,
borderDash: [5, 10],
borderColor: 'rgba(255, 68, 87, 1)',
pointBackgroundColor: 'rgba(255, 68, 87, 1)',
backgroundColor: gradient,
}]
} else {
return [{
label: 'Conversions',
data: plot,
borderWidth: 3,
borderColor: 'rgba(255, 68, 87, 1)',
pointBackgroundColor: 'rgba(255, 68, 87, 1)',
backgroundColor: gradient,
}]
}
}

function dataSets(graphData, ctx) {
const dataSets = mainSet(graphData.plot, graphData.present_index, ctx, graphData.interval === 'minute' ? 'Pageviews' : 'Visitors')

if (graphData.compare_plot) {
return dataSets.concat(compareSet(graphData.compare_plot, graphData.present_index, ctx))
} else {
return dataSets
}
}

const MONTHS = [
"January", "February", "March",
"April", "May", "June", "July",
Expand Down Expand Up @@ -136,12 +85,14 @@ class LineGraph extends React.Component {
componentDidMount() {
const {graphData} = this.props
this.ctx = document.getElementById("main-graph-canvas").getContext('2d');
const label = this.props.query.filters.goal ? 'Converted visitors' : graphData.interval === 'minute' ? 'Pageviews' : 'Visitors'
const dataSet = buildDataSet(graphData.plot, graphData.present_index, this.ctx, label)

this.chart = new Chart(this.ctx, {
type: 'line',
data: {
labels: graphData.labels,
datasets: dataSets(graphData, this.ctx)
datasets: dataSet
},
options: {
animation: false,
Expand Down Expand Up @@ -296,7 +247,7 @@ class LineGraph extends React.Component {

return (
<a href={endpoint} download>
<svg className="feather w-4 h-5 absolute text-gray-700" style={{right: '2rem', top: '-2rem'}} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="7 10 12 15 17 10"></polyline><line x1="12" y1="15" x2="12" y2="3"></line></svg>
<svg className="feather w-4 h-5 absolute text-gray-700" style={{right: '2rem', top: '-2rem'}} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="7 10 12 15 17 10"></polyline><line x1="12" y1="15" x2="12" y2="3"></line></svg>
</a>
)
}
Expand Down
59 changes: 7 additions & 52 deletions lib/plausible/stats/clickhouse.ex
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ defmodule Plausible.Stats.Clickhouse do

groups =
Clickhouse.all(
from e in base_query(site, %{query | filters: %{}}),
from e in base_query(site, query),
select:
{fragment("toStartOfMonth(toTimeZone(?, ?)) as month", e.timestamp, ^site.timezone),
fragment("uniq(?) as visitors", e.user_id)},
Expand All @@ -43,38 +43,23 @@ defmodule Plausible.Stats.Clickhouse do
|> Enum.map(fn row -> {row["month"], row["visitors"]} end)
|> Enum.into(%{})

compare_groups =
if query.filters["goal"] do
Clickhouse.all(
from e in base_query(site, query),
select:
{fragment("toStartOfMonth(toTimeZone(?, ?)) as month", e.timestamp, ^site.timezone),
fragment("uniq(?) as visitors", e.user_id)},
group_by: fragment("month"),
order_by: fragment("month")
)
|> Enum.map(fn row -> {row["month"], row["visitors"]} end)
|> Enum.into(%{})
end

present_index =
Enum.find_index(steps, fn step ->
step == Timex.now(site.timezone) |> Timex.to_date() |> Timex.beginning_of_month()
end)

plot = Enum.map(steps, fn step -> groups[step] || 0 end)
compare_plot = compare_groups && Enum.map(steps, fn step -> compare_groups[step] || 0 end)
labels = Enum.map(steps, fn step -> Timex.format!(step, "{ISOdate}") end)

{plot, compare_plot, labels, present_index}
{plot, labels, present_index}
end

def calculate_plot(site, %Query{step_type: "date"} = query) do
steps = Enum.into(query.date_range, [])

groups =
Clickhouse.all(
from e in base_query(site, %{query | filters: %{}}),
from e in base_query(site, query),
select:
{fragment("toDate(toTimeZone(?, ?)) as day", e.timestamp, ^site.timezone),
fragment("uniq(?) as visitors", e.user_id)},
Expand All @@ -84,37 +69,22 @@ defmodule Plausible.Stats.Clickhouse do
|> Enum.map(fn row -> {row["day"], row["visitors"]} end)
|> Enum.into(%{})

compare_groups =
if query.filters["goal"] do
Clickhouse.all(
from e in base_query(site, query),
select:
{fragment("toDate(toTimeZone(?, ?)) as day", e.timestamp, ^site.timezone),
fragment("uniq(?) as visitors", e.user_id)},
group_by: fragment("day"),
order_by: fragment("day")
)
|> Enum.map(fn row -> {row["day"], row["visitors"]} end)
|> Enum.into(%{})
end

present_index =
Enum.find_index(steps, fn step -> step == Timex.now(site.timezone) |> Timex.to_date() end)

steps_to_show = if present_index, do: present_index + 1, else: Enum.count(steps)
plot = Enum.map(steps, fn step -> groups[step] || 0 end) |> Enum.take(steps_to_show)
compare_plot = compare_groups && Enum.map(steps, fn step -> compare_groups[step] || 0 end)
labels = Enum.map(steps, fn step -> Timex.format!(step, "{ISOdate}") end)

{plot, compare_plot, labels, present_index}
{plot, labels, present_index}
end

def calculate_plot(site, %Query{step_type: "hour"} = query) do
steps = 0..23

groups =
Clickhouse.all(
from e in base_query(site, %{query | filters: %{}}),
from e in base_query(site, query),
select:
{fragment("toHour(toTimeZone(?, ?)) as hour", e.timestamp, ^site.timezone),
fragment("uniq(?) as visitors", e.user_id)},
Expand All @@ -124,20 +94,6 @@ defmodule Plausible.Stats.Clickhouse do
|> Enum.map(fn row -> {row["hour"], row["visitors"]} end)
|> Enum.into(%{})

compare_groups =
if query.filters["goal"] do
Clickhouse.all(
from e in base_query(site, query),
select:
{fragment("toHour(toTimeZone(?, ?)) as hour", e.timestamp, ^site.timezone),
fragment("uniq(?) as visitors", e.user_id)},
group_by: fragment("hour"),
order_by: fragment("hour")
)
|> Enum.map(fn row -> {row["hour"], row["visitors"]} end)
|> Enum.into(%{})
end

now = Timex.now(site.timezone)
is_today = Timex.to_date(now) == query.date_range.first
present_index = is_today && Enum.find_index(steps, fn step -> step == now.hour end)
Expand All @@ -151,8 +107,7 @@ defmodule Plausible.Stats.Clickhouse do
end)

plot = Enum.map(steps, fn step -> groups[step] || 0 end) |> Enum.take(steps_to_show)
compare_plot = compare_groups && Enum.map(steps, fn step -> compare_groups[step] || 0 end)
{plot, compare_plot, labels, present_index}
{plot, labels, present_index}
end

def calculate_plot(site, %Query{period: "realtime"}) do
Expand All @@ -173,7 +128,7 @@ defmodule Plausible.Stats.Clickhouse do

labels = Enum.into(-30..-1, [])
plot = Enum.map(labels, fn label -> groups[label] || 0 end)
{plot, nil, labels, nil}
{plot, labels, nil}
end

def bounce_rate(site, query) do
Expand Down
3 changes: 1 addition & 2 deletions lib/plausible_web/controllers/api/stats_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,10 @@ defmodule PlausibleWeb.Api.StatsController do

plot_task = Task.async(fn -> Stats.calculate_plot(site, query) end)
top_stats = fetch_top_stats(site, query)
{plot, compare_plot, labels, present_index} = Task.await(plot_task)
{plot, labels, present_index} = Task.await(plot_task)

json(conn, %{
plot: plot,
compare_plot: compare_plot,
labels: labels,
present_index: present_index,
top_stats: top_stats,
Expand Down
2 changes: 1 addition & 1 deletion lib/plausible_web/controllers/stats_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ defmodule PlausibleWeb.StatsController do
site = conn.assigns[:site]

query = Query.from(site.timezone, conn.params)
{plot, _, labels, _} = Stats.calculate_plot(site, query)
{plot, labels, _} = Stats.calculate_plot(site, query)

csv_content =
Enum.zip(labels, plot)
Expand Down