Skip to content

Commit

Permalink
feat(functions): add social-media-square image type (#4219)
Browse files Browse the repository at this point in the history
* feat(functions): add `social-media-square` image type

* 🤖 style: prettify code

* enhance: extract `GRAPHER_SQUARE_SIZE` as constant

* 🤖 style: prettify code

---------

Co-authored-by: marcelgerber <[email protected]>
  • Loading branch information
marcelgerber and marcelgerber authored Nov 26, 2024
1 parent aa73d89 commit 49834b6
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 10 deletions.
3 changes: 2 additions & 1 deletion functions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -232,13 +232,14 @@ All of the below options can be given as query parameters, e.g. `?imType=og&noca
<td><code>imType</code></td>
<td>
<code>twitter</code> or <code>og</code> (short for
<a href="https://ogp.me">Open Graph</a>)
<a href="https://ogp.me">Open Graph</a>) or <code>social-media-square</code>
</td>
<td>
If present, will use fitting defaults for the generated image size:
<ul>
<li><code>twitter</code>: 800x418</li>
<li><code>og</code>: 1200x628</li>
<li><code>social-media-square</code>: 2160x2160, customizable using <code>imSquareSize=[number]</code></li>
</ul>
All below options will be ignored if <code>imType</code> is set to one of these values.
</td>
Expand Down
20 changes: 15 additions & 5 deletions functions/_common/grapherRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ async function fetchAndRenderGrapherToSvg(

const svg = grapher.generateStaticSvg()
grapherLogger.log("generateStaticSvg")
return svg

return { svg, backgroundColor: grapher.backgroundColor }
}

export const fetchAndRenderGrapher = async (
Expand All @@ -94,12 +95,17 @@ export const fetchAndRenderGrapher = async (
const options = extractOptions(searchParams)

console.log("Rendering", id.id, outType, options)
const svg = await fetchAndRenderGrapherToSvg(id, options, searchParams, env)
const { svg, backgroundColor } = await fetchAndRenderGrapherToSvg(
id,
options,
searchParams,
env
)
console.log("fetched svg")

switch (outType) {
case "png":
return png(await renderSvgToPng(svg, options))
return png(await renderSvgToPng(svg, options, backgroundColor))
case "svg":
return new Response(svg, {
headers: {
Expand All @@ -111,7 +117,11 @@ export const fetchAndRenderGrapher = async (

let initialized = false

export async function renderSvgToPng(svg: string, options: ImageOptions) {
export async function renderSvgToPng(
svg: string,
options: ImageOptions,
backgroundColor: string
) {
if (!initialized) {
await initializeSvg2Png(svg2png_wasm)
initialized = true
Expand All @@ -123,7 +133,7 @@ export async function renderSvgToPng(svg: string, options: ImageOptions) {

// if we include details, pngHeight is only the height of the chart, but we also have an "appendix" at the bottom that we want to include
height: options.details ? undefined : options.pngHeight,
backgroundColor: "#fff",
backgroundColor,
fonts: [LatoRegular, LatoMedium, LatoBold, PlayfairSemiBold].map(
(f) => new Uint8Array(f)
),
Expand Down
2 changes: 2 additions & 0 deletions functions/_common/grapherTools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,9 @@ export async function initGrapher(
bounds,
staticBounds: bounds,
baseFontSize: options.fontSize,
...options.grapherProps,
})
grapher.isExportingToSvgOrPng = true
grapher.shouldIncludeDetailsInStaticExport = options.details

return grapher
Expand Down
34 changes: 31 additions & 3 deletions functions/_common/imageOptions.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import {
GrapherProgrammaticInterface,
GRAPHER_SQUARE_SIZE,
} from "@ourworldindata/grapher"
import {
DEFAULT_ASPECT_RATIO,
MIN_ASPECT_RATIO,
Expand All @@ -7,14 +11,16 @@ import {
DEFAULT_WIDTH,
DEFAULT_HEIGHT,
} from "./grapherRenderer.js"
import { GrapherStaticFormat } from "@ourworldindata/types"

export interface ImageOptions {
pngWidth: number
pngHeight: number
svgWidth: number
svgHeight: number
details: boolean
fontSize: number
fontSize: number | undefined
grapherProps?: Partial<GrapherProgrammaticInterface>
}
export const TWITTER_OPTIONS: ImageOptions = {
// Twitter cards are 1.91:1 in aspect ratio, and 800x418 is the recommended size
Expand All @@ -34,12 +40,34 @@ const OPEN_GRAPH_OPTIONS: ImageOptions = {
details: false,
fontSize: 21,
}
export const extractOptions = (params: URLSearchParams): ImageOptions => {
const options: Partial<ImageOptions> = {}
const SOCIAL_MEDIA_SQUARE_OPTIONS: ImageOptions = {
pngWidth: 4 * GRAPHER_SQUARE_SIZE,
pngHeight: 4 * GRAPHER_SQUARE_SIZE,
svgWidth: GRAPHER_SQUARE_SIZE,
svgHeight: GRAPHER_SQUARE_SIZE,
details: false,
fontSize: undefined,
grapherProps: {
isSocialMediaExport: true,
staticFormat: GrapherStaticFormat.square,
},
}

export const extractOptions = (params: URLSearchParams): ImageOptions => {
// We have two special images types specified via the `imType` query param:
if (params.get("imType") === "twitter") return TWITTER_OPTIONS
else if (params.get("imType") === "og") return OPEN_GRAPH_OPTIONS
else if (params.get("imType") === "social-media-square") {
const squareOptions = SOCIAL_MEDIA_SQUARE_OPTIONS
if (params.has("imSquareSize")) {
const size = parseInt(params.get("imSquareSize")!)
squareOptions.pngWidth = size
squareOptions.pngHeight = size
}
return squareOptions
}

const options: Partial<ImageOptions> = {}

// Otherwise, query params can specify the size to be rendered at; and in addition we're doing a
// bunch of normalization to make sure the image is rendered at a reasonable size and aspect ratio.
Expand Down
8 changes: 7 additions & 1 deletion packages/@ourworldindata/grapher/src/core/Grapher.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ import {
GRAPHER_FRAME_PADDING_VERTICAL,
latestGrapherConfigSchema,
validChartTypeCombinations,
GRAPHER_SQUARE_SIZE,
} from "../core/GrapherConstants"
import { loadVariableDataAndMetadata } from "./loadVariable"
import Cookies from "js-cookie"
Expand Down Expand Up @@ -2072,7 +2073,12 @@ export class Grapher
case GrapherStaticFormat.landscape:
return this.defaultBounds
case GrapherStaticFormat.square:
return new Bounds(0, 0, 540, 540)
return new Bounds(
0,
0,
GRAPHER_SQUARE_SIZE,
GRAPHER_SQUARE_SIZE
)
default:
return this.defaultBounds
}
Expand Down
2 changes: 2 additions & 0 deletions packages/@ourworldindata/grapher/src/core/GrapherConstants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export const GRAPHER_LOADED_EVENT_NAME = "grapherLoaded"
export const DEFAULT_GRAPHER_WIDTH = 850
export const DEFAULT_GRAPHER_HEIGHT = 600

export const GRAPHER_SQUARE_SIZE = 540

export const GRAPHER_FRAME_PADDING_VERTICAL = 16
export const GRAPHER_FRAME_PADDING_HORIZONTAL = 16

Expand Down
1 change: 1 addition & 0 deletions packages/@ourworldindata/grapher/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export {
GRAPHER_IS_IN_IFRAME_CLASS,
DEFAULT_GRAPHER_WIDTH,
DEFAULT_GRAPHER_HEIGHT,
GRAPHER_SQUARE_SIZE,
STATIC_EXPORT_DETAIL_SPACING,
DEFAULT_GRAPHER_ENTITY_TYPE,
GRAPHER_LOADED_EVENT_NAME,
Expand Down

0 comments on commit 49834b6

Please sign in to comment.