Пример #1
0
func dataLatencySummarySvg(r *http.Request, h http.Header, b *bytes.Buffer) *weft.Result {
	var rows *sql.Rows
	var width int
	var err error

	typeID := r.URL.Query().Get("typeID")
	bbox := r.URL.Query().Get("bbox")

	if err = map180.ValidBbox(bbox); err != nil {
		return weft.BadRequest(err.Error())
	}

	if width, err = strconv.Atoi(r.URL.Query().Get("width")); err != nil {
		return weft.BadRequest("invalid width")
	}

	var raw map180.Raw
	if raw, err = wm.MapRaw(bbox, width); err != nil {
		return weft.InternalServerError(err)
	}

	var bboxWkt string
	if bboxWkt, err = map180.BboxToWKTPolygon(bbox); err != nil {
		return weft.InternalServerError(err)
	}

	if rows, err = dbR.Query(`with p as (select geom, time, mean, lower, upper,
			st_transform(geom::geometry, 3857) as pt
			FROM data.latency_summary
			JOIN data.site USING (sitePK)
			JOIN data.type USING (typePK)
			JOIN data.latency_threshold USING (sitePK, typePK)
			where typeID = $1)
			select ST_X(pt), ST_Y(pt)*-1, ST_X(geom::geometry),ST_Y(geom::geometry), time,
			mean, lower,upper from p
			WHERE ST_Within(geom::geometry, ST_GeomFromText($2, 4326))`, typeID, bboxWkt); err != nil {
		return weft.InternalServerError(err)
	}

	defer rows.Close()

	ago := time.Now().UTC().Add(time.Hour * -3)

	var late []point
	var good []point
	var bad []point
	var dunno []point

	for rows.Next() {
		var p point
		var t time.Time
		var min, max, v int

		if err = rows.Scan(&p.x, &p.y, &p.longitude, &p.latitude, &t, &v, &min, &max); err != nil {
			return weft.InternalServerError(err)
		}

		// Does not handle crossing the equator.
		switch {
		case raw.CrossesCentral && p.longitude > -180.0 && p.longitude < 0.0:
			p.x = (p.x + map180.Width3857 - raw.LLX) * raw.DX
			p.y = (p.y - math.Abs(raw.YShift)) * raw.DX
		case p.longitude > 0.0:
			p.x = (p.x - math.Abs(raw.XShift)) * raw.DX
			p.y = (p.y - math.Abs(raw.YShift)) * raw.DX
		default:
			p.x = (p.x + math.Abs(raw.XShift)) * raw.DX
			p.y = (p.y - math.Abs(raw.YShift)) * raw.DX

		}
		switch {
		case t.Before(ago):
			late = append(late, p)
		case min == 0 && max == 0:
			dunno = append(dunno, p)
		case v < min || v > max:
			bad = append(bad, p)
		default:
			good = append(good, p)
		}
	}
	rows.Close()

	b.WriteString(`<?xml version="1.0"?>`)
	b.WriteString(fmt.Sprintf("<svg  viewBox=\"0 0 %d %d\"  xmlns=\"http://www.w3.org/2000/svg\">",
		raw.Width, raw.Height))
	b.WriteString(fmt.Sprintf("<rect x=\"0\" y=\"0\" width=\"%d\" height=\"%d\" style=\"fill: azure\"/>", raw.Width, raw.Height))
	b.WriteString(fmt.Sprintf("<path style=\"fill: wheat; stroke-width: 1; stroke-linejoin: round; stroke: lightslategrey\" d=\"%s\"/>", raw.Land))
	b.WriteString(fmt.Sprintf("<path style=\"fill: azure; stroke-width: 1; stroke-linejoin: round; stroke: lightslategrey\" d=\"%s\"/>", raw.Lakes))

	b.WriteString("<g style=\"stroke: #377eb8; fill: #377eb8; \">") // blueish
	for _, p := range dunno {
		b.WriteString(fmt.Sprintf("<circle cx=\"%.1f\" cy=\"%.1f\" r=\"%d\"/>", p.x, p.y, 5))
	}
	b.WriteString("</g>")

	b.WriteString("<g style=\"stroke: #4daf4a; fill: #4daf4a; \">") // greenish
	for _, p := range good {
		b.WriteString(fmt.Sprintf("<circle cx=\"%.1f\" cy=\"%.1f\" r=\"%d\"/>", p.x, p.y, 5))
	}
	b.WriteString("</g>")

	b.WriteString("<g style=\"stroke: #e41a1c; fill: #e41a1c; \">") //red
	for _, p := range bad {
		b.WriteString(fmt.Sprintf("<circle cx=\"%.1f\" cy=\"%.1f\" r=\"%d\"/>", p.x, p.y, 6))
	}
	b.WriteString("</g>")

	b.WriteString("<g style=\"stroke: #984ea3; fill: #984ea3; \">") // purple
	for _, p := range late {
		b.WriteString(fmt.Sprintf("<circle cx=\"%.1f\" cy=\"%.1f\" r=\"%d\"/>", p.x, p.y, 6))
	}
	b.WriteString("</g>")

	b.WriteString("</svg>")

	return &weft.StatusOK
}
Пример #2
0
func siteTypeMap(w http.ResponseWriter, r *http.Request) {
	if err := siteTypeMapD.CheckParams(r.URL.Query()); err != nil {
		web.BadRequest(w, r, err.Error())
		return
	}

	v := r.URL.Query()

	bbox := v.Get("bbox")

	err := map180.ValidBbox(bbox)
	if err != nil {
		web.BadRequest(w, r, err.Error())
		return
	}

	var insetBbox, typeID, methodID, within string
	width := 130

	if v.Get("insetBbox") != "" {
		insetBbox = v.Get("insetBbox")

		err := map180.ValidBbox(insetBbox)
		if err != nil {
			web.BadRequest(w, r, err.Error())
			return
		}
	}

	if v.Get("width") != "" {
		width, err = strconv.Atoi(v.Get("width"))
		if err != nil {
			web.BadRequest(w, r, "invalid width.")
			return
		}
	}
	if v.Get("methodID") != "" && v.Get("typeID") == "" {
		web.BadRequest(w, r, "typeID must be specified when methodID is specified.")
		return
	}

	if v.Get("typeID") != "" {
		typeID = v.Get("typeID")

		if !validType(w, r, typeID) {
			return
		}

		if v.Get("methodID") != "" {
			methodID = v.Get("methodID")
			if !validTypeMethod(w, r, typeID, methodID) {
				return
			}
		}
	}

	if v.Get("within") != "" {
		within = strings.Replace(v.Get("within"), "+", "", -1)
		if !validPoly(w, r, within) {
			return
		}
	} else if bbox != "" {
		within, err = map180.BboxToWKTPolygon(bbox)
		if err != nil {
			web.ServiceUnavailable(w, r, err)
			return
		}
	}

	g, err := geoJSONSites(typeID, methodID, within)
	if err != nil {
		web.ServiceUnavailable(w, r, err)
		return
	}

	m, err := geoJSONToMarkers(g)
	if err != nil {
		web.ServiceUnavailable(w, r, err)
		return
	}

	b, err := wm.SVG(bbox, width, m, insetBbox)
	if err != nil {
		web.ServiceUnavailable(w, r, err)
		return
	}

	w.Header().Set("Content-Type", "image/svg+xml")
	web.OkBuf(w, r, &b)
}